@@ -31,9 +31,10 @@ class _Extension:
3131
3232 # The use of a parent class as a "trick":
3333 # - We need to modify __init__ so to achieve backwards compatibility
34+ # and keep allowing arbitrary keywords to be ignored
3435 # - But we don't want to throw away the dataclass-generated __init__
35- # - We also want to fool the typechecker to consider the same type
36- # signature as the dataclass-generated __init__
36+ # specially because we don't want to have to redefine all the typing
37+ # for the function arguments
3738
3839 name : str
3940 """
@@ -139,42 +140,42 @@ class _Extension:
139140_safe = tuple (f .name for f in fields (_Extension ))
140141
141142
142- if TYPE_CHECKING :
143-
144- @dataclass
145- class Extension (_Extension ):
146- pass
147-
148- else :
149-
150- @dataclass (init = False )
151- class Extension (_Extension ):
152- def __init__ (self , name , sources , * args , ** kwargs ):
153- if not isinstance (name , str ):
154- raise TypeError ("'name' must be a string" )
155-
156- # handle the string case first; since strings are iterable, disallow them
157- if isinstance (sources , str ):
158- raise TypeError (
159- "'sources' must be an iterable of strings or PathLike objects, not a string"
160- )
161-
162- # now we check if it's iterable and contains valid types
163- try :
164- sources = list (map (os .fspath , sources ))
165- except TypeError :
166- raise TypeError (
167- "'sources' must be an iterable of strings or PathLike objects"
168- )
143+ @dataclass (init = True if TYPE_CHECKING else False ) # type: ignore[literal-required]
144+ class Extension (_Extension ):
145+ if not TYPE_CHECKING :
169146
147+ def __init__ (self , * args , ** kwargs ):
170148 extra = {repr (k ): kwargs .pop (k ) for k in tuple (kwargs ) if k not in _safe }
171149 if extra :
172- warnings .warn (f"Unknown Extension options: { ',' .join (extra )} " )
150+ msg = f"""
151+ Please remove unknown `Extension` options: { ',' .join (extra )}
152+ this kind of usage is deprecated and may cause errors in the future.
153+ """
154+ warnings .warn (msg )
173155
174156 # Ensure default values (e.g. []) are used instead of None:
175- positional = {k : v for k , v in zip (_safe [ 2 :] , args ) if v is not None }
157+ positional = {k : v for k , v in zip (_safe , args ) if v is not None }
176158 keywords = {k : v for k , v in kwargs .items () if v is not None }
177- super ().__init__ (name , sources , ** positional , ** keywords )
159+ super ().__init__ (** positional , ** keywords )
160+ self .__post_init__ () # does not seem to be called when customizing __init__
161+
162+ def __post_init__ (self ):
163+ if not isinstance (self .name , str ):
164+ raise TypeError ("'name' must be a string" )
165+
166+ # handle the string case first; since strings are iterable, disallow them
167+ if isinstance (self .sources , str ):
168+ raise TypeError (
169+ "'sources' must be an iterable of strings or PathLike objects, not a string"
170+ )
171+
172+ # now we check if it's iterable and contains valid types
173+ try :
174+ self .sources = list (map (os .fspath , self .sources ))
175+ except TypeError :
176+ raise TypeError (
177+ "'sources' must be an iterable of strings or PathLike objects"
178+ )
178179
179180
180181def read_setup_file (filename ): # noqa: C901
0 commit comments