You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a module with ~several dozen Pydantic classes that have ~200 NDArray field annotations. Importing that module takes 21.15 seconds. 19.95s (94%) are spent in NDArrayMeta.__module__, nearly 100% of which is spent in its inspect.stack() call.
def_get_module(cls, stack: List[FrameInfo], module: str) ->str:
# The magic below makes Python's help function display a meaningful# text with nptyping types.return"typing"ifstack[1][3] =="formatannotation"elsemodule
This seems to be an attempt to give a clean module name to inspect.formatannotation by returning "typing" which is special cased to be stripped out of the string representation used in help() (see python/cpython#72176 )
No matter whether importing, printing, or calling help(), the return of __module__ was always nptyping.ndarray, so the call appears to be entirely unused anyway.
Options
Replace with more constrained inspect call
If instead of getting the full stack, only the current and parent frame are inspected, the problem is resolved - imports are now ~1s which is entirely pydantic's overhead -- the __module__ call takes 0.08424s cumulative (for 591 calls).
fromtypesimportFrameTypefrominspectimportgetframeinfodef_get_module(cls, stack: FrameType, module: str) ->str:
# The magic below makes Python's help function display a meaningful# text with nptyping types.return"typing"ifgetframeinfo(stack.f_back).function=="formatannotation"elsemodule
That's identical to the original stack call, so a 236x perf boost for free.
I had other solutions i was going to test but that one worked so well i didn't bother
The text was updated successfully, but these errors were encountered:
here's a drop-in monkeypatch function for anyone else this affects
defpatch_npytyping():
""" npytyping makes an expensive call to inspect.stack() that makes imports of pydantic models take ~200x longer than they should: References: - https://github.com/ramonhagenaars/nptyping/issues/110 """fromnptypingimportndarrayfromnptyping.pandas_importdataframefromnptypingimportrecarrayfromnptypingimportbase_meta_classesimportinspectfromtypesimportFrameType# make a new __module__ methods for the affected classesdefnew_module_ndarray(cls) ->str:
returncls._get_module(inspect.currentframe(), 'nptyping.ndarray')
defnew_module_recarray(cls) ->str:
returncls._get_module(inspect.currentframe(), 'nptyping.recarray')
defnew_module_dataframe(cls) ->str:
returncls._get_module(inspect.currentframe(), 'nptyping.pandas_.dataframe')
# and a new _get_module method for the parent classdefnew_get_module(cls, stack: FrameType, module: str) ->str:
return"typing"ifinspect.getframeinfo(stack.f_back).function=="formatannotation"elsemodule# now apply the patchesndarray.NDArrayMeta.__module__=property(new_module_ndarray)
recarray.RecArrayMeta.__module__=property(new_module_recarray)
dataframe.DataFrameMeta.__module__=property(new_module_dataframe)
base_meta_classes.SubscriptableMeta._get_module=new_get_module
Problem
I have a module with ~several dozen Pydantic classes that have ~200
NDArray
field annotations. Importing that module takes 21.15 seconds. 19.95s (94%) are spent inNDArrayMeta.__module__
, nearly 100% of which is spent in itsinspect.stack()
call.the module call does this:
which in turn calls:
This seems to be an attempt to give a clean module name to
inspect.formatannotation
by returning "typing" which is special cased to be stripped out of the string representation used inhelp()
(see python/cpython#72176 )No matter whether importing, printing, or calling
help()
, the return of__module__
was alwaysnptyping.ndarray
, so the call appears to be entirely unused anyway.Options
Replace with more constrained
inspect
callIf instead of getting the full stack, only the current and parent frame are inspected, the problem is resolved - imports are now ~1s which is entirely pydantic's overhead -- the
__module__
call takes 0.08424s cumulative (for 591 calls).so for
NDArrayMeta
and
SubscriptableMeta
That's identical to the original
stack
call, so a 236x perf boost for free.I had other solutions i was going to test but that one worked so well i didn't bother
The text was updated successfully, but these errors were encountered: