55import sys
66import zipp
77import email
8+ import inspect
89import pathlib
910import operator
1011import textwrap
1415import posixpath
1516import contextlib
1617import collections
17- import inspect
1818
1919from . import _adapters , _meta , _py39compat
2020from ._collections import FreezableDefaultDict , Pair
2121from ._compat import (
2222 NullFinder ,
23+ StrPath ,
2324 install ,
2425 pypy_partial ,
2526)
3132from importlib import import_module
3233from importlib .abc import MetaPathFinder
3334from itertools import starmap
34- from typing import List , Mapping , Optional , cast
35-
35+ from typing import Iterable , List , Mapping , Optional , Set , cast
3636
3737__all__ = [
3838 'Distribution' ,
5353class PackageNotFoundError (ModuleNotFoundError ):
5454 """The package was not found."""
5555
56- def __str__ (self ):
56+ def __str__ (self ) -> str :
5757 return f"No package metadata was found for { self .name } "
5858
5959 @property
60- def name (self ):
60+ def name (self ) -> str : # type: ignore[override]
6161 (name ,) = self .args
6262 return name
6363
@@ -123,7 +123,7 @@ def read(text, filter_=None):
123123 yield Pair (name , value )
124124
125125 @staticmethod
126- def valid (line ):
126+ def valid (line : str ):
127127 return line and not line .startswith ('#' )
128128
129129
@@ -198,7 +198,7 @@ class EntryPoint(DeprecatedTuple):
198198
199199 dist : Optional ['Distribution' ] = None
200200
201- def __init__ (self , name , value , group ) :
201+ def __init__ (self , name : str , value : str , group : str ) -> None :
202202 vars (self ).update (name = name , value = value , group = group )
203203
204204 def load (self ):
@@ -212,18 +212,21 @@ def load(self):
212212 return functools .reduce (getattr , attrs , module )
213213
214214 @property
215- def module (self ):
215+ def module (self ) -> str :
216216 match = self .pattern .match (self .value )
217+ assert match is not None
217218 return match .group ('module' )
218219
219220 @property
220- def attr (self ):
221+ def attr (self ) -> str :
221222 match = self .pattern .match (self .value )
223+ assert match is not None
222224 return match .group ('attr' )
223225
224226 @property
225- def extras (self ):
227+ def extras (self ) -> List [ str ] :
226228 match = self .pattern .match (self .value )
229+ assert match is not None
227230 return re .findall (r'\w+' , match .group ('extras' ) or '' )
228231
229232 def _for (self , dist ):
@@ -271,7 +274,7 @@ def __repr__(self):
271274 f'group={ self .group !r} )'
272275 )
273276
274- def __hash__ (self ):
277+ def __hash__ (self ) -> int :
275278 return hash (self ._key ())
276279
277280
@@ -282,7 +285,7 @@ class EntryPoints(tuple):
282285
283286 __slots__ = ()
284287
285- def __getitem__ (self , name ): # -> EntryPoint:
288+ def __getitem__ (self , name : str ) -> EntryPoint : # type: ignore[override]
286289 """
287290 Get the EntryPoint in self matching name.
288291 """
@@ -299,14 +302,14 @@ def select(self, **params):
299302 return EntryPoints (ep for ep in self if _py39compat .ep_matches (ep , ** params ))
300303
301304 @property
302- def names (self ):
305+ def names (self ) -> Set [ str ] :
303306 """
304307 Return the set of all names of all entry points.
305308 """
306309 return {ep .name for ep in self }
307310
308311 @property
309- def groups (self ):
312+ def groups (self ) -> Set [ str ] :
310313 """
311314 Return the set of all groups of all entry points.
312315 """
@@ -327,24 +330,28 @@ def _from_text(text):
327330class PackagePath (pathlib .PurePosixPath ):
328331 """A reference to a path in a package"""
329332
330- def read_text (self , encoding = 'utf-8' ):
333+ hash : Optional ["FileHash" ]
334+ size : int
335+ dist : "Distribution"
336+
337+ def read_text (self , encoding : str = 'utf-8' ) -> str : # type: ignore[override]
331338 with self .locate ().open (encoding = encoding ) as stream :
332339 return stream .read ()
333340
334- def read_binary (self ):
341+ def read_binary (self ) -> bytes :
335342 with self .locate ().open ('rb' ) as stream :
336343 return stream .read ()
337344
338- def locate (self ):
345+ def locate (self ) -> pathlib . Path :
339346 """Return a path-like object for this path"""
340347 return self .dist .locate_file (self )
341348
342349
343350class FileHash :
344- def __init__ (self , spec ) :
351+ def __init__ (self , spec : str ) -> None :
345352 self .mode , _ , self .value = spec .partition ('=' )
346353
347- def __repr__ (self ):
354+ def __repr__ (self ) -> str :
348355 return f'<FileHash mode: { self .mode } value: { self .value } >'
349356
350357
@@ -379,14 +386,14 @@ def read_text(self, filename) -> Optional[str]:
379386 """
380387
381388 @abc .abstractmethod
382- def locate_file (self , path ) :
389+ def locate_file (self , path : StrPath ) -> pathlib . Path :
383390 """
384391 Given a path to a file in this distribution, return a path
385392 to it.
386393 """
387394
388395 @classmethod
389- def from_name (cls , name : str ):
396+ def from_name (cls , name : str ) -> "Distribution" :
390397 """Return the Distribution for the given package name.
391398
392399 :param name: The name of the distribution package to search for.
@@ -399,12 +406,12 @@ def from_name(cls, name: str):
399406 if not name :
400407 raise ValueError ("A distribution name is required." )
401408 try :
402- return next (cls .discover (name = name ))
409+ return next (iter ( cls .discover (name = name ) ))
403410 except StopIteration :
404411 raise PackageNotFoundError (name )
405412
406413 @classmethod
407- def discover (cls , ** kwargs ):
414+ def discover (cls , ** kwargs ) -> Iterable [ "Distribution" ] :
408415 """Return an iterable of Distribution objects for all packages.
409416
410417 Pass a ``context`` or pass keyword arguments for constructing
@@ -422,7 +429,7 @@ def discover(cls, **kwargs):
422429 )
423430
424431 @staticmethod
425- def at (path ) :
432+ def at (path : StrPath ) -> "Distribution" :
426433 """Return a Distribution for the indicated metadata path
427434
428435 :param path: a string or path-like object
@@ -457,7 +464,7 @@ def metadata(self) -> _meta.PackageMetadata:
457464 return _adapters .Message (email .message_from_string (text ))
458465
459466 @property
460- def name (self ):
467+ def name (self ) -> str :
461468 """Return the 'Name' metadata for the distribution package."""
462469 return self .metadata ['Name' ]
463470
@@ -467,16 +474,16 @@ def _normalized_name(self):
467474 return Prepared .normalize (self .name )
468475
469476 @property
470- def version (self ):
477+ def version (self ) -> str :
471478 """Return the 'Version' metadata for the distribution package."""
472479 return self .metadata ['Version' ]
473480
474481 @property
475- def entry_points (self ):
482+ def entry_points (self ) -> EntryPoints :
476483 return EntryPoints ._from_text_for (self .read_text ('entry_points.txt' ), self )
477484
478485 @property
479- def files (self ):
486+ def files (self ) -> Optional [ List [ PackagePath ]] :
480487 """Files in this distribution.
481488
482489 :return: List of PackagePath for this distribution or None
@@ -561,7 +568,7 @@ def _read_files_egginfo_sources(self):
561568 return text and map ('"{}"' .format , text .splitlines ())
562569
563570 @property
564- def requires (self ):
571+ def requires (self ) -> Optional [ List [ str ]] :
565572 """Generated requirements specified for this Distribution"""
566573 reqs = self ._read_dist_info_reqs () or self ._read_egg_info_reqs ()
567574 return reqs and list (reqs )
@@ -640,7 +647,7 @@ def __init__(self, **kwargs):
640647 vars (self ).update (kwargs )
641648
642649 @property
643- def path (self ):
650+ def path (self ) -> List [ str ] :
644651 """
645652 The sequence of directory path that a distribution finder
646653 should search.
@@ -651,7 +658,7 @@ def path(self):
651658 return vars (self ).get ('path' , sys .path )
652659
653660 @abc .abstractmethod
654- def find_distributions (self , context = Context ()):
661+ def find_distributions (self , context = Context ()) -> Iterable [ Distribution ] :
655662 """
656663 Find distributions.
657664
@@ -786,7 +793,9 @@ class MetadataPathFinder(NullFinder, DistributionFinder):
786793 of Python that do not have a PathFinder find_distributions().
787794 """
788795
789- def find_distributions (self , context = DistributionFinder .Context ()):
796+ def find_distributions (
797+ self , context = DistributionFinder .Context ()
798+ ) -> Iterable ["PathDistribution" ]:
790799 """
791800 Find distributions.
792801
@@ -806,19 +815,19 @@ def _search_paths(cls, name, paths):
806815 path .search (prepared ) for path in map (FastPath , paths )
807816 )
808817
809- def invalidate_caches (cls ):
818+ def invalidate_caches (cls ) -> None :
810819 FastPath .__new__ .cache_clear ()
811820
812821
813822class PathDistribution (Distribution ):
814- def __init__ (self , path : SimplePath ):
823+ def __init__ (self , path : SimplePath ) -> None :
815824 """Construct a distribution.
816825
817826 :param path: SimplePath indicating the metadata directory.
818827 """
819828 self ._path = path
820829
821- def read_text (self , filename ) :
830+ def read_text (self , filename : StrPath ) -> Optional [ str ] :
822831 with suppress (
823832 FileNotFoundError ,
824833 IsADirectoryError ,
@@ -828,9 +837,11 @@ def read_text(self, filename):
828837 ):
829838 return self ._path .joinpath (filename ).read_text (encoding = 'utf-8' )
830839
840+ return None
841+
831842 read_text .__doc__ = Distribution .read_text .__doc__
832843
833- def locate_file (self , path ) :
844+ def locate_file (self , path : StrPath ) -> pathlib . Path :
834845 return self ._path .parent / path
835846
836847 @property
@@ -863,7 +874,7 @@ def _name_from_stem(stem):
863874 return name
864875
865876
866- def distribution (distribution_name ):
877+ def distribution (distribution_name ) -> Distribution :
867878 """Get the ``Distribution`` instance for the named package.
868879
869880 :param distribution_name: The name of the distribution package as a string.
@@ -872,7 +883,7 @@ def distribution(distribution_name):
872883 return Distribution .from_name (distribution_name )
873884
874885
875- def distributions (** kwargs ):
886+ def distributions (** kwargs ) -> Iterable [ Distribution ] :
876887 """Get all ``Distribution`` instances in the current environment.
877888
878889 :return: An iterable of ``Distribution`` instances.
@@ -889,7 +900,7 @@ def metadata(distribution_name) -> _meta.PackageMetadata:
889900 return Distribution .from_name (distribution_name ).metadata
890901
891902
892- def version (distribution_name ):
903+ def version (distribution_name ) -> str :
893904 """Get the version string for the named package.
894905
895906 :param distribution_name: The name of the distribution package to query.
@@ -923,7 +934,7 @@ def entry_points(**params) -> EntryPoints:
923934 return EntryPoints (eps ).select (** params )
924935
925936
926- def files (distribution_name ):
937+ def files (distribution_name ) -> Optional [ List [ PackagePath ]] :
927938 """Return a list of files for the named package.
928939
929940 :param distribution_name: The name of the distribution package to query.
@@ -932,11 +943,11 @@ def files(distribution_name):
932943 return distribution (distribution_name ).files
933944
934945
935- def requires (distribution_name ):
946+ def requires (distribution_name ) -> Optional [ List [ str ]] :
936947 """
937948 Return a list of requirements for the named package.
938949
939- :return: An iterator of requirements, suitable for
950+ :return: An iterable of requirements, suitable for
940951 packaging.requirement.Requirement.
941952 """
942953 return distribution (distribution_name ).requires
0 commit comments