3434import types
3535from typing import (
3636 Any ,
37+ Dict ,
38+ Iterator ,
3739 Mapping ,
3840 MutableSequence ,
3941 NamedTuple ,
4547 Callable ,
4648 Iterable ,
4749 TypeVar ,
48- Optional ,
49- Dict ,
5050 overload ,
5151)
5252import zipfile
9898from pkg_resources .extern .platformdirs import user_cache_dir as _user_cache_dir
9999
100100if TYPE_CHECKING :
101+ from typing_extensions import Self
101102 from _typeshed import StrPath , StrOrBytesPath , BytesPath
102103
103104warnings .warn (
111112_T = TypeVar ("_T" )
112113# Type aliases
113114_NestedStr = Union [str , Iterable [Union [str , Iterable ["_NestedStr" ]]]]
114- _InstallerType = Callable [["Requirement" ], Optional ["Distribution" ]]
115+ _InstallerType = Callable [["Requirement" ], Union ["Distribution" , None ]]
115116_PkgReqType = Union [str , "Requirement" ]
116117_EPDistType = Union ["Distribution" , _PkgReqType ]
117- _MetadataType = Optional ["IResourceProvider" ]
118+ _MetadataType = Union ["IResourceProvider" , None ]
118119# Any object works, but let's indicate we expect something like a module (optionally has __loader__ or __file__)
119120_ModuleLike = Union [object , types .ModuleType ]
120121_ProviderFactoryType = Callable [[_ModuleLike ], "IResourceProvider" ]
121122_DistFinderType = Callable [[_T , str , bool ], Iterable ["Distribution" ]]
122- _NSHandlerType = Callable [[_T , str , str , types .ModuleType ], Optional [str ]]
123+ _NSHandlerType = Callable [[_T , str , str , types .ModuleType ], Union [str , None ]]
123124_AdapterT = TypeVar (
124125 "_AdapterT" , _DistFinderType [Any ], _ProviderFactoryType , _NSHandlerType [Any ]
125126)
@@ -151,15 +152,15 @@ def _declare_state(vartype: str, varname: str, initial_value: _T) -> _T:
151152 return initial_value
152153
153154
154- def __getstate__ ():
155+ def __getstate__ () -> dict [ str , Any ] :
155156 state = {}
156157 g = globals ()
157158 for k , v in _state_vars .items ():
158159 state [k ] = g ['_sget_' + v ](g [k ])
159160 return state
160161
161162
162- def __setstate__ (state ) :
163+ def __setstate__ (state : dict [ str , Any ]) -> dict [ str , Any ] :
163164 g = globals ()
164165 for k , v in state .items ():
165166 g ['_sset_' + _state_vars [k ]](k , g [k ], v )
@@ -314,11 +315,11 @@ class VersionConflict(ResolutionError):
314315 _template = "{self.dist} is installed but {self.req} is required"
315316
316317 @property
317- def dist (self ):
318+ def dist (self ) -> Distribution :
318319 return self .args [0 ]
319320
320321 @property
321- def req (self ):
322+ def req (self ) -> Requirement :
322323 return self .args [1 ]
323324
324325 def report (self ):
@@ -344,7 +345,7 @@ class ContextualVersionConflict(VersionConflict):
344345 _template = VersionConflict ._template + ' by {self.required_by}'
345346
346347 @property
347- def required_by (self ):
348+ def required_by (self ) -> set [ str ] :
348349 return self .args [2 ]
349350
350351
@@ -357,11 +358,11 @@ class DistributionNotFound(ResolutionError):
357358 )
358359
359360 @property
360- def req (self ):
361+ def req (self ) -> Requirement :
361362 return self .args [0 ]
362363
363364 @property
364- def requirers (self ):
365+ def requirers (self ) -> set [ str ] | None :
365366 return self .args [1 ]
366367
367368 @property
@@ -667,11 +668,11 @@ def add_entry(self, entry: str):
667668 for dist in find_distributions (entry , True ):
668669 self .add (dist , entry , False )
669670
670- def __contains__ (self , dist : Distribution ):
671+ def __contains__ (self , dist : Distribution ) -> bool :
671672 """True if `dist` is the active distribution for its project"""
672673 return self .by_key .get (dist .key ) == dist
673674
674- def find (self , req : Requirement ):
675+ def find (self , req : Requirement ) -> Distribution | None :
675676 """Find a distribution matching requirement `req`
676677
677678 If there is an active distribution for the requested project, this
@@ -717,7 +718,7 @@ def run_script(self, requires: str, script_name: str):
717718 ns ['__name__' ] = name
718719 self .require (requires )[0 ].run_script (script_name , ns )
719720
720- def __iter__ (self ):
721+ def __iter__ (self ) -> Iterator [ Distribution ] :
721722 """Yield distributions for non-duplicate projects in the working set
722723
723724 The yield order is the order in which the items' path entries were
@@ -1101,7 +1102,7 @@ def scan(self, search_path: Iterable[str] | None = None):
11011102 for dist in find_distributions (item ):
11021103 self .add (dist )
11031104
1104- def __getitem__ (self , project_name : str ):
1105+ def __getitem__ (self , project_name : str ) -> list [ Distribution ] :
11051106 """Return a newest-to-oldest list of distributions for `project_name`
11061107
11071108 Uses case-insensitive `project_name` comparison, assuming all the
@@ -1168,7 +1169,7 @@ def obtain(
11681169 to the `installer` argument."""
11691170 return installer (requirement ) if installer else None
11701171
1171- def __iter__ (self ):
1172+ def __iter__ (self ) -> Iterator [ str ] :
11721173 """Yield the unique project names of the available distributions"""
11731174 for key in self ._distmap .keys ():
11741175 if self [key ]:
@@ -1401,7 +1402,7 @@ def cleanup_resources(self, force: bool = False) -> list[str]:
14011402 return []
14021403
14031404
1404- def get_default_cache ():
1405+ def get_default_cache () -> str :
14051406 """
14061407 Return the ``PYTHON_EGG_CACHE`` environment variable
14071408 or a platform-relevant user cache dir for an app
@@ -1493,7 +1494,7 @@ def invalid_marker(text: str):
14931494 return False
14941495
14951496
1496- def evaluate_marker (text : str , extra : str | None = None ):
1497+ def evaluate_marker (text : str , extra : str | None = None ) -> bool :
14971498 """
14981499 Evaluate a PEP 508 environment marker.
14991500 Return a boolean indicating the marker result in this environment.
@@ -1799,7 +1800,7 @@ class ZipManifests(Dict[str, "MemoizedZipManifests.manifest_mod"]):
17991800 zip manifest builder
18001801 """
18011802
1802- # `path` could be `Union[" StrPath", IO[bytes] ]` but that violates the LSP for `MemoizedZipManifests.load`
1803+ # `path` could be `StrPath | IO[bytes]` but that violates the LSP for `MemoizedZipManifests.load`
18031804 @classmethod
18041805 def build (cls , path : str ):
18051806 """
@@ -1831,7 +1832,7 @@ class manifest_mod(NamedTuple):
18311832 manifest : dict [str , zipfile .ZipInfo ]
18321833 mtime : float
18331834
1834- def load (self , path : str ): # type: ignore[override] # ZipManifests.load is a classmethod
1835+ def load (self , path : str ) -> dict [ str , zipfile . ZipInfo ] : # type: ignore[override] # ZipManifests.load is a classmethod
18351836 """
18361837 Load a manifest at path or return a suitable manifest already loaded.
18371838 """
@@ -2123,7 +2124,7 @@ def find_distributions(path_item: str, only: bool = False):
21232124
21242125def find_eggs_in_zip (
21252126 importer : zipimport .zipimporter , path_item : str , only : bool = False
2126- ):
2127+ ) -> Iterator [ Distribution ] :
21272128 """
21282129 Find eggs in zip files; possibly multiple nested eggs.
21292130 """
@@ -2216,7 +2217,7 @@ def __call__(self, fullpath):
22162217 return iter (())
22172218
22182219
2219- def safe_listdir (path ):
2220+ def safe_listdir (path : StrOrBytesPath ):
22202221 """
22212222 Attempt to list contents of path, but suppress some exceptions.
22222223 """
@@ -2232,13 +2233,13 @@ def safe_listdir(path):
22322233 return ()
22332234
22342235
2235- def distributions_from_metadata (path ):
2236+ def distributions_from_metadata (path : str ):
22362237 root = os .path .dirname (path )
22372238 if os .path .isdir (path ):
22382239 if len (os .listdir (path )) == 0 :
22392240 # empty metadata dir; skip
22402241 return
2241- metadata = PathMetadata (root , path )
2242+ metadata : _MetadataType = PathMetadata (root , path )
22422243 else :
22432244 metadata = FileMetadata (path )
22442245 entry = os .path .basename (path )
@@ -2679,7 +2680,7 @@ def parse_group(
26792680 """Parse an entry point group"""
26802681 if not MODULE (group ):
26812682 raise ValueError ("Invalid group name" , group )
2682- this = {}
2683+ this : dict [ str , Self ] = {}
26832684 for line in yield_lines (lines ):
26842685 ep = cls .parse (line , dist )
26852686 if ep .name in this :
@@ -2694,11 +2695,12 @@ def parse_map(
26942695 dist : Distribution | None = None ,
26952696 ):
26962697 """Parse a map of entry point groups"""
2698+ _data : Iterable [tuple [str | None , str | Iterable [str ]]]
26972699 if isinstance (data , dict ):
26982700 _data = data .items ()
26992701 else :
27002702 _data = split_sections (data )
2701- maps : dict [str , dict [str , EntryPoint ]] = {}
2703+ maps : dict [str , dict [str , Self ]] = {}
27022704 for group , lines in _data :
27032705 if group is None :
27042706 if not lines :
@@ -2757,7 +2759,7 @@ def from_location(
27572759 basename : StrPath ,
27582760 metadata : _MetadataType = None ,
27592761 ** kw : int , # We could set `precedence` explicitly, but keeping this as `**kw` for full backwards and subclassing compatibility
2760- ):
2762+ ) -> Distribution :
27612763 project_name , version , py_version , platform = [None ] * 4
27622764 basename , ext = os .path .splitext (basename )
27632765 if ext .lower () in _distributionImpl :
@@ -2896,14 +2898,14 @@ def _dep_map(self):
28962898 return self .__dep_map
28972899
28982900 @staticmethod
2899- def _filter_extras (dm ):
2901+ def _filter_extras (dm : dict [ str | None , list [ Requirement ]] ):
29002902 """
29012903 Given a mapping of extras to dependencies, strip off
29022904 environment markers and filter out any dependencies
29032905 not matching the markers.
29042906 """
29052907 for extra in list (filter (None , dm )):
2906- new_extra = extra
2908+ new_extra : str | None = extra
29072909 reqs = dm .pop (extra )
29082910 new_extra , _ , marker = extra .partition (':' )
29092911 fails_marker = marker and (
@@ -2926,7 +2928,7 @@ def _build_dep_map(self):
29262928 def requires (self , extras : Iterable [str ] = ()):
29272929 """List of Requirements needed for this distro if `extras` are used"""
29282930 dm = self ._dep_map
2929- deps = []
2931+ deps : list [ Requirement ] = []
29302932 deps .extend (dm .get (None , ()))
29312933 for ext in extras :
29322934 try :
@@ -3223,11 +3225,11 @@ def _dep_map(self):
32233225 self .__dep_map = self ._compute_dependencies ()
32243226 return self .__dep_map
32253227
3226- def _compute_dependencies (self ):
3228+ def _compute_dependencies (self ) -> dict [ str | None , list [ Requirement ]] :
32273229 """Recompute this distribution's dependencies."""
3228- dm = self .__dep_map = {None : []}
3230+ self .__dep_map : dict [ str | None , list [ Requirement ]] = {None : []}
32293231
3230- reqs = []
3232+ reqs : list [ Requirement ] = []
32313233 # Including any condition expressions
32323234 for req in self ._parsed_pkg_info .get_all ('Requires-Dist' ) or []:
32333235 reqs .extend (parse_requirements (req ))
@@ -3238,13 +3240,15 @@ def reqs_for_extra(extra):
32383240 yield req
32393241
32403242 common = types .MappingProxyType (dict .fromkeys (reqs_for_extra (None )))
3241- dm [None ].extend (common )
3243+ self . __dep_map [None ].extend (common )
32423244
32433245 for extra in self ._parsed_pkg_info .get_all ('Provides-Extra' ) or []:
32443246 s_extra = safe_extra (extra .strip ())
3245- dm [s_extra ] = [r for r in reqs_for_extra (extra ) if r not in common ]
3247+ self .__dep_map [s_extra ] = [
3248+ r for r in reqs_for_extra (extra ) if r not in common
3249+ ]
32463250
3247- return dm
3251+ return self . __dep_map
32483252
32493253
32503254_distributionImpl = {
@@ -3305,7 +3309,7 @@ def __eq__(self, other: object):
33053309 def __ne__ (self , other ):
33063310 return not self == other
33073311
3308- def __contains__ (self , item : Distribution | str | tuple [str , ...]):
3312+ def __contains__ (self , item : Distribution | str | tuple [str , ...]) -> bool :
33093313 if isinstance (item , Distribution ):
33103314 if item .key != self .key :
33113315 return False
@@ -3369,7 +3373,7 @@ def _bypass_ensure_directory(path):
33693373 pass
33703374
33713375
3372- def split_sections (s : _NestedStr ):
3376+ def split_sections (s : _NestedStr ) -> Iterator [ tuple [ str | None , list [ str ]]] :
33733377 """Split a string or iterable thereof into (section, content) pairs
33743378
33753379 Each ``section`` is a stripped version of the section header ("[section]")
0 commit comments