-
Notifications
You must be signed in to change notification settings - Fork 262
fix pyrefly does not track mapping keys after explicit check #289 #2283
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes issue #289 where pyrefly didn't track mapping keys after explicit in checks. Previously, narrowing only worked for TypedDict types. After this change, if "key" in mapping: now properly narrows the type so that mapping.get("key") returns the value type instead of value_type | None.
Changes:
- Extended key-existence narrowing from TypedDict-only to all dict-like types (dict and its subtypes)
- Added regression test for dict narrowing with
inchecks
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| pyrefly/lib/alt/narrow.rs | Replaced TypedDict-specific check with is_dict_like() method call for both HasKey and NotHasKey narrowing operations |
| pyrefly/lib/test/subscript_narrow.rs | Added test case verifying that in checks properly narrow dict types for both .get() and subscript access |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Diff from mypy_primer, showing the effect of this PR on open source code: urllib3 (https://github.com/urllib3/urllib3)
+ ERROR src/urllib3/poolmanager.py:483:27-45: Object of class `Mapping` has no attribute `copy` [missing-attribute]
+ ::error file=src/urllib3/poolmanager.py,line=483,col=27,endLine=483,endColumn=45,title=Pyrefly missing-attribute::Object of class `Mapping` has no attribute `copy`
cloud-init (https://github.com/canonical/cloud-init)
+ ERROR cloudinit/config/cc_growpart.py:563:35-39: Argument `bool | list[str] | str | Unknown` is not assignable to parameter `mode` with type `str` in function `resizer_factory` [bad-argument-type]
+ ERROR cloudinit/sources/DataSourceVMware.py:358:9-23: Class member `DataSourceVMware.network_config` overrides parent class `DataSource` in an inconsistent manner [bad-override]
+ ::error file=cloudinit/config/cc_growpart.py,line=563,col=35,endLine=563,endColumn=39,title=Pyrefly bad-argument-type::Argument `bool | list[str] | str | Unknown` is not assignable to parameter `mode` with type `str` in function `resizer_factory`
+ ::error file=cloudinit/sources/DataSourceVMware.py,line=358,col=9,endLine=358,endColumn=23,title=Pyrefly bad-override::Class member `DataSourceVMware.network_config` overrides parent class `DataSource` in an inconsistent manner%0A Property getter for `DataSourceVMware.network_config` has type `BoundMethod[DataSourceVMware, (self: DataSourceVMware) -> dict[Unknown, Unknown] | Unknown | None]`, which is not assignable to `BoundMethod[DataSourceVMware, (self: DataSourceVMware) -> None]`, the property getter for `DataSource.network_config`
pwndbg (https://github.com/pwndbg/pwndbg)
- ERROR pwndbg/gdblib/vmmap.py:433:39-73: `None` is not subscriptable [unsupported-operation]
- ::error file=pwndbg/gdblib/vmmap.py,line=433,col=39,endLine=433,endColumn=73,title=Pyrefly unsupported-operation::`None` is not subscriptable
pyjwt (https://github.com/jpadilla/pyjwt)
- ERROR jwt/algorithms.py:749:34-46: Argument `Unknown | None` is not assignable to parameter `input` with type `bytes | str` in function `jwt.utils.base64url_decode` [bad-argument-type]
- ERROR jwt/algorithms.py:750:34-46: Argument `Unknown | None` is not assignable to parameter `input` with type `bytes | str` in function `jwt.utils.base64url_decode` [bad-argument-type]
- ERROR jwt/algorithms.py:795:34-46: Argument `Unknown | None` is not assignable to parameter `input` with type `bytes | str` in function `jwt.utils.base64url_decode` [bad-argument-type]
- ERROR jwt/algorithms.py:986:34-46: Argument `Unknown | None` is not assignable to parameter `input` with type `bytes | str` in function `jwt.utils.base64url_decode` [bad-argument-type]
- ERROR jwt/algorithms.py:993:38-50: Argument `Unknown | None` is not assignable to parameter `input` with type `bytes | str` in function `jwt.utils.base64url_decode` [bad-argument-type]
- ::error file=jwt/algorithms.py,line=749,col=34,endLine=749,endColumn=46,title=Pyrefly bad-argument-type::Argument `Unknown | None` is not assignable to parameter `input` with type `bytes | str` in function `jwt.utils.base64url_decode`
- ::error file=jwt/algorithms.py,line=750,col=34,endLine=750,endColumn=46,title=Pyrefly bad-argument-type::Argument `Unknown | None` is not assignable to parameter `input` with type `bytes | str` in function `jwt.utils.base64url_decode`
- ::error file=jwt/algorithms.py,line=795,col=34,endLine=795,endColumn=46,title=Pyrefly bad-argument-type::Argument `Unknown | None` is not assignable to parameter `input` with type `bytes | str` in function `jwt.utils.base64url_decode`
- ::error file=jwt/algorithms.py,line=986,col=34,endLine=986,endColumn=46,title=Pyrefly bad-argument-type::Argument `Unknown | None` is not assignable to parameter `input` with type `bytes | str` in function `jwt.utils.base64url_decode`
- ::error file=jwt/algorithms.py,line=993,col=38,endLine=993,endColumn=50,title=Pyrefly bad-argument-type::Argument `Unknown | None` is not assignable to parameter `input` with type `bytes | str` in function `jwt.utils.base64url_decode`
apprise (https://github.com/caronc/apprise)
- ERROR apprise/config/base.py:146:29-51: `object | None` is not assignable to attribute `encoding` with type `str` [bad-assignment]
+ ERROR apprise/config/base.py:146:29-51: `object` is not assignable to attribute `encoding` with type `str` [bad-assignment]
- ERROR apprise/plugins/bluesky.py:258:21-52: Cannot set item in `None` [unsupported-operation]
- ERROR apprise/plugins/bluesky.py:261:21-47: Cannot set item in `None` [unsupported-operation]
- ERROR apprise/plugins/bluesky.py:263:17-44: Cannot set item in `None` [unsupported-operation]
- ERROR apprise/plugins/bluesky.py:327:12-26: Object of class `NoneType` has no attribute `startswith` [missing-attribute]
- ERROR apprise/plugins/bluesky.py:354:14-28: Object of class `NoneType` has no attribute `startswith` [missing-attribute]
- ERROR apprise/plugins/bluesky.py:356:22-29: `None` is not subscriptable [unsupported-operation]
- ERROR apprise/url.py:252:50-67: Argument `Unknown | None` is not assignable to parameter `x` with type `Buffer | SupportsFloat | SupportsIndex | str` in function `float.__new__` [bad-argument-type]
- ERROR apprise/url.py:261:53-70: Argument `Unknown | None` is not assignable to parameter `x` with type `Buffer | SupportsFloat | SupportsIndex | str` in function `float.__new__` [bad-argument-type]
- ::error file=apprise/config/base.py,line=146,col=29,endLine=146,endColumn=51,title=Pyrefly bad-assignment::`object | None` is not assignable to attribute `encoding` with type `str`
+ ::error file=apprise/config/base.py,line=146,col=29,endLine=146,endColumn=51,title=Pyrefly bad-assignment::`object` is not assignable to attribute `encoding` with type `str`
- ::error file=apprise/plugins/bluesky.py,line=258,col=21,endLine=258,endColumn=52,title=Pyrefly unsupported-operation::Cannot set item in `None`%0A Object of class `NoneType` has no attribute `__setitem__`
- ::error file=apprise/plugins/bluesky.py,line=261,col=21,endLine=261,endColumn=47,title=Pyrefly unsupported-operation::Cannot set item in `None`%0A Object of class `NoneType` has no attribute `__setitem__`
- ::error file=apprise/plugins/bluesky.py,line=263,col=17,endLine=263,endColumn=44,title=Pyrefly unsupported-operation::Cannot set item in `None`%0A Object of class `NoneType` has no attribute `__setitem__`
- ::error file=apprise/plugins/bluesky.py,line=327,col=12,endLine=327,endColumn=26,title=Pyrefly missing-attribute::Object of class `NoneType` has no attribute `startswith`
- ::error file=apprise/plugins/bluesky.py,line=354,col=14,endLine=354,endColumn=28,title=Pyrefly missing-attribute::Object of class `NoneType` has no attribute `startswith`
- ::error file=apprise/plugins/bluesky.py,line=356,col=22,endLine=356,endColumn=29,title=Pyrefly unsupported-operation::`None` is not subscriptable
- ::error file=apprise/url.py,line=252,col=50,endLine=252,endColumn=67,title=Pyrefly bad-argument-type::Argument `Unknown | None` is not assignable to parameter `x` with type `Buffer | SupportsFloat | SupportsIndex | str` in function `float.__new__`
- ::error file=apprise/url.py,line=261,col=53,endLine=261,endColumn=70,title=Pyrefly bad-argument-type::Argument `Unknown | None` is not assignable to parameter `x` with type `Buffer | SupportsFloat | SupportsIndex | str` in function `float.__new__`
sphinx (https://github.com/sphinx-doc/sphinx)
+ ERROR sphinx/cmd/quickstart.py:248:19-28: `bool | str | Any` is not assignable to `str` [bad-assignment]
+ ERROR sphinx/cmd/quickstart.py:319:57-69: Argument `bool | str | Any` is not assignable to parameter `default` with type `str | None` in function `do_prompt` [bad-argument-type]
+ ERROR sphinx/cmd/quickstart.py:361:14-23: `bool | str | Any` is not assignable to variable `d_path` with type `str` [bad-assignment]
+ ERROR sphinx/cmd/quickstart.py:362:21-32: `bool | str | Any` is not assignable to `str` [bad-assignment]
+ ERROR sphinx/cmd/quickstart.py:363:21-32: `bool | str | Any` is not assignable to `str` [bad-assignment]
+ ERROR sphinx/cmd/quickstart.py:385:13-24: Argument `bool | str | Any` is not assignable to parameter `default` with type `str | None` in function `do_prompt` [bad-argument-type]
+ ::error file=sphinx/cmd/quickstart.py,line=248,col=19,endLine=248,endColumn=28,title=Pyrefly bad-assignment::`bool | str | Any` is not assignable to `str`
+ ::error file=sphinx/cmd/quickstart.py,line=319,col=57,endLine=319,endColumn=69,title=Pyrefly bad-argument-type::Argument `bool | str | Any` is not assignable to parameter `default` with type `str | None` in function `do_prompt`
+ ::error file=sphinx/cmd/quickstart.py,line=361,col=14,endLine=361,endColumn=23,title=Pyrefly bad-assignment::`bool | str | Any` is not assignable to variable `d_path` with type `str`
+ ::error file=sphinx/cmd/quickstart.py,line=362,col=21,endLine=362,endColumn=32,title=Pyrefly bad-assignment::`bool | str | Any` is not assignable to `str`
+ ::error file=sphinx/cmd/quickstart.py,line=363,col=21,endLine=363,endColumn=32,title=Pyrefly bad-assignment::`bool | str | Any` is not assignable to `str`
+ ::error file=sphinx/cmd/quickstart.py,line=385,col=13,endLine=385,endColumn=24,title=Pyrefly bad-argument-type::Argument `bool | str | Any` is not assignable to parameter `default` with type `str | None` in function `do_prompt`
|
Summary
Fixes #289
Expanded key‑existence narrowing to dict‑like types so "key" in mapping now makes mapping.get("key") return the value type (not None)
Test Plan
Added a regression test for the dict case. This matches the expected behavior described in issue 289.