PyPI / filelock / 4.2.4

filelock 4.2.4

Source
https://github.com/tox-dev/py-filelock
Tag scanned
4.2.4
Compared with
4.2.3 (0 signals introduced since)
Files
95 scanned, 9 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 23 info
Scan time
17.6 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-20 11:14

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.80 A compose service that copies the repo to a work directory and runs tox tests on Python 3.14.
    Reasoning

    The snippet is a tox CI/test setup in a compose file: copy the repo, pip install, run tox with a Python version override. The flagged `$$` is Compose escaping for a shell variable ($HOME), not a dynamic command name. The command itself (cp, pip, tox) is ordinary build tooling, with no download, decode, or pipe-to-shell pattern.

  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 Lazy attribute resolution in the filelock package that caches looked-up names in module globals.
    Reasoning

    This is a lazy module `__getattr__` pattern that resolves names such as AsyncFileLock and caches them into globals. It is a standard, well-understood way to implement lazy exports in a library, and the names come from the package's own classes.

  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.93 Records the current frame on the lock state during release for logging purposes.
    Reasoning

    The lock stores the current frame in state.releasing so debug logging can report the caller. This is diagnostic bookkeeping in a file-locking library, not a sign of 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.93 Records the current frame as the acquiring context during lock acquisition.
    Reasoning

    Stores the current frame as the acquiring context so the acquisition logic can track its caller. This is ordinary internal state handling in a 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.92 Walks the call stack via currentframe and f_back to locate a specific frame.
    Reasoning

    Walks the f_back chain to find a frame in the call stack, likely to detect whether a lock is held by a caller. This is a routine stack walk for reentrancy or ownership logic, with no network, exec, or hidden payload.

  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.88 A probe that installs a temporary profile hook to test interrupt handling, restoring the previous hook afterward.
    Reasoning

    This is a development task script that probes whether sys.setprofile can interrupt code, which matters for KeyboardInterrupt safety in the lock. It saves and restores the previous profiler, and it has no exfiltration or persistence behavior.

  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.88 Restores the previous profile hook in a finally block after a capability probe.
    Reasoning

    This is the restore step in a finally block that resets the profiler set earlier. It is paired cleanup for the probe above.

  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.85 Re-sets the profile hook from within an audit hook as part of a capability probe.
    Reasoning

    Inside an audit hook used for a capability test, the code re-applies the current profile hook to check whether re-entrant setprofile calls are handled. This is a test of interpreter behavior, not a stealthy hook that intercepts user data.

  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.85 Checks whether setprofile is usable here, returning False on RuntimeError.
    Reasoning

    A probe for whether sys.setprofile can be called in the current context, with RuntimeError caught to return False. It is a capability check with no malicious side effects.

  10. info warn → info by review frame-introspection tests/test_async_filelock.py:1525: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.92 Test-only profile hook that exercises singleton cache behavior during AsyncFileLock construction.
    Reasoning

    A test installs a profile hook to force a cache-related race in AsyncFileLock singleton creation, then clears it. This is concurrency test instrumentation in a locking library's test suite.

  11. info warn → info by review frame-introspection tests/test_async_filelock.py:1529: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.92 Clears the profile hook in a finally block after an async lock test.
    Reasoning

    Clears the test's profile hook in a finally block after the race test, which is standard 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.92 Test-only profile hook that exercises FileLock singleton cache behavior.
    Reasoning

    Same pattern as the async test: a test-only profile hook forces a singleton cache race while constructing FileLock. It is test instrumentation with no external effects.

  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.92 Clears the profile hook after a FileLock singleton test.
    Reasoning

    Clears the test profile hook in a finally block. This is standard cleanup for a test.

  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.90 Test profile hook that injects interrupts to check lock robustness.
    Reasoning

    A test installs an interrupt-injecting profile hook to verify that the lock handles KeyboardInterrupt during operations. This is a robustness test in a locking library.

  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.92 Clears the interrupt profile hook after a robustness test.
    Reasoning

    Clears the interrupt-injecting profile hook in a finally block, which is standard test 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.92 Test profile hook that inspects lock lookups while a lock is closing.
    Reasoning

    A test sets a profile hook that looks up locks during close, to check reentrancy in the read/write lock. This is targeted concurrency testing in a locking library.

  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.92 Clears the profile hook after a read/write lock unit test.
    Reasoning

    Clears the test profile hook in a finally block, which is standard test cleanup.

  18. info warn → info by review frame-introspection tests/test_soft_lease.py:488: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 code installs a profile hook to inject a pause while checking lease compromise state under concurrency.
    Reasoning

    sys.setprofile is used in a test to pause a reader thread at a chosen point inside claim creation, so the test can check the compromise state during a race. Test-harness instrumentation like this is a legitimate pattern, and the snippet shows no exfiltration or hidden execution.

  19. info warn → info by review frame-introspection tests/test_soft_lease.py:492: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 Test code clears the profile hook it installed earlier, in a finally block.
    Reasoning

    The matching sys.setprofile(None) in the finally block removes the test's profile hook after the reader runs. This is cleanup for the same concurrency test and is not malicious.

  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.95 Test records its own line number with sys._getframe to verify warning location.
    Reasoning

    sys._getframe().f_lineno is used to record the current line so the test can assert that a lifetime warning points at the correct source line. This is a common test technique and does not touch anything sensitive.

  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.95 Test uses sys._getframe to compute the expected warning line number.
    Reasoning

    Same pattern as the other findings: the frame's line number is captured to compute the expected warning line in a test assertion. No dynamic execution or evasion is involved.

  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.95 Test reads the current frame line number to check the lifetime warning location.
    Reasoning

    This is a repeated test case that captures the current line via sys._getframe to assert the warning location for the constructor entry point. It is benign test scaffolding.

  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.95 Test captures its own line number via sys._getframe for warning-location assertions.
    Reasoning

    Same benign test pattern: sys._getframe().f_lineno supplies the expected line for an assertion on a lifetime warning. Nothing in the snippet indicates obfuscation or malicious intent.

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.4
disclude scan --severity info --diff 4.2.3 .