Skip to content

Commit 92229e6

Browse files
Your Nameclaude
andcommitted
fix(optional_dereference): suppress zero-arg .get() false positives
dict.get() requires at least one positional key argument; .get() with no arguments is always a custom class method (e.g. Twisted DeferredQueue.get(), stats collector .get()). The prior guard only short-circuited the kwargs-only case (Django ORM pattern), leaving bare .get() calls incorrectly flagged. Regression: jasmin/managers/clients.py DeferredQueue pattern. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent af0ad8a commit 92229e6

2 files changed

Lines changed: 26 additions & 0 deletions

File tree

failure_mode.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ def visit_Assign(self, node):
230230
# dict.get() is never called on a chained method result.
231231
if isinstance(recv, _ast.Call):
232232
return
233+
# Zero-arg .get() — dict.get() requires at least one positional
234+
# arg (the key); a bare .get() call is a custom class method
235+
# (e.g. Twisted DeferredQueue.get(), stats collector .get()).
236+
if not call_args and not node.value.keywords:
237+
return
233238
# Django ORM queryset.get(**kwargs) — no positional args, only
234239
# keyword field lookups like .get(pk=1) or .get(user=user).
235240
# dict.get() ALWAYS takes a positional key; kwargs-only means ORM.

test_checker.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,3 +1927,24 @@ async def main(urls):
19271927
violations = check_codebase(tmp_path)
19281928
ma = [v for v in violations if v.context == "missing_await" and "direct_gather.py" in v.file]
19291929
assert len(ma) == 0, f"Expected 0 missing_await for starred comprehension, got {len(ma)}: {[(v.line, v.call) for v in ma]}"
1930+
1931+
1932+
def test_optional_dereference_zero_arg_get_not_flagged(tmp_path):
1933+
"""obj.get() with no args is a custom method (e.g. Twisted DeferredQueue), not dict.get().
1934+
dict.get() always requires at least one positional key argument."""
1935+
_write_src(
1936+
tmp_path,
1937+
"twisted_queue.py",
1938+
"""
1939+
class DeferredQueue:
1940+
def get(self):
1941+
return Deferred()
1942+
1943+
def process(queue):
1944+
d = queue.get()
1945+
d.addCallback(handler)
1946+
""",
1947+
)
1948+
violations = check_codebase(tmp_path)
1949+
od = [v for v in violations if v.context == "optional_dereference" and "twisted_queue.py" in v.file]
1950+
assert len(od) == 0, f"Expected 0 optional_dereference for zero-arg .get(), got {len(od)}: {[(v.line, v.call) for v in od]}"

0 commit comments

Comments
 (0)