5
5
import sys
6
6
import zipp
7
7
import email
8
+ import inspect
8
9
import pathlib
9
10
import operator
10
11
import textwrap
14
15
import posixpath
15
16
import contextlib
16
17
import collections
17
- import inspect
18
18
19
19
from . import _adapters , _meta , _py39compat
20
20
from ._collections import FreezableDefaultDict , Pair
21
21
from ._compat import (
22
22
NullFinder ,
23
+ StrPath ,
23
24
install ,
24
25
pypy_partial ,
25
26
)
31
32
from importlib import import_module
32
33
from importlib .abc import MetaPathFinder
33
34
from itertools import starmap
34
- from typing import List , Mapping , Optional , cast
35
-
35
+ from typing import Iterable , List , Mapping , Optional , Set , cast
36
36
37
37
__all__ = [
38
38
'Distribution' ,
53
53
class PackageNotFoundError (ModuleNotFoundError ):
54
54
"""The package was not found."""
55
55
56
- def __str__ (self ):
56
+ def __str__ (self ) -> str :
57
57
return f"No package metadata was found for { self .name } "
58
58
59
59
@property
60
- def name (self ):
60
+ def name (self ) -> str : # type: ignore[override]
61
61
(name ,) = self .args
62
62
return name
63
63
@@ -123,7 +123,7 @@ def read(text, filter_=None):
123
123
yield Pair (name , value )
124
124
125
125
@staticmethod
126
- def valid (line ):
126
+ def valid (line : str ):
127
127
return line and not line .startswith ('#' )
128
128
129
129
@@ -198,7 +198,7 @@ class EntryPoint(DeprecatedTuple):
198
198
199
199
dist : Optional ['Distribution' ] = None
200
200
201
- def __init__ (self , name , value , group ) :
201
+ def __init__ (self , name : str , value : str , group : str ) -> None :
202
202
vars (self ).update (name = name , value = value , group = group )
203
203
204
204
def load (self ):
@@ -212,18 +212,21 @@ def load(self):
212
212
return functools .reduce (getattr , attrs , module )
213
213
214
214
@property
215
- def module (self ):
215
+ def module (self ) -> str :
216
216
match = self .pattern .match (self .value )
217
+ assert match is not None
217
218
return match .group ('module' )
218
219
219
220
@property
220
- def attr (self ):
221
+ def attr (self ) -> str :
221
222
match = self .pattern .match (self .value )
223
+ assert match is not None
222
224
return match .group ('attr' )
223
225
224
226
@property
225
- def extras (self ):
227
+ def extras (self ) -> List [ str ] :
226
228
match = self .pattern .match (self .value )
229
+ assert match is not None
227
230
return re .findall (r'\w+' , match .group ('extras' ) or '' )
228
231
229
232
def _for (self , dist ):
@@ -271,7 +274,7 @@ def __repr__(self):
271
274
f'group={ self .group !r} )'
272
275
)
273
276
274
- def __hash__ (self ):
277
+ def __hash__ (self ) -> int :
275
278
return hash (self ._key ())
276
279
277
280
@@ -282,7 +285,7 @@ class EntryPoints(tuple):
282
285
283
286
__slots__ = ()
284
287
285
- def __getitem__ (self , name ): # -> EntryPoint:
288
+ def __getitem__ (self , name : str ) -> EntryPoint : # type: ignore[override]
286
289
"""
287
290
Get the EntryPoint in self matching name.
288
291
"""
@@ -299,14 +302,14 @@ def select(self, **params):
299
302
return EntryPoints (ep for ep in self if _py39compat .ep_matches (ep , ** params ))
300
303
301
304
@property
302
- def names (self ):
305
+ def names (self ) -> Set [ str ] :
303
306
"""
304
307
Return the set of all names of all entry points.
305
308
"""
306
309
return {ep .name for ep in self }
307
310
308
311
@property
309
- def groups (self ):
312
+ def groups (self ) -> Set [ str ] :
310
313
"""
311
314
Return the set of all groups of all entry points.
312
315
"""
@@ -327,24 +330,28 @@ def _from_text(text):
327
330
class PackagePath (pathlib .PurePosixPath ):
328
331
"""A reference to a path in a package"""
329
332
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]
331
338
with self .locate ().open (encoding = encoding ) as stream :
332
339
return stream .read ()
333
340
334
- def read_binary (self ):
341
+ def read_binary (self ) -> bytes :
335
342
with self .locate ().open ('rb' ) as stream :
336
343
return stream .read ()
337
344
338
- def locate (self ):
345
+ def locate (self ) -> pathlib . Path :
339
346
"""Return a path-like object for this path"""
340
347
return self .dist .locate_file (self )
341
348
342
349
343
350
class FileHash :
344
- def __init__ (self , spec ) :
351
+ def __init__ (self , spec : str ) -> None :
345
352
self .mode , _ , self .value = spec .partition ('=' )
346
353
347
- def __repr__ (self ):
354
+ def __repr__ (self ) -> str :
348
355
return f'<FileHash mode: { self .mode } value: { self .value } >'
349
356
350
357
@@ -379,14 +386,14 @@ def read_text(self, filename) -> Optional[str]:
379
386
"""
380
387
381
388
@abc .abstractmethod
382
- def locate_file (self , path ) :
389
+ def locate_file (self , path : StrPath ) -> pathlib . Path :
383
390
"""
384
391
Given a path to a file in this distribution, return a path
385
392
to it.
386
393
"""
387
394
388
395
@classmethod
389
- def from_name (cls , name : str ):
396
+ def from_name (cls , name : str ) -> "Distribution" :
390
397
"""Return the Distribution for the given package name.
391
398
392
399
:param name: The name of the distribution package to search for.
@@ -399,12 +406,12 @@ def from_name(cls, name: str):
399
406
if not name :
400
407
raise ValueError ("A distribution name is required." )
401
408
try :
402
- return next (cls .discover (name = name ))
409
+ return next (iter ( cls .discover (name = name ) ))
403
410
except StopIteration :
404
411
raise PackageNotFoundError (name )
405
412
406
413
@classmethod
407
- def discover (cls , ** kwargs ):
414
+ def discover (cls , ** kwargs ) -> Iterable [ "Distribution" ] :
408
415
"""Return an iterable of Distribution objects for all packages.
409
416
410
417
Pass a ``context`` or pass keyword arguments for constructing
@@ -422,7 +429,7 @@ def discover(cls, **kwargs):
422
429
)
423
430
424
431
@staticmethod
425
- def at (path ) :
432
+ def at (path : StrPath ) -> "Distribution" :
426
433
"""Return a Distribution for the indicated metadata path
427
434
428
435
:param path: a string or path-like object
@@ -457,7 +464,7 @@ def metadata(self) -> _meta.PackageMetadata:
457
464
return _adapters .Message (email .message_from_string (text ))
458
465
459
466
@property
460
- def name (self ):
467
+ def name (self ) -> str :
461
468
"""Return the 'Name' metadata for the distribution package."""
462
469
return self .metadata ['Name' ]
463
470
@@ -467,16 +474,16 @@ def _normalized_name(self):
467
474
return Prepared .normalize (self .name )
468
475
469
476
@property
470
- def version (self ):
477
+ def version (self ) -> str :
471
478
"""Return the 'Version' metadata for the distribution package."""
472
479
return self .metadata ['Version' ]
473
480
474
481
@property
475
- def entry_points (self ):
482
+ def entry_points (self ) -> EntryPoints :
476
483
return EntryPoints ._from_text_for (self .read_text ('entry_points.txt' ), self )
477
484
478
485
@property
479
- def files (self ):
486
+ def files (self ) -> Optional [ List [ PackagePath ]] :
480
487
"""Files in this distribution.
481
488
482
489
:return: List of PackagePath for this distribution or None
@@ -561,7 +568,7 @@ def _read_files_egginfo_sources(self):
561
568
return text and map ('"{}"' .format , text .splitlines ())
562
569
563
570
@property
564
- def requires (self ):
571
+ def requires (self ) -> Optional [ List [ str ]] :
565
572
"""Generated requirements specified for this Distribution"""
566
573
reqs = self ._read_dist_info_reqs () or self ._read_egg_info_reqs ()
567
574
return reqs and list (reqs )
@@ -640,7 +647,7 @@ def __init__(self, **kwargs):
640
647
vars (self ).update (kwargs )
641
648
642
649
@property
643
- def path (self ):
650
+ def path (self ) -> List [ str ] :
644
651
"""
645
652
The sequence of directory path that a distribution finder
646
653
should search.
@@ -651,7 +658,7 @@ def path(self):
651
658
return vars (self ).get ('path' , sys .path )
652
659
653
660
@abc .abstractmethod
654
- def find_distributions (self , context = Context ()):
661
+ def find_distributions (self , context = Context ()) -> Iterable [ Distribution ] :
655
662
"""
656
663
Find distributions.
657
664
@@ -786,7 +793,9 @@ class MetadataPathFinder(NullFinder, DistributionFinder):
786
793
of Python that do not have a PathFinder find_distributions().
787
794
"""
788
795
789
- def find_distributions (self , context = DistributionFinder .Context ()):
796
+ def find_distributions (
797
+ self , context = DistributionFinder .Context ()
798
+ ) -> Iterable ["PathDistribution" ]:
790
799
"""
791
800
Find distributions.
792
801
@@ -806,19 +815,19 @@ def _search_paths(cls, name, paths):
806
815
path .search (prepared ) for path in map (FastPath , paths )
807
816
)
808
817
809
- def invalidate_caches (cls ):
818
+ def invalidate_caches (cls ) -> None :
810
819
FastPath .__new__ .cache_clear ()
811
820
812
821
813
822
class PathDistribution (Distribution ):
814
- def __init__ (self , path : SimplePath ):
823
+ def __init__ (self , path : SimplePath ) -> None :
815
824
"""Construct a distribution.
816
825
817
826
:param path: SimplePath indicating the metadata directory.
818
827
"""
819
828
self ._path = path
820
829
821
- def read_text (self , filename ) :
830
+ def read_text (self , filename : StrPath ) -> Optional [ str ] :
822
831
with suppress (
823
832
FileNotFoundError ,
824
833
IsADirectoryError ,
@@ -828,9 +837,11 @@ def read_text(self, filename):
828
837
):
829
838
return self ._path .joinpath (filename ).read_text (encoding = 'utf-8' )
830
839
840
+ return None
841
+
831
842
read_text .__doc__ = Distribution .read_text .__doc__
832
843
833
- def locate_file (self , path ) :
844
+ def locate_file (self , path : StrPath ) -> pathlib . Path :
834
845
return self ._path .parent / path
835
846
836
847
@property
@@ -863,7 +874,7 @@ def _name_from_stem(stem):
863
874
return name
864
875
865
876
866
- def distribution (distribution_name ):
877
+ def distribution (distribution_name ) -> Distribution :
867
878
"""Get the ``Distribution`` instance for the named package.
868
879
869
880
:param distribution_name: The name of the distribution package as a string.
@@ -872,7 +883,7 @@ def distribution(distribution_name):
872
883
return Distribution .from_name (distribution_name )
873
884
874
885
875
- def distributions (** kwargs ):
886
+ def distributions (** kwargs ) -> Iterable [ Distribution ] :
876
887
"""Get all ``Distribution`` instances in the current environment.
877
888
878
889
:return: An iterable of ``Distribution`` instances.
@@ -889,7 +900,7 @@ def metadata(distribution_name) -> _meta.PackageMetadata:
889
900
return Distribution .from_name (distribution_name ).metadata
890
901
891
902
892
- def version (distribution_name ):
903
+ def version (distribution_name ) -> str :
893
904
"""Get the version string for the named package.
894
905
895
906
:param distribution_name: The name of the distribution package to query.
@@ -923,7 +934,7 @@ def entry_points(**params) -> EntryPoints:
923
934
return EntryPoints (eps ).select (** params )
924
935
925
936
926
- def files (distribution_name ):
937
+ def files (distribution_name ) -> Optional [ List [ PackagePath ]] :
927
938
"""Return a list of files for the named package.
928
939
929
940
:param distribution_name: The name of the distribution package to query.
@@ -932,11 +943,11 @@ def files(distribution_name):
932
943
return distribution (distribution_name ).files
933
944
934
945
935
- def requires (distribution_name ):
946
+ def requires (distribution_name ) -> Optional [ List [ str ]] :
936
947
"""
937
948
Return a list of requirements for the named package.
938
949
939
- :return: An iterator of requirements, suitable for
950
+ :return: An iterable of requirements, suitable for
940
951
packaging.requirement.Requirement.
941
952
"""
942
953
return distribution (distribution_name ).requires
0 commit comments