You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Current typehints for numbers.py are worse than useless. #14290
While I understand that typing this module correctly is hard (or even impossible currently) to do, the current situation makes it impossible to use in a sane way since even the most simple of expressions result in false type errors. It would honestly be better to just not have any typing stubs for this module instead of the current ones. Two examples:
Both of these functions result in error messages which might technically be correct in the sense that there are types out there for which these are errors at runtime, but the fact that you can't write them without type ignores or casts means that using this module in combination with type checking is counter productive for finding errors.
It would be strictly better to just remove the _ComplexLike protocol and just make subclasses require type ignores in their method definitions - it's more important for the users (like in the above example) to not have to provide type ignores than for implementers - there are fewer implementers and they probably have a clearer understanding of the edge cases to be aware of.
The numbers module predates typing and is known to work badly with it. Fixing this is outside typeshed's mandate and would probably require changes to CPython and/or type checkers. I think there are already issues open about this in the python/typing repository.
For complex numbers use complex instead of numbers.Complex.
Also, if you have specific suggestions for making the stubs better, please send a PR. Calling the work of the stub authors "worse than useless" is not a good way to start a discussion.
Also, if you have specific suggestions for making the stubs better, please send a PR.
I mean, I have a suggestion, and mentioned it, but it would go against the currently established pattern. I don't think there is any chance of the PR being accepted unless other people agree that the current situation is very bad.
Calling the work of the stub authors "worse than useless" is not a good way to start a discussion.
Based on the current content of that .pyi file I need to argue why the current situation is bad, since it's clearly the work of years of work - and that is what I am expressing with that statement. This is not an attack on any author, just an expression of frustration with the current state. I assume the original authors of the file (whoever they are) have not fully considered the usability or have different weighting of whose experiences need to be good.
If you don't like my tone, ignoring every word I said, and just look at the two example functions I provided. Do you think it's sensible that they result in type checking errors?
I think there are already issues open about this in the python/typing repository.
No, there are only closed issues saying the numeric tower is useless and shouldn't be used or shifting the blame and work onto typeshed.
For complex numbers use complex instead of numbers.Complex.
This obviously isn't a solution:
def f3(a: complex, b: complex) -> complex:
return a * b
f3(Fraction(1,2), Fraction(2, 3))
I don't actually necessarily need Complex - Real or Rational would also be fine. But those types don't work either.
I would consider a PR loosening the annotations on the numbers module. Instead of arguing, make a PR and show the results of the change (e.g., by adding test cases or checking mypy-primer output).
Effectively I would be undoing #11353, which is exactly what I mean with "worse than useless". It would have been better for users to never merge this PR and do less work and leave the number types as untyped.
Most of the current annotations in the numbers module were added around a year and a half ago by me in #11353 and #11375. You can see the discussions in #11353 (comment), #11353 (comment), and the mypy_primer reports on the two PRs for some of the motivations for those changes.
I did put some effort into those PRs, it's true, because we've had years of complaints about the poor quality of annotations for this module, and I felt like it would be nice to move things forward somehow. The mypy_primer reports on those PRs that showed errors going away seemed to confirm that there were ways of making small progress even without type checkers adding any special understanding of these ABCs or us rewriting the MROs of fundamental types like int, float and complex (which would be quite hard to do).
With regards to your issue here, I don't think there's any way of annotating the numbers module that would make this program type check soundly, unfortunately:
If we just wanted to stop type checkers complaining about your code, we could consider simply reverting #11353 and #11375. But is that the correct thing to do? Most people add type annotations to their code because they want type checkers to attempt to verify the correctness of their code. If you have two arbitrary objects a and b and all that you know about them is that they are both considered instances of the Complex ABC by a type checker, it is indeed true that you can't really say anything about whether the operation a * b is going to return an object that the type checker will consider an instance of Complex. A lot of implementations might choose to return a float, for example, which is considered an instance of Complex at runtime but not by type checkers. Although the error messages from type checkers aren't great here, you could consider them an accurate warning that the type checker just doesn't really understand code that makes use of the numbers module in this way.
I'm very open to reverting #11353 and #11375 if we think it's the correct tradeoff for users -- but I'm curious to learn more about your use case. Have you considered using protocol types, which would allow you to more precisely express exactly the interface you want the types passed in to support?
Have you considered using protocol types, which would allow you to more precisely express exactly the interface you want the types passed in to support?
I want to write simple code that works on most things that act "like a number". I can accept that the Number type itself fails to do this because it has no requirements on the supported interface. So I use Complex instead, a pretty broad type that still theoretically fullfils the constraints I need.
I, as a user who writes scripts, but still use type annotations in an IDE, do not want to have to hand roll by own protocols, type ignores or cast for code that is simple and does the right thing :TM: 99% of the time.
I would much prefer for the numbers stub file to more or less actively lie about it and say that __add__(Complex, Complex) returns a Complex. Yes, it might not be correct for some weird edge cases (which ones?), but it's going to be far more useful for users. And IMO user experience should be high on the list of correctness isn't achievable anyway.
The current situation is actively user-hostile and, based on your message, essentially by design since they probably shouldn't be using this module. No user is going to gain anything from using these classes, meaning they are better of just leaving their code untyped.
Most people add type annotations to their code because they want type checkers to attempt to verify the correctness of their code.
Can you show me real examples where these functions behave incorrectly and cause issues? What real-world types do I need to pass into here to get a type error at runtime?
Activity
srittau commentedon Jun 17, 2025
The
numbersmodule predates typing and is known to work badly with it. Fixing this is outside typeshed's mandate and would probably require changes to CPython and/or type checkers. I think there are already issues open about this in the python/typing repository.For complex numbers use
complexinstead ofnumbers.Complex.JelleZijlstra commentedon Jun 17, 2025
Also, if you have specific suggestions for making the stubs better, please send a PR. Calling the work of the stub authors "worse than useless" is not a good way to start a discussion.
MegaIng commentedon Jun 17, 2025
I mean, I have a suggestion, and mentioned it, but it would go against the currently established pattern. I don't think there is any chance of the PR being accepted unless other people agree that the current situation is very bad.
Based on the current content of that
.pyifile I need to argue why the current situation is bad, since it's clearly the work of years of work - and that is what I am expressing with that statement. This is not an attack on any author, just an expression of frustration with the current state. I assume the original authors of the file (whoever they are) have not fully considered the usability or have different weighting of whose experiences need to be good.If you don't like my tone, ignoring every word I said, and just look at the two example functions I provided. Do you think it's sensible that they result in type checking errors?
No, there are only closed issues saying the numeric tower is useless and shouldn't be used or shifting the blame and work onto typeshed.
This obviously isn't a solution:
I don't actually necessarily need Complex - Real or Rational would also be fine. But those types don't work either.
JelleZijlstra commentedon Jun 17, 2025
I would consider a PR loosening the annotations on the numbers module. Instead of arguing, make a PR and show the results of the change (e.g., by adding test cases or checking mypy-primer output).
MegaIng commentedon Jun 17, 2025
Effectively I would be undoing #11353, which is exactly what I mean with "worse than useless". It would have been better for users to never merge this PR and do less work and leave the number types as untyped.
JelleZijlstra commentedon Jun 17, 2025
We've reverted PRs before if further experience shows they were not the right solution.
AlexWaygood commentedon Jun 17, 2025
Most of the current annotations in the
numbersmodule were added around a year and a half ago by me in #11353 and #11375. You can see the discussions in #11353 (comment), #11353 (comment), and the mypy_primer reports on the two PRs for some of the motivations for those changes.I did put some effort into those PRs, it's true, because we've had years of complaints about the poor quality of annotations for this module, and I felt like it would be nice to move things forward somehow. The mypy_primer reports on those PRs that showed errors going away seemed to confirm that there were ways of making small progress even without type checkers adding any special understanding of these ABCs or us rewriting the MROs of fundamental types like
int,floatandcomplex(which would be quite hard to do).With regards to your issue here, I don't think there's any way of annotating the
numbersmodule that would make this program type check soundly, unfortunately:If we just wanted to stop type checkers complaining about your code, we could consider simply reverting #11353 and #11375. But is that the correct thing to do? Most people add type annotations to their code because they want type checkers to attempt to verify the correctness of their code. If you have two arbitrary objects
aandband all that you know about them is that they are both considered instances of theComplexABC by a type checker, it is indeed true that you can't really say anything about whether the operationa * bis going to return an object that the type checker will consider an instance ofComplex. A lot of implementations might choose to return afloat, for example, which is considered an instance ofComplexat runtime but not by type checkers. Although the error messages from type checkers aren't great here, you could consider them an accurate warning that the type checker just doesn't really understand code that makes use of thenumbersmodule in this way.I'm very open to reverting #11353 and #11375 if we think it's the correct tradeoff for users -- but I'm curious to learn more about your use case. Have you considered using protocol types, which would allow you to more precisely express exactly the interface you want the types passed in to support?
MegaIng commentedon Jun 17, 2025
I want to write simple code that works on most things that act "like a number". I can accept that the
Numbertype itself fails to do this because it has no requirements on the supported interface. So I useComplexinstead, a pretty broad type that still theoretically fullfils the constraints I need.I, as a user who writes scripts, but still use type annotations in an IDE, do not want to have to hand roll by own protocols, type ignores or cast for code that is simple and does the right thing :TM: 99% of the time.
I would much prefer for the
numbersstub file to more or less actively lie about it and say that__add__(Complex, Complex)returns aComplex. Yes, it might not be correct for some weird edge cases (which ones?), but it's going to be far more useful for users. And IMO user experience should be high on the list of correctness isn't achievable anyway.The current situation is actively user-hostile and, based on your message, essentially by design since they probably shouldn't be using this module. No user is going to gain anything from using these classes, meaning they are better of just leaving their code untyped.
Can you show me real examples where these functions behave incorrectly and cause issues? What real-world types do I need to pass into here to get a type error at runtime?