1
- from typing import Any
1
+ from typing import Any , Optional
2
2
3
3
from pip ._vendor .packaging .specifiers import SpecifierSet
4
4
from pip ._vendor .packaging .utils import NormalizedName , canonicalize_name
@@ -51,8 +51,18 @@ class SpecifierRequirement(Requirement):
51
51
def __init__ (self , ireq : InstallRequirement ) -> None :
52
52
assert ireq .link is None , "This is a link, not a specifier"
53
53
self ._ireq = ireq
54
+ self ._equal_cache : Optional [str ] = None
55
+ self ._hash : Optional [int ] = None
54
56
self ._extras = frozenset (canonicalize_name (e ) for e in self ._ireq .extras )
55
57
58
+ @property
59
+ def _equal (self ) -> str :
60
+ if self ._equal_cache is not None :
61
+ return self ._equal_cache
62
+
63
+ self ._equal_cache = str (self ._ireq )
64
+ return self ._equal_cache
65
+
56
66
def __str__ (self ) -> str :
57
67
return str (self ._ireq .req )
58
68
@@ -62,10 +72,14 @@ def __repr__(self) -> str:
62
72
def __eq__ (self , other : object ) -> bool :
63
73
if not isinstance (other , SpecifierRequirement ):
64
74
return NotImplemented
65
- return str ( self ._ireq ) == str ( other ._ireq )
75
+ return self ._equal == other ._equal
66
76
67
77
def __hash__ (self ) -> int :
68
- return hash (str (self ._ireq ))
78
+ if self ._hash is not None :
79
+ return self ._hash
80
+
81
+ self ._hash = hash (self ._equal )
82
+ return self ._hash
69
83
70
84
@property
71
85
def project_name (self ) -> NormalizedName :
@@ -114,15 +128,29 @@ class SpecifierWithoutExtrasRequirement(SpecifierRequirement):
114
128
def __init__ (self , ireq : InstallRequirement ) -> None :
115
129
assert ireq .link is None , "This is a link, not a specifier"
116
130
self ._ireq = install_req_drop_extras (ireq )
131
+ self ._equal_cache : Optional [str ] = None
132
+ self ._hash : Optional [int ] = None
117
133
self ._extras = frozenset (canonicalize_name (e ) for e in self ._ireq .extras )
118
134
135
+ @property
136
+ def _equal (self ) -> str :
137
+ if self ._equal_cache is not None :
138
+ return self ._equal_cache
139
+
140
+ self ._equal_cache = str (self ._ireq )
141
+ return self ._equal_cache
142
+
119
143
def __eq__ (self , other : object ) -> bool :
120
144
if not isinstance (other , SpecifierWithoutExtrasRequirement ):
121
145
return NotImplemented
122
- return str ( self ._ireq ) == str ( other ._ireq )
146
+ return self ._equal == other ._equal
123
147
124
148
def __hash__ (self ) -> int :
125
- return hash (str (self ._ireq ))
149
+ if self ._hash is not None :
150
+ return self ._hash
151
+
152
+ self ._hash = hash (self ._equal )
153
+ return self ._hash
126
154
127
155
128
156
class RequiresPythonRequirement (Requirement ):
@@ -131,6 +159,7 @@ class RequiresPythonRequirement(Requirement):
131
159
def __init__ (self , specifier : SpecifierSet , match : Candidate ) -> None :
132
160
self .specifier = specifier
133
161
self ._specifier_string = str (specifier ) # for faster __eq__
162
+ self ._hash : Optional [int ] = None
134
163
self ._candidate = match
135
164
136
165
def __str__ (self ) -> str :
@@ -140,7 +169,11 @@ def __repr__(self) -> str:
140
169
return f"{ self .__class__ .__name__ } ({ str (self .specifier )!r} )"
141
170
142
171
def __hash__ (self ) -> int :
143
- return hash ((self ._specifier_string , self ._candidate ))
172
+ if self ._hash is not None :
173
+ return self ._hash
174
+
175
+ self ._hash = hash ((self ._specifier_string , self ._candidate ))
176
+ return self ._hash
144
177
145
178
def __eq__ (self , other : Any ) -> bool :
146
179
if not isinstance (other , RequiresPythonRequirement ):
0 commit comments