fix pyrefly does not track mapping keys after explicit check #289#2283
Open
asukaminato0721 wants to merge 1 commit intofacebook:mainfrom
Open
fix pyrefly does not track mapping keys after explicit check #289#2283asukaminato0721 wants to merge 1 commit intofacebook:mainfrom
asukaminato0721 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`
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.