"""Metaprogramming functions for numpydantic to modify itself :)"""frompathlibimportPathfromwarningsimportwarnfromnumpydantic.interfaceimportInterface_BUILTIN_IMPORTS=("import typing","import pathlib")
[docs]defgenerate_ndarray_stub()->str:""" Make a stub file based on the array interfaces that are available """import_strings=[]type_names=[]forarrinInterface.input_types():ifarr.__module__=="builtins":continue# Create import statements, saving aliased name of type if neededifarr.__module__.startswith("numpydantic")orarr.__module__=="typing":type_name=str(arr)ifarr.__module__=="typing"elsearr.__name__ifarr.__module__!="typing":import_strings.append(f"from {arr.__module__} import {type_name}")else:# since other packages could use the same name for an imported object# (eg dask and zarr both use an Array class)# we make an import alias from the module names to differentiate them# in the type annotationmod_name="".join([a.capitalize()forainarr.__module__.split(".")])type_name=mod_name+arr.__name__import_strings.append(f"from {arr.__module__} import {arr.__name__} "f"as {type_name}")type_names.append(type_name)import_strings.extend(_BUILTIN_IMPORTS)import_strings=list(dict.fromkeys(import_strings))import_string="\n".join(import_strings)class_union=" | ".join(type_names)ndarray_type="NDArray = "+class_unionstub_string="\n".join([import_string,ndarray_type])returnstub_string
[docs]defupdate_ndarray_stub()->None:""" Update the ndarray.pyi string in the numpydantic file """fromnumpydanticimportndarraytry:stub_string=generate_ndarray_stub()pyi_file=Path(ndarray.__file__).with_suffix(".pyi")withopen(pyi_file,"w")aspyi:pyi.write(stub_string)exceptExceptionase:# pragma: no coverwarn(f"ndarray.pyi stub file could not be generated: {e}",stacklevel=1)