Skip to content
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

False negative for PYI016 Duplicate union member #15815

Open
nickdrozd opened this issue Jan 29, 2025 · 3 comments
Open

False negative for PYI016 Duplicate union member #15815

nickdrozd opened this issue Jan 29, 2025 · 3 comments
Labels
question Asking for support or clarification

Comments

@nickdrozd
Copy link
Contributor

Description

Q = int | int

Not flagged, should raise PYI016

ruff 0.9.3

@AlexWaygood
Copy link
Member

This is because Ruff can't be sure here that Q is a type alias, so it doesn't know whether to analyse it as a type expression or a value expression. If you explicitly annotate it with typing.TypeAlias or typing_extensions.TypeAlias, the diagnostic is emitted as expected:

from typing import TypeAlias

Q: TypeAlias = int | int

Same if you use a type statement on Python 3.12 or newer:

type Q = int | int

@AlexWaygood AlexWaygood added the question Asking for support or clarification label Jan 29, 2025
@nickdrozd
Copy link
Contributor Author

This is because Ruff can't be sure here that Q is a type alias, so it doesn't know whether to analyse it as a type expression or a value expression.

I don't think it matters how it is used. AFAICT, there is literally no difference between int | int and int:

assert int is int | int
assert int == int | int

##############################

Q = int | int

assert Q is int

q = int

assert q is q | q

assert Q is q

##############################

from typing import TypeAlias

P: TypeAlias = int | int

assert P is int

assert P is Q

assert P is q

Is there any situation in which int | int would be preferred to int? Or IOW, any situation in which flagging this would be a false positive?

Can't speak for others, but I have definitely done this before, and it was definitely a mistake.

@AlexWaygood
Copy link
Member

From a human's perspective, it's obvious that X = int | int is an attempt to create a type alias. But from a static-analysis tool's perspective, how can it unambiguously differentiate X = int | int from Y = 42 | 56 (which is not a type alias, just a normal value being assigned to a variable)?

This would be easier for Ruff if it had better type inference. But even for type checkers, differentiating type aliases from other assignments isn't easy. If it were easy, there wouldn't be any need for typing.TypeAlias at all, and PEP 613 would never have been written :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Asking for support or clarification
Projects
None yet
Development

No branches or pull requests

2 participants