88import sys
99from glob import iglob
1010from pathlib import Path
11- from typing import TYPE_CHECKING , MutableMapping
11+ from typing import TYPE_CHECKING , List , MutableMapping , NoReturn , Tuple , Union , overload
1212
1313from more_itertools import partition , unique_everseen
1414from packaging .markers import InvalidMarker , Marker
2121 command as _ , # noqa: F401 # imported for side-effects
2222)
2323from ._importlib import metadata
24+ from ._reqs import _StrOrIter
2425from .config import pyprojecttoml , setupcfg
2526from .discovery import ConfigDiscovery
2627from .monkey import get_unpatched
3637from distutils .fancy_getopt import translate_longopt
3738from distutils .util import strtobool
3839
40+ if TYPE_CHECKING :
41+ from typing_extensions import TypeAlias
42+
3943__all__ = ['Distribution' ]
4044
4145sequence = tuple , list
46+ """
47+ Supported iterable types that are known to be:
48+ - ordered (which `set` isn't)
49+ - not match a str (which `Sequence[str]` does)
50+ - not imply a nested type (like `dict`)
51+ for use with `isinstance`.
52+ """
53+ _Sequence : TypeAlias = Union [Tuple [str , ...], List [str ]]
54+ # This is how stringifying _Sequence would look in Python 3.10
55+ _requence_type_repr = "tuple[str, ...] | list[str]"
4256
4357
4458def check_importable (dist , attr , value ):
@@ -51,7 +65,7 @@ def check_importable(dist, attr, value):
5165 ) from e
5266
5367
54- def assert_string_list (dist , attr , value ) :
68+ def assert_string_list (dist , attr : str , value : _Sequence ) -> None :
5569 """Verify that value is a string list"""
5670 try :
5771 # verify that value is a list or tuple to exclude unordered
@@ -61,7 +75,7 @@ def assert_string_list(dist, attr, value):
6175 assert '' .join (value ) != value
6276 except (TypeError , ValueError , AttributeError , AssertionError ) as e :
6377 raise DistutilsSetupError (
64- "%r must be a list of strings (got %r)" % ( attr , value )
78+ f" { attr !r } must be of type < { _requence_type_repr } > (got { value !r } )"
6579 ) from e
6680
6781
@@ -138,18 +152,22 @@ def invalid_unless_false(dist, attr, value):
138152 raise DistutilsSetupError (f"{ attr } is invalid." )
139153
140154
141- def check_requirements (dist , attr , value ):
155+ @overload
156+ def check_requirements (dist , attr : str , value : set | dict ) -> NoReturn : ...
157+ @overload
158+ def check_requirements (dist , attr : str , value : _StrOrIter ) -> None : ...
159+ def check_requirements (dist , attr : str , value : _StrOrIter ) -> None :
142160 """Verify that install_requires is a valid requirements list"""
143161 try :
144162 list (_reqs .parse (value ))
145163 if isinstance (value , (dict , set )):
146164 raise TypeError ("Unordered types are not allowed" )
147165 except (TypeError , ValueError ) as error :
148166 tmpl = (
149- "{attr!r} must be a string or list of strings "
150- "containing valid project/version requirement specifiers; {error}"
167+ f "{ attr !r} must be a string or iterable of strings "
168+ f "containing valid project/version requirement specifiers; { error } "
151169 )
152- raise DistutilsSetupError (tmpl . format ( attr = attr , error = error ) ) from error
170+ raise DistutilsSetupError (tmpl ) from error
153171
154172
155173def check_specifier (dist , attr , value ):
@@ -767,11 +785,11 @@ def has_contents_for(self, package):
767785
768786 return False
769787
770- def _exclude_misc (self , name , value ) :
788+ def _exclude_misc (self , name : str , value : _Sequence ) -> None :
771789 """Handle 'exclude()' for list/tuple attrs without a special handler"""
772790 if not isinstance (value , sequence ):
773791 raise DistutilsSetupError (
774- "%s : setting must be a list or tuple (%r)" % ( name , value )
792+ f" { name } : setting must be of type < { _requence_type_repr } > (got { value !r } )"
775793 )
776794 try :
777795 old = getattr (self , name )
@@ -784,11 +802,13 @@ def _exclude_misc(self, name, value):
784802 elif old :
785803 setattr (self , name , [item for item in old if item not in value ])
786804
787- def _include_misc (self , name , value ) :
805+ def _include_misc (self , name : str , value : _Sequence ) -> None :
788806 """Handle 'include()' for list/tuple attrs without a special handler"""
789807
790808 if not isinstance (value , sequence ):
791- raise DistutilsSetupError ("%s: setting must be a list (%r)" % (name , value ))
809+ raise DistutilsSetupError (
810+ f"{ name } : setting must be of type <{ _requence_type_repr } > (got { value !r} )"
811+ )
792812 try :
793813 old = getattr (self , name )
794814 except AttributeError as e :
@@ -801,7 +821,7 @@ def _include_misc(self, name, value):
801821 )
802822 else :
803823 new = [item for item in value if item not in old ]
804- setattr (self , name , old + new )
824+ setattr (self , name , list ( old ) + new )
805825
806826 def exclude (self , ** attrs ):
807827 """Remove items from distribution that are named in keyword arguments
@@ -826,10 +846,10 @@ def exclude(self, **attrs):
826846 else :
827847 self ._exclude_misc (k , v )
828848
829- def _exclude_packages (self , packages ) :
849+ def _exclude_packages (self , packages : _Sequence ) -> None :
830850 if not isinstance (packages , sequence ):
831851 raise DistutilsSetupError (
832- "packages: setting must be a list or tuple (%r)" % ( packages ,)
852+ f "packages: setting must be of type < { _requence_type_repr } > (got { packages !r } )"
833853 )
834854 list (map (self .exclude_package , packages ))
835855
0 commit comments