fix pyrefly does not track mapping keys after explicit check #289#2283
fix pyrefly does not track mapping keys after explicit check #289#2283asukaminato0721 wants to merge 1 commit intofacebook:mainfrom
Conversation
There was a problem hiding this comment.
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`
|
|
@yangdanny97 has imported this pull request. If you are a Meta employee, you can view this in D92405594. |
stroxler
left a comment
There was a problem hiding this comment.
Review automatically exported from Phabricator review in Meta.
|
@yangdanny97 merged this pull request in 049c2bf. |
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.