33import enum
44import typing
55from dataclasses import MISSING
6- from typing import cast , Any , Callable , Dict , Set , Tuple , Type , TypeVar , Iterator , Optional , Union
6+ from typing import (
7+ cast ,
8+ Any ,
9+ Callable ,
10+ Dict ,
11+ Set ,
12+ Tuple ,
13+ Type ,
14+ TypeVar ,
15+ Iterator ,
16+ Optional ,
17+ Union ,
18+ )
719from typing_extensions import Protocol
820
921
@@ -12,24 +24,27 @@ class HasAnnotations(Protocol):
1224
1325
1426class Constructable (Protocol ):
15- def __init__ (self , ** kwargs : object ) -> None : ...
27+ def __init__ (self , ** kwargs : object ) -> None :
28+ ...
1629
1730
18- _A = TypeVar ('_A' , bound = HasAnnotations )
19- _C = TypeVar ('_C' , bound = Constructable )
31+ _A = TypeVar ("_A" , bound = HasAnnotations )
32+ _C = TypeVar ("_C" , bound = Constructable )
2033
2134
2235class mapping_dict (Dict [str , Any ]):
2336 """A dictionary that also contains source line information."""
24- __slots__ = ('_start_line' , '_end_line' )
37+
38+ __slots__ = ("_start_line" , "_end_line" )
2539 _start_line : int
2640 _end_line : int
2741
2842
2943@dataclasses .dataclass
3044class _Field :
3145 """A single field in a _TypeThunk."""
32- __slots__ = ('default_factory' , 'type' )
46+
47+ __slots__ = ("default_factory" , "type" )
3348
3449 default_factory : Optional [Callable [[], Any ]]
3550 type : Type [Any ]
@@ -39,7 +54,8 @@ class _TypeThunk:
3954 """Type hints cannot be fully resolved at module runtime due to ForwardRefs. Instead,
4055 store the type here, and resolve type hints only when needed. By that time, hopefully all
4156 types have been declared."""
42- __slots__ = ('type' , '_fields' )
57+
58+ __slots__ = ("type" , "_fields" )
4359
4460 def __init__ (self , klass : Type [Any ]) -> None :
4561 self .type = klass
@@ -63,10 +79,16 @@ def make_factory(value: object) -> Callable[[], Any]:
6379 # in the lambda is a ~~hack~~ to avoid messing up the variable binding.
6480 fields : Dict [str , _Field ] = {
6581 field .name : _Field (
66- field .default_factory if field .default_factory is not MISSING # type: ignore
67- else ((make_factory (field .default )) if field .default is not MISSING
68- else None ),
69- hints [field .name ]) for field in dataclasses .fields (self .type )
82+ field .default_factory # type: ignore
83+ if field .default_factory is not MISSING # type: ignore
84+ else (
85+ (make_factory (field .default ))
86+ if field .default is not MISSING
87+ else None
88+ ),
89+ hints [field .name ],
90+ )
91+ for field in dataclasses .fields (self .type )
7092 }
7193
7294 self ._fields = fields
@@ -78,73 +100,76 @@ def make_factory(value: object) -> Callable[[], Any]:
78100
79101
80102def _add_indefinite_article (s : str ) -> str :
81- if s == ' nothing' :
103+ if s == " nothing" :
82104 return s
83105
84- return (' an ' if s [0 ].lower () in ' aeiouy' else 'a ' ) + s
106+ return (" an " if s [0 ].lower () in " aeiouy" else "a " ) + s
85107
86108
87109def _get_typename (ty : type ) -> str :
88- return str (ty ).replace (' typing.' , '' )
110+ return str (ty ).replace (" typing." , "" )
89111
90112
91113def _pluralize (s : str ) -> str :
92114 if s [- 1 ].isalpha ():
93- return s + 's'
115+ return s + "s"
94116
95- return s + ' \' s'
117+ return s + "'s"
96118
97119
98120def _generate_hint (ty : type , get_description : Callable [[type ], str ]) -> str :
99121 try :
100122 name = ty .__name__
101123 except AttributeError :
102124 return str (ty )
103- docstring = '\n ' .join (' ' + line for line in (ty .__doc__ or '' ).split ('\n ' ))
104- fields = '\n ' .join (f' { k } : { get_description (v )} '
105- for k , v in typing .get_type_hints (ty ).items () if not k .startswith ('_' ))
106- return f'{ name } :\n { docstring } \n { fields } '
125+ docstring = "\n " .join (" " + line for line in (ty .__doc__ or "" ).split ("\n " ))
126+ fields = "\n " .join (
127+ f" { k } : { get_description (v )} "
128+ for k , v in typing .get_type_hints (ty ).items ()
129+ if not k .startswith ("_" )
130+ )
131+ return f"{ name } :\n { docstring } \n { fields } "
107132
108133
109134def english_description_of_type (ty : type ) -> Tuple [str , Dict [type , str ]]:
110135 hints : Dict [type , str ] = {}
111136
112137 def inner (ty : type , plural : bool , level : int ) -> str :
113138 pluralize = _pluralize if plural else lambda s : s
114- plural_suffix = 's' if plural else ''
139+ plural_suffix = "s" if plural else ""
115140
116141 if ty is str :
117- return pluralize (' string' )
142+ return pluralize (" string" )
118143
119144 if ty is int :
120- return pluralize (' integer' )
145+ return pluralize (" integer" )
121146
122147 if ty is float :
123- return pluralize (' number' )
148+ return pluralize (" number" )
124149
125150 if ty is bool :
126- return pluralize (' boolean' )
151+ return pluralize (" boolean" )
127152
128153 if ty is type (None ): # noqa
129- return ' nothing'
154+ return " nothing"
130155
131156 if ty is object or ty is Any :
132- return ' anything'
157+ return " anything"
133158
134159 level += 1
135160 if level > 4 :
136161 # Making nested English clauses understandable is hard. Give up.
137162 return pluralize (_get_typename (ty ))
138163
139- origin = getattr (ty , ' __origin__' , None )
164+ origin = getattr (ty , " __origin__" , None )
140165 if origin is not None :
141- args = getattr (ty , ' __args__' )
166+ args = getattr (ty , " __args__" )
142167 if origin is list :
143- return f' list{ plural_suffix } of { inner (args [0 ], True , level )} '
168+ return f" list{ plural_suffix } of { inner (args [0 ], True , level )} "
144169 elif origin is dict :
145170 key_type = inner (args [0 ], True , level )
146171 value_type = inner (args [1 ], True , level )
147- return f' mapping{ plural_suffix } of { key_type } to { value_type } '
172+ return f" mapping{ plural_suffix } of { key_type } to { value_type } "
148173 elif origin is tuple :
149174 # Tuples are a hard problem... this is okay
150175 return pluralize (_get_typename (ty ))
@@ -156,17 +181,17 @@ def inner(ty: type, plural: bool, level: int) -> str:
156181 pass
157182 else :
158183 non_none_arg = args [int (not none_index )]
159- return f' optional { inner (non_none_arg , plural , level )} '
184+ return f" optional { inner (non_none_arg , plural , level )} "
160185
161186 up_to_last = args [:- 1 ]
162187 part1 = (inner (arg , plural , level = level ) for arg in up_to_last )
163188 part2 = inner (args [- 1 ], plural , level = level )
164189 if not plural :
165190 part1 = (_add_indefinite_article (desc ) for desc in part1 )
166191 part2 = _add_indefinite_article (part2 )
167- comma = ',' if len (up_to_last ) > 1 else ''
168- joined_part1 = ', ' .join (part1 )
169- return f' either { joined_part1 } { comma } or { part2 } '
192+ comma = "," if len (up_to_last ) > 1 else ""
193+ joined_part1 = ", " .join (part1 )
194+ return f" either { joined_part1 } { comma } or { part2 } "
170195
171196 # A custom type
172197 if ty not in hints :
@@ -196,14 +221,13 @@ def __init__(self, message: str, ty: type, bad_data: object) -> None:
196221class LoadWrongType (LoadError ):
197222 def __init__ (self , ty : type , bad_data : object ) -> None :
198223 description , hints = english_description_of_type (ty )
199- hint_text = ' \n \n ' .join (hints .values ())
224+ hint_text = " \n \n " .join (hints .values ())
200225 if hint_text :
201- hint_text = ' \n \n ' + hint_text
226+ hint_text = " \n \n " + hint_text
202227
203228 super ().__init__ (
204- f'Incorrect type. Expected { description } .{ hint_text } ' ,
205- ty ,
206- bad_data )
229+ f"Incorrect type. Expected { description } .{ hint_text } " , ty , bad_data
230+ )
207231
208232
209233class LoadWrongArity (LoadWrongType ):
@@ -264,15 +288,15 @@ def check_type(ty: Type[_C], data: object) -> _C:
264288 result [key ] = check_type (field .type , value )
265289
266290 output = ty (** result )
267- start_line = getattr (data , ' _start_line' , None )
291+ start_line = getattr (data , " _start_line" , None )
268292 if start_line is not None :
269- setattr (output , ' _start_line' , start_line )
293+ setattr (output , " _start_line" , start_line )
270294 return output
271295
272296 # Check for one of the special types defined by PEP-484
273- origin = getattr (ty , ' __origin__' , None )
297+ origin = getattr (ty , " __origin__" , None )
274298 if origin is not None :
275- args = getattr (ty , ' __args__' )
299+ args = getattr (ty , " __args__" )
276300 if origin is list :
277301 if not isinstance (data , list ):
278302 raise LoadWrongType (ty , data )
@@ -281,17 +305,22 @@ def check_type(ty: Type[_C], data: object) -> _C:
281305 if not isinstance (data , dict ):
282306 raise LoadWrongType (ty , data )
283307 key_type , value_type = args
284- return cast (_C , {
285- check_type (key_type , k ): check_type (value_type , v )
286- for k , v in data .items ()})
308+ return cast (
309+ _C ,
310+ {
311+ check_type (key_type , k ): check_type (value_type , v )
312+ for k , v in data .items ()
313+ },
314+ )
287315 elif origin is tuple :
288316 if not isinstance (data , collections .abc .Collection ):
289317 raise LoadWrongType (ty , data )
290318
291319 if not len (data ) == len (args ):
292320 raise LoadWrongArity (ty , data )
293- return cast (_C , tuple (
294- check_type (tuple_ty , x ) for x , tuple_ty in zip (data , args )))
321+ return cast (
322+ _C , tuple (check_type (tuple_ty , x ) for x , tuple_ty in zip (data , args ))
323+ )
295324 elif origin is Union :
296325 for candidate_ty in args :
297326 try :
@@ -301,9 +330,9 @@ def check_type(ty: Type[_C], data: object) -> _C:
301330
302331 raise LoadWrongType (ty , data )
303332
304- raise LoadError (' Unsupported PEP-484 type' , ty , data )
333+ raise LoadError (" Unsupported PEP-484 type" , ty , data )
305334
306335 if ty is object or ty is Any or isinstance (data , ty ):
307336 return cast (_C , data )
308337
309- raise LoadError (' Unloadable type' , ty , data )
338+ raise LoadError (" Unloadable type" , ty , data )
0 commit comments