8000 bpo-37685: Fixed __eq__, __lt__ etc implementations in some classes. by serhiy-storchaka · Pull Request #14952 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-37685: Fixed __eq__, __lt__ etc implementations in some classes. #14952

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

Merged
merged 8 commits into from
Aug 8, 2019

Conversation

serhiy-storchaka
Copy link
Member
@serhiy-storchaka serhiy-storchaka commented Jul 25, 2019

They now return NotImplemented for unsupported type of the other operand.

https://bugs.python.org/issue37685

They now return NotImplemented for unsupported type of the other operand.
Copy link
Contributor
@aeros aeros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this PR. Simply returning False when an equality comparison is not supported can be quite misleading. The usage of the NotImplemeted constant is far more explicit.

Copy link
Member
@pganssle pganssle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should probably not backport this all the way to 3.7 because it changes the semantics of comparisons (albeit in a good way).

If there is some subset of the changes that either just brings the C and Python implementations into agreement or fixes something that is much more obviously a bug, I think maybe we can split this into two PRs - one to be backported and one for 3.9 (and maybe 3.8 - I don't know the rules on that one, but from a practical purpose I think people treat 3.8 as sufficiently unstable that it's fine).

@@ -16,6 +16,7 @@
import re
import struct
import unittest
from unittest.mock import ANY
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a dedicated class for this in datetimetester.py to avoid relying on the implementation details of ANY.

I think we can move it into tests.support if you are going to be adding tests like this across multiple modules.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think we need yet one ANY in private tests.support if we can use public unittest.mock.ANY.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unittest.mock.ANY only accidentally has the property that it compares equal to things. Even if that were a guaranteed property (it probably won't change, but it's an implementation detail), it's still confusing to see people using the "wild card for arguments" singleton from unittest.mock for one of its incidental properties (comparing equal to things).

If someone tried to understand this test and looked it up in the documentation, they would be confused as to what it means. I think it is much clearer to use a dedicated class for this (particularly since we already have one in the datetime tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That class was added 15 days ago. Perhaps the author was not aware of mock.ANY. There are explicit tests for this property of mock.ANY, it is not incidental.

It is not very difficult to add a duplicate in test.support, but I am not sure that it is worth.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are explicit tests for this property of mock.ANY, it is not incidental.

I don't know about that, people test implementation details all the time.

That class was added 15 days ago. Perhaps the author was not aware of mock.ANY.

Definitely they were. The original PR used mock.ANY and I asked for it to be replaced with a dedicated class. You can see my comment on the original PR.

If you look at the documentation for ANY, it is clearly documented as a wild card to be used for making assertions about some calls to a function but not others. Nothing in the documentation says that it is implemented with a permissive __eq__, and in fact a permissive __eq__ is not always sufficient, as we learned in #14700. The ANY class does have the property you want, but it's a dedicated singleton with a semantic meaning other than "this compares equal to anything".

For reasons of clarity, I think it makes sense to have dedicated singletons for each of the custom comparison behaviors, even if there are other objects that also have those properties for their own reasons.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change has been extracted into #14996. Please take a look.

Lib/datetime.py Outdated
@@ -739,25 +739,25 @@ def __le__(self, other):
if isinstance(other, timedelta):
return self._cmp(other) <= 0
else:
_cmperror(self, other)
return NotImplemented
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, we recently changed these and I guess I just assumed that _cmperror returned NotImplemented.

I agree with this change, but I would argue that it precludes backporting to 3.7 (and possibly 3.8), because it is a pretty significant change to the semantics of the language.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change fixes a discrepancy between Python and C implementations. Other changes are discussable, but this change is a bugfix and it should be backported.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if that is the case, I agree about backporting the subset of these changes that fixes discrepancies between the Python and C implementations. We should figure out what that subset is and break it into two PRs - one for backporting and one for master (and maybe 3.8).

@@ -3093,6 +3093,21 @@ def __fspath__(self):
return self.path


@functools.total_ordering
class LargestObject:
Copy link
Member
@pganssle pganssle Jul 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about making these singletons?

LargestObject = LargestObject() and SmallestObject = SmallestObject().

I don't think anyone needs to subclass these and there's no need to instantiate more than one of them.

Similarly we can move ComparesEqualClass into this module and make it a singleton.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.

@bedevere-bot
Copy link

When you're done making the requested changes, leave the comment: I have made the requested changes; please review again.

@brettcannon
Copy link
Member

I agree that this probably shouldn't be backported as it's a shift in semantics.

@aeros
Copy link
Contributor
aeros commented Jul 26, 2019

I agree that this probably shouldn't be backported as it's a shift in semantics.

Would a backport to 3.8 still be appropriate since that branch is still in pre-release or should it exclusively be merged to 3.9?

@brettcannon
Copy link
Member

@aeros167 it's up to Serhiy and ultimately Lukasz as release manager, but beta is open to bugfixes, just not enhancements.

@serhiy-storchaka serhiy-storchaka merged commit 662db12 into python:master Aug 8, 2019
@serhiy-storchaka serhiy-storchaka deleted the eq-notimplemented branch August 8, 2019 05:42
lisroach pushed a commit to lisroach/cpython that referenced this pull request Sep 10, 2019
…ythonGH-14952)

They now return NotImplemented for unsupported type of the other operand.
@miss-islington
Copy link
Contributor

Thanks @serhiy-storchaka for the PR 🌮🎉.. I'm working now to backport this PR to: 3.8.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Sorry, @serhiy-storchaka, I could not cleanly backport this to 3.8 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 662db125cddbca1db68116c547c290eb3943d98e 3.8

serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this pull request Jan 5, 2020
…sses. (pythonGH-14952)

They now return NotImplemented for unsupported type of the other operand..
(cherry picked from commit 662db12)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
@bedevere-bot
Copy link

GH-17836 is a backport of this pull request to the 3.8 branch.

DinoV pushed a commit to DinoV/cpython that referenced this pull request Jan 14, 2020
…ythonGH-14952)

They now return NotImplemented for unsupported type of the other operand.
websurfer5 pushed a commit to websurfer5/cpython that referenced this pull request Jul 20, 2020
…ythonGH-14952)

They now return NotImplemented for unsupported type of the other operand.
@serhiy-storchaka serhiy-storchaka removed their assignment Dec 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
4BF2
None yet
Development

Successfully merging this pull request may close these issues.

7 participants
0