PyPI / filelock / 4.2.3

filelock 4.2.3

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

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.75 A compose service runs a fixed bash sequence that copies the repo, installs it, and runs tox with a Python version override.
    Reasoning

    In compose YAML, `$$` is the escape for a literal `$`, so `$$HOME` becomes `$HOME` at runtime. The embedded command is a fixed sequence (cp, cd, pip install, exec tox run) with no fetched or decoded payload. It reads as a CI/dev-environment helper that runs tox against a copy of the repo, not a dropper.

  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 A lazy module `__getattr__` that resolves and caches attribute names through globals.
    Reasoning

    Assigning `globals()[name]` inside a module-level `__getattr__` is the standard PEP 562 lazy-attribute pattern. It resolves known public names (such as AsyncFileLock) and caches them, with no dynamic code execution.

  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.92 Stores the current stack frame on the lock state during release for bookkeeping.
    Reasoning

    `inspect.currentframe()` is stored on the lock state to record which frame is releasing, for debug logging and reentrancy tracking. It is a normal use inside a locking library.

  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.92 Records the acquiring frame on the lock context during acquisition.
    Reasoning

    The frame is recorded as `acquiring` context during lock acquisition so the library can diagnose re-entrant or concurrent acquisition. The surrounding code is ordinary lock logic.

  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 f_back to locate a caller frame.
    Reasoning

    Walking `f_back` to find a caller frame is a common technique for identifying the calling scope, here used to match a frame. It does not exfiltrate or alter behaviour outside the library.

  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.82 Temporarily installs a profile hook to probe whether profiling interrupts work, then restores the prior hook.
    Reasoning

    This is a capability probe in the project's task tooling. It installs a temporary profile hook, runs a test operation, then restores the previous hook in a finally block. The purpose is checking interpreter behaviour, not hiding code.

  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.82 Restores the previous profile function after the capability probe.
    Reasoning

    This is the restore step in the `finally` block of the same probe, reinstating the saved profile function.

  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 An audit hook re-applies the profile function as part of the capability probe.
    Reasoning

    An audit hook re-installs the profile function when it is cleared, so the probe can detect whether profiling persists. This is an unusual but explainable test-tooling mechanism within a probe that tests for interpreter behaviour.

  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.82 Feature-detects whether the profile hook can be set, returning False if it raises.
    Reasoning

    This calls `sys.setprofile(sys.getprofile())` in a try block and returns False on RuntimeError. It is a feature check that tests whether profile hooks can be set, a benign capability test.

  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.85 Installs a profile hook in a test to observe singleton cache lookups during lock construction.
    Reasoning

    This is a test that installs a profile hook to observe cache lookups while a singleton AsyncFileLock is constructed. That is a targeted concurrency and singleton-caching test, with the hook removed afterwards.

  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.85 Clears the test's profile hook in a finally block.
    Reasoning

    The `finally` clause clears the profile hook after the 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.85 Installs a profile hook in a sync singleton-caching test.
    Reasoning

    This mirrors the async singleton test: a sync FileLock test uses a profile hook to check that the cache hands out the same instance. It is a test technique for a library.

  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's profile hook in a finally block.
    Reasoning

    The `finally` block resets the profile hook after the test, which is normal cleanup.

  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 Installs an interrupting profile hook to test lock behaviour under interruption.
    Reasoning

    This test uses a profile hook to interrupt an operation at a precise point, checking that the lock handles interruption correctly. It is a standard way to test signal and interrupt safety.

  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 interruption profile hook in a finally block.
    Reasoning

    The `finally` block removes the profile hook after the interruption test, which is ordinary 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 Installs a profile hook in a read/write lock unit test to observe lookups during close.
    Reasoning

    This test uses a profile hook to run lookups during lock closing, checking read/write lock lifecycle behaviour. It is a targeted unit test.

  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 read/write test's profile hook in a finally block.
    Reasoning

    The `finally` block clears the profile hook after the test, which is standard test hygiene.

  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.85 Test code installs a temporary profile hook to pause a thread at a chosen point while another thread reads lease state.
    Reasoning

    sys.setprofile installs a profiler hook that pauses a thread at a specific call during a race-condition test (read_compromise). The surrounding code is a lock library's concurrency test, and the hook is cleared in a finally block. This is a test-harness technique for controlling thread interleaving, not malicious introspection.

  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.85 Test code removes the profile hook it installed earlier, restoring normal execution.
    Reasoning

    This is the matching cleanup, sys.setprofile(None) in a finally block, which removes the hook installed at line 488. It is part of the same benign test scaffolding and has no effect outside the 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.92 Test captures its own current line number to verify where a lifetime warning is attributed.
    Reasoning

    sys._getframe().f_lineno is used in a test to record the line number where a lifetime warning is expected, so the test can assert the warning points at the correct source line. It is a common testing idiom with no data exfiltration, dynamic code execution, or obfuscation.

  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.92 Test records its current line number to check the location of a lifetime warning.
    Reasoning

    Same pattern as the other finding in this file: sys._getframe().f_lineno records the expected warning line in a test that checks warning attribution. It is benign introspection within a test.

  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.92 Test uses the current frame's line number as the expected location of a warning.
    Reasoning

    The snippet repeats the test idiom of reading the current frame's line number to compare against a warning's reported location. Nothing in it is malicious or obfuscated.

  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.92 Test reads its own line number to assert where a lifetime warning is raised.
    Reasoning

    This is another instance of the same test-only frame line lookup for asserting warning location. It is a legitimate testing pattern and shows no sign of 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.3
disclude scan --severity info --diff 4.2.2 .