PyPI / filelock / 4.2.2

filelock 4.2.2

Source
https://github.com/tox-dev/py-filelock
Tag scanned
4.2.2
Compared with
4.2.1 (0 signals introduced since)
Files
95 scanned, 9 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 23 info
Scan time
17.1 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 23 of 23 warn and critical signals; 23 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-18 09:41

Signals

Ordered by severity, then signals introduced in this release. Hidden characters are shown as ⟨U+…⟩.

  1. info warn → info by review dynamic-execution compose.yaml:18:30

    [embedded bash] command name is a variable (`$$`) not set in this file — the caller or environment decides what runs (ast pass, confidence 0.70)

    "cp -a /repo \"$$HOME/work\" && cd \"$$HOME/work\" && pip install -q . && exec tox run -e py -x env.py.base_python=3.14 -x env_pkg_base.default_base_python=3.14"
    likely benign LLM, confidence 0.70 A docker-compose service runs a tox test command inside an embedded bash block.
    Reasoning

    The flagged command name is a compose-escaped `$$` expansion inside an embedded CI-style bash block. The rest of the command is literal and readable (cp of the repo, pip install, tox run with fixed Python version). Nothing indicates a dropper or hidden payload, though the variable-command-name flag is a fair thing to note.

  2. info warn → info by review dynamic-attribute src/filelock/__init__.py:124:5

    reach-by-name through `globals` (ast pass, confidence 0.60)

                value = getattr(module, f"Async{_FileLock.__name__}" if name == "AsyncFileLock" else name)
        globals()[name] = value
        return value
    likely benign LLM, confidence 0.90 Module-level lazy attribute loader that caches resolved names in globals().
    Reasoning

    This is the standard PEP 562 lazy-attribute pattern: a module-level __getattr__ resolves names, caches them in globals(), and returns them. The name is restricted to known filelock symbols, so it is not a hidden dynamic-execution path.

  3. info warn → info by review frame-introspection src/filelock/_api.py:1323:31

    `inspect.currentframe` — call-stack frame introspection (ast pass, confidence 0.70)

                    return
                state.releasing = inspect.currentframe()
                try:
                    _LOGGER.debug("Attempting to release lock %s on %s", id(self), self.lock_file)
    likely benign LLM, confidence 0.90 Records the current call frame on the lock state during release for reentrancy tracking.
    Reasoning

    inspect.currentframe() is stored on the lock state to detect reentrant release for logging and correctness. This is ordinary library bookkeeping, not malicious introspection.

  4. info warn → info by review frame-introspection src/filelock/_api.py:1466:35

    `inspect.currentframe` — call-stack frame introspection (ast pass, confidence 0.70)

            attempt = 0
            self._context.acquiring = inspect.currentframe()
            try:
                # Created once, so a directory that disappears while the acquisition waits fails it, not builds a second
    likely benign LLM, confidence 0.90 Stores the current frame on the lock context during acquisition.
    Reasoning

    The frame is saved on the acquisition context so the library can tell which call is acquiring the lock. This is internal state handling in a file-locking library.

  5. info warn → info by review frame-introspection src/filelock/_api.py:1775:14

    `inspect.currentframe` — call-stack frame introspection (ast pass, confidence 0.70)

            return False
        caller = inspect.currentframe()
        while caller is not None and caller is not frame:
            caller = caller.f_back
    likely benign LLM, confidence 0.90 Walks the call stack via f_back to find a specific caller frame.
    Reasoning

    The loop walks f_back from the current frame to find a target frame, which is a normal way to locate a caller for ownership or cleanup logic. It has no network, exec, or file-write behaviour.

  6. info warn → info by review frame-introspection tasks/capabilities.py:182:5

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        previous: Final = sys.getprofile()
        sys.setprofile(interrupt)
        try:
            with suppress(KeyboardInterrupt), contextmanager(probe)():
    likely benign LLM, confidence 0.80 Test-tooling probe that temporarily installs a profile hook to check interpreter capability.
    Reasoning

    This is a repo task that probes whether sys.setprofile can be used safely in the current interpreter, saving and restoring the previous profiler. It is a development capability check and does not persist or exfiltrate anything.

  7. info warn → info by review frame-introspection tasks/capabilities.py:187:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        finally:
            sys.setprofile(previous)
        return bool(finished)
    likely benign LLM, confidence 0.80 Restores the previous profiler in a finally block after the capability probe.
    Reasoning

    The finally block restores the previous profile function after the probe. This is correct cleanup for a temporary profiler install.

  8. info warn → info by review frame-introspection tasks/capabilities.py:230:13

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

                nested.append(True)
                sys.setprofile(sys.getprofile())
    
        sys.addaudithook(setprofile_again)
    likely benign LLM, confidence 0.80 Re-installs the profile hook from inside an audit hook as part of the reentrancy probe.
    Reasoning

    Within the probe, the hook re-sets the profiler from inside an audit hook to test reentrancy. The behaviour is confined to the local check and is not a payload.

  9. info warn → info by review frame-introspection tasks/capabilities.py:234:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        try:
            sys.setprofile(sys.getprofile())
        except RuntimeError:
            return False
    likely benign LLM, confidence 0.80 Feature-detects whether setprofile can be called reentrantly, catching RuntimeError.
    Reasoning

    Calls sys.setprofile(sys.getprofile()) inside a try that catches RuntimeError to determine whether profiler reentry is allowed. This is a standard feature-detection idiom.

  10. info warn → info by review frame-introspection tests/test_async_filelock.py:1524:5

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

    
        sys.setprofile(take_from_cache)
        try:
            AsyncFileLock(lock_path, is_singleton=True, thread_local=thread_local, run_in_executor=False)
    likely benign LLM, confidence 0.85 Test installs a temporary profiler to observe singleton cache lookups in AsyncFileLock.
    Reasoning

    The test installs a profile hook to intercept cache lookups during AsyncFileLock construction, verifying singleton and thread-local behaviour. The hook is removed in a finally block, so this is a test harness.

  11. info warn → info by review frame-introspection tests/test_async_filelock.py:1528:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        finally:
            sys.setprofile(None)
    
        with pytest.raises(Timeout):
    likely benign LLM, confidence 0.85 Clears the test profiler in a finally block.
    Reasoning

    The finally block clears the profiler after the test. This is correct test cleanup.

  12. info warn → info by review frame-introspection tests/test_filelock.py:629:5

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

    
        sys.setprofile(take_from_cache)
        try:
            FileLock(lock_path, is_singleton=True, thread_local=thread_local)
    likely benign LLM, confidence 0.85 Test installs a temporary profiler to observe FileLock singleton cache lookups.
    Reasoning

    The same singleton-cache test pattern as the async variant: a temporary profile hook observes FileLock construction and is cleaned up afterwards. It is a legitimate unit test.

  13. info warn → info by review frame-introspection tests/test_filelock.py:633:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        finally:
            sys.setprofile(None)
        return handed_out.pop()
    likely benign LLM, confidence 0.85 Clears the test profiler in a finally block.
    Reasoning

    The finally block resets the profiler after the test, which is correct cleanup for test instrumentation.

  14. info warn → info by review frame-introspection tests/test_filelock.py:1679:5

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        entered: Final[set[FrameType]] = set()
        sys.setprofile(interrupt)
        try:
            operation()
    likely benign LLM, confidence 0.85 Test installs a profile hook to inject an interrupt during a locking operation.
    Reasoning

    The test sets a profiler to force a reentrant interrupt during an operation and check that the lock stays consistent. This is concurrency testing, not malicious behaviour.

  15. info warn → info by review frame-introspection tests/test_filelock.py:1685:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        finally:
            sys.setprofile(None)
        return False
    likely benign LLM, confidence 0.85 Clears the test profiler in a finally block.
    Reasoning

    The finally block removes the test profiler, which is correct cleanup.

  16. info warn → info by review frame-introspection tests/test_read_write_unit.py:861:5

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

    
        sys.setprofile(look_up_while_closing)
        try:
            del lock
    likely benign LLM, confidence 0.85 Test installs a profile hook to look up read/write locks during close.
    Reasoning

    The test uses a profile hook to look up read or write locks while a lock is being closed, to check for a race. This is a unit test of reentrant lock behaviour.

  17. info warn → info by review frame-introspection tests/test_read_write_unit.py:865:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        finally:
            sys.setprofile(None)
    
        with (looked_up[0].read_lock if mode == "read" else looked_up[0].write_lock)(), pytest.raises(Timeout):
    likely benign LLM, confidence 0.85 Clears the test profiler in a finally block.
    Reasoning

    The finally block clears the profiler after the test, which is correct test cleanup.

  18. info warn → info by review frame-introspection tests/test_soft_lease.py:478:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        def read_compromise() -> None:
            sys.setprofile(pause_in_claim_creation)
            try:
                assert lease.compromise is None
    likely benign LLM, confidence 0.93 Test helper installs a profile hook to inject a pause during lease claim creation.
    Reasoning

    sys.setprofile is used in a test to pause a thread inside claim creation so a concurrent reader can observe the intermediate lease state. This is a standard race-condition testing technique in a lock library's test suite, not obfuscation or malicious behavior.

  19. info warn → info by review frame-introspection tests/test_soft_lease.py:482:13

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

            finally:
                sys.setprofile(None)
    
        reader: Final = Thread(target=read_compromise)
    likely benign LLM, confidence 0.93 Cleanup that removes the test's profile hook in a finally block.
    Reasoning

    The finally block clears the profile hook with sys.setprofile(None) after the reader thread's check. This is cleanup for the same race-testing hook, consistent with a legitimate test.

  20. info warn → info by review frame-introspection tests/test_soft_lifetime_warning.py:47:28

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

            if entry_point == "constructor":
                warning_line = sys._getframe().f_lineno + 1
                lock_type(tmp_path / "test.lock", lifetime=10)
            else:
    likely benign LLM, confidence 0.94 Test captures the current source line number to verify a lifetime warning location.
    Reasoning

    sys._getframe().f_lineno is used to record the line number where a lifetime warning is expected, so the test can assert the warning points at the correct source line. This is a common testing idiom and does not involve obfuscation or hidden execution.

  21. info warn → info by review frame-introspection tests/test_soft_lifetime_warning.py:51:28

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

                lock = lock_type(tmp_path / "test.lock")
                warning_line = sys._getframe().f_lineno + 1
                lock.lifetime = 10
    likely benign LLM, confidence 0.94 Test records the current line to check the warning location for a lifetime assignment.
    Reasoning

    Same pattern: sys._getframe() captures the line number so the test can assert the warning is attributed to the assignment of lock.lifetime. Benign test introspection.

  22. info warn → info by review frame-introspection tests/test_soft_lifetime_warning.py:139:28

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

            if entry_point == "constructor":
                warning_line = sys._getframe().f_lineno + 1
                lock_type(tmp_path / "test.lock", lifetime=10)
            else:
    likely benign LLM, confidence 0.94 Test captures the current line number to validate a constructor-path lifetime warning.
    Reasoning

    Identical use of sys._getframe().f_lineno in a parametrized test to locate the expected warning line for the constructor path. Legitimate test code.

  23. info warn → info by review frame-introspection tests/test_soft_lifetime_warning.py:143:28

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

                lock = lock_type(tmp_path / "test.lock")
                warning_line = sys._getframe().f_lineno + 1
                lock.lifetime = 10
    likely benign LLM, confidence 0.94 Test captures the current line number to validate a lifetime attribute-assignment warning.
    Reasoning

    Repeats the line-number capture for the attribute-assignment path of the lifetime warning test. Benign introspection used only for assertion bookkeeping.

Reproduce This Scan

Run disclude locally to verify. Add --format sarif for SARIF output. Add --llm (with an API key in the environment) to include the LLM review.

cargo install disclude --version 4.0.0
git clone https://github.com/tox-dev/py-filelock py-filelock && cd py-filelock
git checkout 4.2.2
disclude scan --severity info --diff 4.2.1 .