33__all__ = ['defaults' , 'ifnone' , 'maybe_attr' , 'basic_repr' , 'is_array' , 'listify' , 'true' , 'NullType' , 'null' ,
44 'tonull' , 'get_class' , 'mk_class' , 'wrap_class' , 'ignore_exceptions' , 'exec_local' , 'risinstance' , 'Inf' ,
55 'in_' , 'lt' , 'gt' , 'le' , 'ge' , 'eq' , 'ne' , 'add' , 'sub' , 'mul' , 'truediv' , 'is_' , 'is_not' , 'in_' , 'true' ,
6- 'stop' , 'gen' , 'chunked' , 'otherwise' , 'custom_dir' , 'AttrDict' , 'with_cast ' , 'store_attr ' , 'attrdict ' ,
7- 'properties ' , 'camel2snake ' , 'snake2camel ' , 'class2attr ' , 'hasattrs ' , 'setattrs ' , 'try_attrs ' , 'ShowPrint ' ,
8- 'Int ' , 'Str ' , 'Float ' , 'detuplify ' , 'replicate ' , 'setify ' , 'merge ' , 'range_of ' , 'groupby' , 'last_index ' ,
9- 'filter_dict ' , 'filter_keys ' , 'filter_values ' , 'cycle ' , 'zip_cycle ' , 'sorted_ex ' , 'negate_func ' , 'argwhere ' ,
10- 'filter_ex ' , 'range_of ' , 'renumerate ' , 'first ' , 'nested_attr ' , 'nested_idx ' , 'num_methods ' , 'rnum_methods ' ,
11- 'inum_methods ' , 'fastuple ' , 'arg0 ' , 'arg1 ' , 'arg2 ' , 'arg3 ' , 'arg4' , 'bind' , 'map_ex' , 'compose' , 'maps ' ,
12- 'partialler ' , 'instantiate ' , 'using_attr ' , 'Self ' , 'Self ' , 'PrettyString ' , 'even_mults ' , 'num_cpus ' ,
13- 'add_props' , 'typed' ]
6+ 'stop' , 'gen' , 'chunked' , 'otherwise' , 'custom_dir' , 'AttrDict' , 'type_hints ' , 'annotations ' , 'anno_ret ' ,
7+ 'argnames ' , 'with_cast ' , 'store_attr ' , 'attrdict ' , 'properties ' , 'camel2snake ' , 'snake2camel ' , 'class2attr ' ,
8+ 'getattrs ' , 'hasattrs ' , 'setattrs ' , 'try_attrs ' , 'ShowPrint ' , 'Int ' , 'Str ' , 'Float ' , 'detuplify ' ,
9+ 'replicate ' , 'setify ' , 'merge ' , 'range_of ' , 'groupby ' , 'last_index ' , 'filter_dict ' , 'filter_keys ' ,
10+ 'filter_values ' , 'cycle ' , 'zip_cycle ' , 'sorted_ex ' , 'negate_func ' , 'argwhere ' , 'filter_ex ' , 'range_of ' ,
11+ 'renumerate ' , 'first ' , 'nested_attr ' , 'nested_idx ' , 'num_methods ' , 'rnum_methods ' , 'inum_methods ' ,
12+ 'fastuple ' , 'arg0 ' , 'arg1 ' , 'arg2 ' , 'arg3 ' , 'arg4 ' , 'bind ' , 'map_ex' , 'compose' , 'maps' , 'partialler ' ,
13+ 'instantiate' , 'using_attr' , 'Self' , 'Self' , 'PrettyString' , 'even_mults' , 'num_cpus' , ' add_props' , 'typed' ]
1414
1515# Cell
1616from .imports import *
@@ -216,12 +216,37 @@ def __getattr__(self,k): return self[k] if k in self else stop(AttributeError(k)
216216 def __setattr__ (self , k , v ): (self .__setitem__ ,super ().__setattr__ )[k [0 ]== '_' ](k ,v )
217217 def __dir__ (self ): return custom_dir (self , list (self .keys ()))
218218
219+ # Cell
220+ def type_hints (f ):
221+ "Same as `typing.get_type_hints` but returns `{}` if not allowed type"
222+ return typing .get_type_hints (f ) if isinstance (f , typing ._allowed_types ) else {}
223+
224+ # Cell
225+ def annotations (o ):
226+ "Annotations for `o`, or `type(o)`"
227+ res = {}
228+ if not o : return res
229+ res = type_hints (o )
230+ if not res : res = type_hints (getattr (o ,'__init__' ,None ))
231+ if not res : res = type_hints (type (o ))
232+ return res
233+
234+ # Cell
235+ def anno_ret (func ):
236+ "Get the return annotation of `func`"
237+ return annotations (func ).get ('return' , None ) if func else None
238+
239+ # Cell
240+ def argnames (f ):
241+ "Names of arguments to function `f`"
242+ code = f .__code__
243+ return code .co_varnames [:code .co_argcount ]
244+
219245# Cell
220246def with_cast (f ):
221247 "Decorator which uses any parameter annotations as preprocessing functions"
222- anno = f .__annotations__
223- params = f .__code__ .co_varnames [:f .__code__ .co_argcount ]
224- defaults = dict (zip (reversed (params ), reversed (f .__defaults__ ))) if f .__defaults__ else {}
248+ anno ,params = annotations (f ),argnames (f )
249+ defaults = dict (zip (reversed (params ), reversed (f .__defaults__ or {})))
225250 @functools .wraps (f )
226251 def _inner (* args , ** kwargs ):
227252 args = list (args )
@@ -236,28 +261,32 @@ def _inner(*args, **kwargs):
236261
237262# Cell
238263def _store_attr (self , anno , ** attrs ):
264+ stored = self .__stored_args__
239265 for n ,v in attrs .items ():
240266 if n in anno : v = anno [n ](v )
241267 setattr (self , n , v )
242- self . __stored_args__ [n ] = v
268+ stored [n ] = v
243269
244270# Cell
245- def store_attr (names = None , self = None , but = None , cast = False , ** attrs ):
271+ def store_attr (names = None , self = None , but = '' , cast = False , ** attrs ):
246272 "Store params named in comma-separated `names` from calling context into attrs in `self`"
247273 fr = sys ._getframe (1 )
248- args = fr .f_code .co_varnames [:fr .f_code .co_argcount ]
274+ args = fr .f_code .co_varnames [:fr .f_code .co_argcount + fr . f_code . co_kwonlyargcount ]
249275 if self : args = ('self' , * args )
250276 else : self = fr .f_locals [args [0 ]]
251277 if not hasattr (self , '__stored_args__' ): self .__stored_args__ = {}
252- anno = self .__class__ .__init__ .__annotations__ if cast else {}
253- if attrs : return _store_attr (self , anno , ** attrs )
254- ns = re .split (', *' , names ) if names else args [1 :]
255- _store_attr (self , anno , ** {n :fr .f_locals [n ] for n in ns if n not in listify (but )})
278+ anno = annotations (self ) if cast else {}
279+ if not attrs :
280+ ns = re .split (', *' , names ) if names else args [1 :]
281+ attrs = {n :fr .f_locals [n ] for n in ns }
282+ if isinstance (but ,str ): but = re .split (', *' , but )
283+ attrs = {k :v for k ,v in attrs .items () if k not in but }
284+ return _store_attr (self , anno , ** attrs )
256285
257286# Cell
258- def attrdict (o , * ks ):
287+ def attrdict (o , * ks , default = None ):
259288 "Dict from each `k` in `ks` to `getattr(o,k)`"
260- return {k :getattr (o ,k ) for k in ks }
289+ return {k :getattr (o , k , default ) for k in ks }
261290
262291# Cell
263292def properties (cls , * ps ):
@@ -284,6 +313,11 @@ def class2attr(self, cls_name):
284313 "Return the snake-cased name of the class; strip ending `cls_name` if it exists."
285314 return camel2snake (re .sub (rf'{ cls_name } $' , '' , self .__class__ .__name__ ) or cls_name .lower ())
286315
316+ # Cell
317+ def getattrs (o , * attrs , default = None ):
318+ "List of all `attrs` in `o`"
319+ return [getattr (o ,attr ,default ) for attr in attrs ]
320+
287321# Cell
288322def hasattrs (o ,attrs ):
289323 "Test whether `o` contains all `attrs`"
@@ -660,14 +694,14 @@ def _typeerr(arg, val, typ): return TypeError(f"{arg}=={val} not {typ}")
660694def typed (f ):
661695 "Decorator to check param and return types at runtime"
662696 names = f .__code__ .co_varnames
663- anno = f . __annotations__
697+ anno = annotations ( f )
664698 ret = anno .pop ('return' ,None )
665699 def _f (* args ,** kwargs ):
666700 kw = {** kwargs }
667701 if len (anno ) > 0 :
668702 for i ,arg in enumerate (args ): kw [names [i ]] = arg
669703 for k ,v in kw .items ():
670- if not isinstance (v ,anno [k ]): raise _typeerr (k , v , anno [k ])
704+ if k in anno and not isinstance (v ,anno [k ]): raise _typeerr (k , v , anno [k ])
671705 res = f (* args ,** kwargs )
672706 if ret is not None and not isinstance (res ,ret ): raise _typeerr ("return" , res , ret )
673707 return res
0 commit comments