@@ -136,8 +136,6 @@ class _EntryPointMatch(types.SimpleNamespace):
136136 extras : str
137137
138138
139- from typing import Optional , List , cast , Match
140-
141139class EntryPoint :
142140 """An entry point as defined by Python packaging conventions.
143141
@@ -204,38 +202,44 @@ class EntryPoint:
204202 value : str
205203 group : str
206204
207- dist : Optional [ Distribution ] = None
205+ dist : Distribution | None = None
208206
209207 def __init__ (self , name : str , value : str , group : str ) -> None :
210208 vars (self ).update (name = name , value = value , group = group )
209+ self .module
211210
212211 def load (self ) -> Any :
213212 """Load the entry point from its definition. If only a module
214213 is indicated by the value, return that module. Otherwise,
215214 return the named object.
216215 """
217- match = cast (Match , self .pattern .match (self .value ))
218- module = import_module (match .group ('module' ))
219- attrs = filter (None , (match .group ('attr' ) or '' ).split ('.' ))
216+ module = import_module (self .module )
217+ attrs = filter (None , (self .attr or '' ).split ('.' ))
220218 return functools .reduce (getattr , attrs , module )
221219
222220 @property
223221 def module (self ) -> str :
224- match = self .pattern .match (self .value )
225- assert match is not None
226- return match .group ('module' )
222+ return self ._match .module
227223
228224 @property
229225 def attr (self ) -> str :
230- match = self .pattern .match (self .value )
231- assert match is not None
232- return match .group ('attr' )
226+ return self ._match .attr
233227
234228 @property
235- def extras (self ) -> List [str ]:
229+ def extras (self ) -> list [str ]:
230+ return re .findall (r'\w+' , self ._match .extras or '' )
231+
232+ @functools .cached_property
233+ def _match (self ) -> _EntryPointMatch :
236234 match = self .pattern .match (self .value )
237- assert match is not None
238- return re .findall (r'\w+' , match .group ('extras' ) or '' )
235+ if not match :
236+ raise ValueError (
237+ 'Invalid object reference. '
238+ 'See https://packaging.python.org'
239+ '/en/latest/specifications/entry-points/#data-model' ,
240+ self .value ,
241+ )
242+ return _EntryPointMatch (** match .groupdict ())
239243
240244 def _for (self , dist ):
241245 vars (self ).update (dist = dist )
@@ -261,9 +265,26 @@ def matches(self, **params):
261265 >>> ep.matches(attr='bong')
262266 True
263267 """
268+ self ._disallow_dist (params )
264269 attrs = (getattr (self , param ) for param in params )
265270 return all (map (operator .eq , params .values (), attrs ))
266271
272+ @staticmethod
273+ def _disallow_dist (params ):
274+ """
275+ Querying by dist is not allowed (dist objects are not comparable).
276+ >>> EntryPoint(name='fan', value='fav', group='fag').matches(dist='foo')
277+ Traceback (most recent call last):
278+ ...
279+ ValueError: "dist" is not suitable for matching...
280+ """
281+ if "dist" in params :
282+ raise ValueError (
283+ '"dist" is not suitable for matching. '
284+ "Instead, use Distribution.entry_points.select() on a "
285+ "located distribution."
286+ )
287+
267288 def _key (self ):
268289 return self .name , self .value , self .group
269290
@@ -1094,7 +1115,7 @@ def packages_distributions() -> Mapping[str, list[str]]:
10941115 pkg_to_dist = collections .defaultdict (list )
10951116 for dist in distributions ():
10961117 for pkg in _top_level_declared (dist ) or _top_level_inferred (dist ):
1097- pkg_to_dist [pkg ].append (dist .metadata ['Name' ])
1118+ pkg_to_dist [pkg ].append (md_none ( dist .metadata ) ['Name' ])
10981119 return dict (pkg_to_dist )
10991120
11001121
0 commit comments