Skip to content

Fix incorrect self-comparison for InfinityType and NegativeInfinityType#1093

Open
bysiber wants to merge 3 commits intopypa:mainfrom
bysiber:fix/infinity-self-comparison
Open

Fix incorrect self-comparison for InfinityType and NegativeInfinityType#1093
bysiber wants to merge 3 commits intopypa:mainfrom
bysiber:fix/infinity-self-comparison

Conversation

@bysiber
Copy link

@bysiber bysiber commented Feb 20, 2026

Summary

InfinityType and NegativeInfinityType give incorrect results when compared to themselves.

Problem

Four comparison operators return wrong values for self-comparison:

Expression Current Expected
Infinity <= Infinity False True
Infinity > Infinity True False
NegativeInfinity < NegativeInfinity True False
NegativeInfinity >= NegativeInfinity False True

These are singletons, so while self-comparison is an edge case, the operators should still be mathematically consistent. Currently __le__ returns False unconditionally for InfinityType, and __gt__ returns True unconditionally — neither accounts for self-comparison. The same pattern affects NegativeInfinityType for __lt__ and __ge__.

Note that __eq__ already handles this correctly using isinstance(other, self.__class__).

Fix

Apply the same isinstance pattern to the four affected operators:

  • InfinityType.__le__: return isinstance(other, self.__class__)
  • InfinityType.__gt__: return not isinstance(other, self.__class__)
  • NegativeInfinityType.__lt__: return not isinstance(other, self.__class__)
  • NegativeInfinityType.__ge__: return isinstance(other, self.__class__)

All other comparisons (cross-type, with regular values) remain unchanged.

@notatallshaw
Copy link
Member

These are internal data structures. Provide a real public facing issue this creates. Also you must include tests that show the behavioral difference.

@bysiber
Copy link
Author

bysiber commented Feb 20, 2026

Fair point, through normal version comparison these are wrapped in tuples, and tuple <= uses == equality first, so the broken operators are never reached in practice.

That said, the operators are still mathematically wrong on their own: Infinity <= Infinity returns False and Infinity > Infinity returns True. Any code that directly compares these (e.g. custom key manipulation, or future internal use) would hit incorrect results.

I've added self-comparison tests covering all four operators for both types. Happy to close this if you feel it's not worth the change though.

@notatallshaw
Copy link
Member

But calls to isinstance are significantly more expeensive, if we never hit this code path so the solution is only for hypotheticals I'd prefer we raise NotImplemented.

@bysiber
Copy link
Author

bysiber commented Feb 20, 2026

Good point about the cost. I can swap the isinstance checks for other is self since Infinity and NegativeInfinity are singletons that's basically free. Would that work for you, or would you rather just close this entirely?

@notatallshaw
Copy link
Member

Good point about the cost. I can swap the isinstance checks for other is self since Infinity and NegativeInfinity are singletons — that's basically free. Would that work for you, or would you rather just close this entirely?

That would be better, I won't be able to review this any time soon though as I'd need to understand where and how this is being used. I'm not against it though, with these fixes.

@henryiii
Copy link
Contributor

It would be nice to have these be a little more correct, just in case they are used someday elsewhere, as long as it's not slower, so I'd be for it.

@bysiber
Copy link
Author

bysiber commented Feb 21, 2026

Updated to use other is self / other is not self instead of isinstance. Since both types are singletons with @typing.final, identity comparison is essentially free and still correct.

InfinityType.__le__ unconditionally returns False and __gt__
unconditionally returns True, which gives wrong results for
self-comparison: Infinity <= Infinity returns False (should be
True) and Infinity > Infinity returns True (should be False).

The same issue exists for NegativeInfinityType where __lt__ always
returns True and __ge__ always returns False, making
NegativeInfinity < NegativeInfinity return True and
NegativeInfinity >= NegativeInfinity return False.

Fix by checking isinstance for these four operators, consistent
with how __eq__ is already implemented.
Since Infinity and NegativeInfinity are singletons, 'other is self'
is both cheaper and more correct than isinstance checks.
@henryiii henryiii force-pushed the fix/infinity-self-comparison branch from 96fcad5 to b090b04 Compare February 24, 2026 03:08
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.

3 participants