8
8
import sys
9
9
from glob import iglob
10
10
from pathlib import Path
11
- from typing import TYPE_CHECKING , MutableMapping
11
+ from typing import (
12
+ TYPE_CHECKING ,
13
+ Any ,
14
+ List ,
15
+ MutableMapping ,
16
+ NoReturn ,
17
+ Tuple ,
18
+ Union ,
19
+ overload ,
20
+ )
12
21
13
22
from more_itertools import partition , unique_everseen
14
23
from packaging .markers import InvalidMarker , Marker
21
30
command as _ , # noqa: F401 # imported for side-effects
22
31
)
23
32
from ._importlib import metadata
33
+ from ._reqs import _StrOrIter
24
34
from .config import pyprojecttoml , setupcfg
25
35
from .discovery import ConfigDiscovery
26
36
from .monkey import get_unpatched
36
46
from distutils .fancy_getopt import translate_longopt
37
47
from distutils .util import strtobool
38
48
49
+ if TYPE_CHECKING :
50
+ from typing_extensions import TypeAlias
51
+
39
52
__all__ = ['Distribution' ]
40
53
41
- sequence = tuple , list
54
+ _sequence = tuple , list
55
+ """
56
+ :meta private:
57
+
58
+ Supported iterable types that are known to be:
59
+ - ordered (which `set` isn't)
60
+ - not match a str (which `Sequence[str]` does)
61
+ - not imply a nested type (like `dict`)
62
+ for use with `isinstance`.
63
+ """
64
+ _Sequence : TypeAlias = Union [Tuple [str , ...], List [str ]]
65
+ # This is how stringifying _Sequence would look in Python 3.10
66
+ _requence_type_repr = "tuple[str, ...] | list[str]"
67
+
68
+
69
+ def __getattr__ (name : str ) -> Any : # pragma: no cover
70
+ if name == "sequence" :
71
+ SetuptoolsDeprecationWarning .emit (
72
+ "`setuptools.dist.sequence` is an internal implementation detail." ,
73
+ "Please define your own `sequence = tuple, list` instead." ,
74
+ due_date = (2025 , 8 , 28 ), # Originally added on 2024-08-27
75
+ )
76
+ return _sequence
77
+ raise AttributeError (f"module { __name__ !r} has no attribute { name !r} " )
42
78
43
79
44
80
def check_importable (dist , attr , value ):
@@ -51,17 +87,17 @@ def check_importable(dist, attr, value):
51
87
) from e
52
88
53
89
54
- def assert_string_list (dist , attr , value ) :
90
+ def assert_string_list (dist , attr : str , value : _Sequence ) -> None :
55
91
"""Verify that value is a string list"""
56
92
try :
57
93
# verify that value is a list or tuple to exclude unordered
58
94
# or single-use iterables
59
- assert isinstance (value , sequence )
95
+ assert isinstance (value , _sequence )
60
96
# verify that elements of value are strings
61
97
assert '' .join (value ) != value
62
98
except (TypeError , ValueError , AttributeError , AssertionError ) as e :
63
99
raise DistutilsSetupError (
64
- "%r must be a list of strings (got %r)" % ( attr , value )
100
+ f" { attr !r } must be of type < { _requence_type_repr } > (got { value !r } )"
65
101
) from e
66
102
67
103
@@ -126,8 +162,7 @@ def _check_marker(marker):
126
162
def assert_bool (dist , attr , value ):
127
163
"""Verify that value is True, False, 0, or 1"""
128
164
if bool (value ) != value :
129
- tmpl = "{attr!r} must be a boolean value (got {value!r})"
130
- raise DistutilsSetupError (tmpl .format (attr = attr , value = value ))
165
+ raise DistutilsSetupError (f"{ attr !r} must be a boolean value (got { value !r} )" )
131
166
132
167
133
168
def invalid_unless_false (dist , attr , value ):
@@ -138,27 +173,31 @@ def invalid_unless_false(dist, attr, value):
138
173
raise DistutilsSetupError (f"{ attr } is invalid." )
139
174
140
175
141
- def check_requirements (dist , attr , value ):
176
+ @overload
177
+ def check_requirements (dist , attr : str , value : set | dict ) -> NoReturn : ...
178
+ @overload
179
+ def check_requirements (dist , attr : str , value : _StrOrIter ) -> None : ...
180
+ def check_requirements (dist , attr : str , value : _StrOrIter ) -> None :
142
181
"""Verify that install_requires is a valid requirements list"""
143
182
try :
144
183
list (_reqs .parse (value ))
145
184
if isinstance (value , (dict , set )):
146
185
raise TypeError ("Unordered types are not allowed" )
147
186
except (TypeError , ValueError ) as error :
148
- tmpl = (
149
- "{attr!r} must be a string or list of strings "
150
- "containing valid project/version requirement specifiers; {error}"
187
+ msg = (
188
+ f "{ attr !r} must be a string or iterable of strings "
189
+ f "containing valid project/version requirement specifiers; { error } "
151
190
)
152
- raise DistutilsSetupError (tmpl . format ( attr = attr , error = error ) ) from error
191
+ raise DistutilsSetupError (msg ) from error
153
192
154
193
155
194
def check_specifier (dist , attr , value ):
156
195
"""Verify that value is a valid version specifier"""
157
196
try :
158
197
SpecifierSet (value )
159
198
except (InvalidSpecifier , AttributeError ) as error :
160
- tmpl = "{attr!r} must be a string containing valid version specifiers; {error}"
161
- raise DistutilsSetupError (tmpl . format ( attr = attr , error = error ) ) from error
199
+ msg = f "{ attr !r} must be a string containing valid version specifiers; { error } "
200
+ raise DistutilsSetupError (msg ) from error
162
201
163
202
164
203
def check_entry_points (dist , attr , value ):
@@ -767,41 +806,43 @@ def has_contents_for(self, package):
767
806
768
807
return False
769
808
770
- def _exclude_misc (self , name , value ) :
809
+ def _exclude_misc (self , name : str , value : _Sequence ) -> None :
771
810
"""Handle 'exclude()' for list/tuple attrs without a special handler"""
772
- if not isinstance (value , sequence ):
811
+ if not isinstance (value , _sequence ):
773
812
raise DistutilsSetupError (
774
- "%s : setting must be a list or tuple (%r)" % ( name , value )
813
+ f" { name } : setting must be of type < { _requence_type_repr } > (got { value !r } )"
775
814
)
776
815
try :
777
816
old = getattr (self , name )
778
817
except AttributeError as e :
779
818
raise DistutilsSetupError ("%s: No such distribution setting" % name ) from e
780
- if old is not None and not isinstance (old , sequence ):
819
+ if old is not None and not isinstance (old , _sequence ):
781
820
raise DistutilsSetupError (
782
821
name + ": this setting cannot be changed via include/exclude"
783
822
)
784
823
elif old :
785
824
setattr (self , name , [item for item in old if item not in value ])
786
825
787
- def _include_misc (self , name , value ) :
826
+ def _include_misc (self , name : str , value : _Sequence ) -> None :
788
827
"""Handle 'include()' for list/tuple attrs without a special handler"""
789
828
790
- if not isinstance (value , sequence ):
791
- raise DistutilsSetupError ("%s: setting must be a list (%r)" % (name , value ))
829
+ if not isinstance (value , _sequence ):
830
+ raise DistutilsSetupError (
831
+ f"{ name } : setting must be of type <{ _requence_type_repr } > (got { value !r} )"
832
+ )
792
833
try :
793
834
old = getattr (self , name )
794
835
except AttributeError as e :
795
836
raise DistutilsSetupError ("%s: No such distribution setting" % name ) from e
796
837
if old is None :
797
838
setattr (self , name , value )
798
- elif not isinstance (old , sequence ):
839
+ elif not isinstance (old , _sequence ):
799
840
raise DistutilsSetupError (
800
841
name + ": this setting cannot be changed via include/exclude"
801
842
)
802
843
else :
803
844
new = [item for item in value if item not in old ]
804
- setattr (self , name , old + new )
845
+ setattr (self , name , list ( old ) + new )
805
846
806
847
def exclude (self , ** attrs ):
807
848
"""Remove items from distribution that are named in keyword arguments
@@ -826,10 +867,10 @@ def exclude(self, **attrs):
826
867
else :
827
868
self ._exclude_misc (k , v )
828
869
829
- def _exclude_packages (self , packages ) :
830
- if not isinstance (packages , sequence ):
870
+ def _exclude_packages (self , packages : _Sequence ) -> None :
871
+ if not isinstance (packages , _sequence ):
831
872
raise DistutilsSetupError (
832
- "packages: setting must be a list or tuple (%r)" % ( packages ,)
873
+ f "packages: setting must be of type < { _requence_type_repr } > (got { packages !r } )"
833
874
)
834
875
list (map (self .exclude_package , packages ))
835
876
0 commit comments