Skip to content

Fix kwarg detection for chained receivers (issue #327)#344

Open
apoorvdarshan wants to merge 1 commit into
netromdk:masterfrom
apoorvdarshan:fix/issue-327-chained-receiver-kwargs
Open

Fix kwarg detection for chained receivers (issue #327)#344
apoorvdarshan wants to merge 1 commit into
netromdk:masterfrom
apoorvdarshan:fix/issue-327-chained-receiver-kwargs

Conversation

@apoorvdarshan

Copy link
Copy Markdown

Fixes #327

Root cause

For a chained receiver such as Path.cwd().exists(follow_symlinks=True), the resolved
function name includes the intermediate cwd() call segment, so the kwarg is looked up
under ('pathlib.Path.cwd.exists', 'follow_symlinks'). That tuple does not match the rule
key ('pathlib.Path.exists', 'follow_symlinks') in KWARGS_REQS, so the follow_symlinks
kwarg is silently dropped and the minimum version is under-reported.

Reproduction

from pathlib import Path
print(Path.cwd().exists(follow_symlinks=True))

Before (wrong):

$ vermin repro.py
Minimum required versions: 3.4

After (correct):

$ vermin repro.py
Minimum required versions: 3.12

The direct form Path('.').exists(follow_symlinks=True) was already reported correctly as
3.12; only the chained-receiver form was affected. The same problem applied to the other
pathlib methods that gained follow_symlinks in 3.13 (e.g. is_file, is_dir), as noted
in the issue thread.

Fix

In SourceVisitor.visit_keyword, when the fully resolved function name does not match a
known kwarg rule and it contains more than two segments (i.e. a chained call), retry with
the intermediate call segment(s) collapsed away — keeping the receiver plus the final
method (pathlib.Path.exists). Because an already-resolved receiver can span several
segments (e.g. pathlib.Path.cwd.exists), each receiver-length prefix is tried joined with
the final method. A collapsed candidate is only accepted when (name, kwarg) is an actual
entry in kwargs_reqs_rules, so unrelated chains (e.g. foo.bar().exists(...)) cannot
produce false matches. The change is localized to the existing kwarg-resolution loop and
does not alter any of the primary lookup paths.

Tests

Added focused regression tests in tests/kwargs.py for the chained-receiver form of
Path.exists, Path.is_file, and Path.is_dir. They fail on the unmodified code and pass
with the fix. The full existing suite (python3 runtests.py, 4382 tests across 26 suites)
passes, and flake8 is clean on the changed files.

Disclosure: prepared with AI assistance; reviewed and verified locally.

A chained receiver such as `Path.cwd().exists(follow_symlinks=True)` was
detected under the name `pathlib.Path.cwd.exists`, because the intermediate
`cwd()` call segment is included in the resolved function name. That name does
not match the kwarg rule key `pathlib.Path.exists`, so `follow_symlinks` was
silently dropped and the code was reported as requiring 3.4 instead of 3.12.

When the full resolved name does not match a known kwarg rule, retry with the
intermediate call segment(s) collapsed away, keeping the receiver plus the
final method. Every receiver-length prefix is tried joined with the final
method, and a collapsed candidate is only accepted when it corresponds to an
actual kwarg rule, so unrelated chains cannot produce false matches.

Also fixes the same issue for the other pathlib methods that gained a
`follow_symlinks` kwarg in 3.13 (e.g. `is_file`, `is_dir`).
@apoorvdarshan
apoorvdarshan requested a review from netromdk as a code owner July 9, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Path.exists(follow_symlinks=True) isn't detected as requiring 3.12

1 participant