Skip to content

Fix isinstance narrowing for classes with __getattr__ returning Any#21105

Open
jpbeaudry wants to merge 1 commit intopython:masterfrom
jpbeaudry:fix-16590-getattr-narrowing
Open

Fix isinstance narrowing for classes with __getattr__ returning Any#21105
jpbeaudry wants to merge 1 commit intopython:masterfrom
jpbeaudry:fix-16590-getattr-narrowing

Conversation

@jpbeaudry
Copy link
Copy Markdown

Fixes #16590

When a class has __getattr__ returning Any and appears in a union with a protocol type, the else-branch of isinstance fails to narrow the class away.

The problem is in narrow_declared_type() in meet.py. When processing union members against the narrowed type, is_overlapping_types(A, Protocol) returns True because __getattr__Any structurally satisfies any protocol. Then meet_types(A, Protocol) returns A, so A leaks back into the result and the narrowing is effectively undone.

The fix: after narrowing a union member d against a protocol n, if the result is d unchanged and d is not nominally related to n (only structurally, via __getattr__), exclude it from the narrowed union.

Test added in check-isinstance.test covering both __getattr__Any and __getattr__str cases.

This is my first contribution to mypy — happy to adjust the approach if there's a better way to handle this.

@github-actions
Copy link
Copy Markdown
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

pandas (https://github.com/pandas-dev/pandas)
+ pandas/core/frame.py:14737: error: Incompatible return value type (got "DataFrame | Series", expected "DataFrame")  [return-value]

werkzeug (https://github.com/pallets/werkzeug)
+ src/werkzeug/datastructures/file_storage.py:189: error: Unused "type: ignore" comment  [unused-ignore]

@jpbeaudry
Copy link
Copy Markdown
Author

Primer results look correct per predominantly AI analysis:

  • werkzeug: type: ignore[assignment] is now unused because the narrowing improvement makes it unnecessary.
  • pandas: the return type DataFrame | Series was previously narrowed incorrectly; mypy now correctly reports the mismatch.

Both appear to be cases where the fix improves narrowing accuracy rather than introducing false positives.

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.

Type narrowing fails for classes with custom __getattr__

1 participant