-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Use dataclasses more liberally throughout the codebase #12571
Conversation
Unfortunately due to dataclasses' poor handling of slots under 3.10, converting the class to a dataclass is not an option. I would get these errors which would be nontrivial to work around. ValueError: '_hashes' in __slots__ conflicts with class variable However, this is the last use of KeyBasedCompareMixin so after this commit, it can be removed entirely!
I left ArchiveInfo alone as it has some non-trivial attribute logic that I would rather not touch.
And drop a test that's now raising type errors as HiddenText can no longer be compared with strings.
@dataclass | ||
class VcsInfo: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opted to leave the direct_url classes non-frozen as some tests broke and it would be more consistent with ArchiveInfo
which I did not convert (due to non-trivial logic I didn't feel like groking).
@@ -217,7 +218,7 @@ def resolve_revision( | |||
|
|||
if sha is not None: | |||
rev_options = rev_options.make_new(sha) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RevOptions.make_new()
seems like unnecessary boilerplate, but I've opted to leave additional (potential) refactoring to another PR.
@dataclass | ||
class CandidatePreferences: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The codebase does assign to these attributes from time to time...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sigh
src/pip/_internal/models/scheme.py
Outdated
|
||
SCHEME_KEYS = ["platlib", "purelib", "headers", "scripts", "data"] | ||
|
||
|
||
@dataclass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can we not freeze this class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pip/src/pip/_internal/locations/_sysconfig.py
Lines 194 to 197 in 31437d6
if root is not None: | |
for key in SCHEME_KEYS: | |
value = change_root(root, getattr(scheme, key)) | |
setattr(scheme, key, value) |
Although this is trivial to fix... so I did that in 3738d25. Hopefully it doesn't break the test suite.
tests/unit/test_utils.py
Outdated
@@ -802,20 +802,6 @@ def test_basic(self) -> None: | |||
assert hidden.redacted == "######" | |||
assert hidden.secret == "my-secret" | |||
|
|||
def test_equality_with_str(self) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I think this test should have been preserved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comparisons in this test are no longer type-safe which is why I removed it. I can adjust the class to support comparisons with strings if that's wanted.
mypy.....................................................................Failed
- hook id: mypy
- exit code: 1
tests/unit/test_utils.py:813: error: Non-overlapping equality check (left
operand type: "HiddenText", right operand type: "str") [comparison-overlap]
assert hidden != hidden.secret
^~~~~~~~~~~~~~~~~~~~~~~
tests/unit/test_utils.py:814: error: Non-overlapping equality check (left
operand type: "str", right operand type: "HiddenText") [comparison-overlap]
assert hidden.secret != hidden
^~~~~~~~~~~~~~~~~~~~~~~
tests/unit/test_utils.py:816: error: Non-overlapping equality check (left
operand type: "HiddenText", right operand type: "str") [comparison-overlap]
assert hidden != hidden.redacted
^~~~~~~~~~~~~~~~~~~~~~~~~
tests/unit/test_utils.py:817: error: Non-overlapping equality check (left
operand type: "str", right operand type: "HiddenText") [comparison-overlap]
assert hidden.redacted != hidden
^~~~~~~~~~~~~~~~~~~~~~~~~
Found 4 errors in 1 file (checked 292 source files)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because you removed the __eq__
comparison from the HiddenText
class... (Edit: More accurately, because the equality implementation added by the dataclass code doesn't have the same type signature as the one it replaced).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem like the class was meant to be compared with strings in the first place (other than in tests) so it's debatable whether it's worth keeping it, but I've rolled this back in bde667d anyway.
pip/src/pip/_internal/utils/misc.py
Lines 594 to 601 in 31437d6
# This is useful for testing. | |
def __eq__(self, other: Any) -> bool: | |
if type(self) != type(other): | |
return False | |
# The string being used for redaction doesn't also have to match, | |
# just the raw, original string. | |
return self.secret == other.secret |
Edit: I've talked to some people more knowledgeable in typing than me and IIUC these type errors shouldn't be raised in the first place... Sometimes, I hate typing ¯\_(ツ)_/¯
Conflicts have been resolved. |
This seemed like an easy refactoring. Please let me know if any/all of these conversions should be dropped.