"""Serialization helpers for :func:`pydantic.BaseModel.model_dump`and :func:`pydantic.BaseModel.model_dump_json` ."""frompathlibimportPathfromtypingimportAny,Callable,TypeVar,Unionfrompydantic_core.core_schemaimportSerializationInfofromnumpydantic.interfaceimportInterface,JsonDictT=TypeVar("T")U=TypeVar("U")
[docs]defjsonize_array(value:Any,info:SerializationInfo)->Union[list,dict]:"""Use an interface class to render an array as JSON"""interface_cls=Interface.match_output(value)array=interface_cls.to_json(value,info)ifisinstance(array,JsonDict):array=array.model_dump(exclude_none=True)ifinfo.context:ifinfo.context.get("mark_interface",False):array=interface_cls.mark_json(array)ifinfo.context.get("absolute_paths",False):array=_absolutize_paths(array)else:relative_to=info.context.get("relative_to",".")array=_relativize_paths(array,relative_to)else:# relativize paths by defaultarray=_relativize_paths(array,".")returnarray
def_relativize_paths(value:dict,relative_to:str=".")->dict:""" Make paths relative to either the current directory or the provided ``relative_to`` directory, if provided in the context """relative_to=Path(relative_to).resolve()# pdb.set_trace()def_r_path(v:Any)->Any:try:path=Path(v)ifnotpath.exists():returnvreturnstr(relative_path(path,relative_to))except(TypeError,ValueError):returnvreturn_walk_and_apply(value,_r_path)def_absolutize_paths(value:dict)->dict:def_a_path(v:Any)->Any:try:path=Path(v)ifnotpath.exists():returnvreturnstr(path.resolve())except(TypeError,ValueError):returnvreturn_walk_and_apply(value,_a_path)def_walk_and_apply(value:T,f:Callable[[U],U])->T:""" Walk an object, applying a function """ifisinstance(value,dict):fork,vinvalue.items():ifisinstance(v,dict):_walk_and_apply(v,f)elifisinstance(v,list):value[k]=[_walk_and_apply(sub_v,f)forsub_vinv]else:value[k]=f(v)elifisinstance(value,list):value=[_walk_and_apply(v,f)forvinvalue]else:value=f(value)returnvalue
[docs]defrelative_path(self:Path,other:Path,walk_up:bool=True)->Path:""" "Backport" of :meth:`pathlib.Path.relative_to` with ``walk_up=True`` that's not available pre 3.12. Return the relative path to another path identified by the passed arguments. If the operation is not possible (because this is not related to the other path), raise ValueError. The *walk_up* parameter controls whether `..` may be used to resolve the path. References: https://github.com/python/cpython/blob/8a2baedc4bcb606da937e4e066b4b3a18961cace/Lib/pathlib/_abc.py#L244-L270 """# pdb.set_trace()ifnotisinstance(other,Path):# pragma: no cover - ripped from cpythonother=Path(other)self_parts=self.partsother_parts=other.partsanchor0,parts0=self_parts[0],list(reversed(self_parts[1:]))anchor1,parts1=other_parts[0],list(reversed(other_parts[1:]))ifanchor0!=anchor1:raiseValueError(f"{self!r} and {other!r} have different anchors")whileparts0andparts1andparts0[-1]==parts1[-1]:parts0.pop()parts1.pop()forpartinparts1:# pragma: no cover - not testing, ripped off from cpythonifnotpartorpart==".":passelifnotwalk_up:raiseValueError(f"{self!r} is not in the subpath of {other!r}")elifpart=="..":raiseValueError(f"'..' segment in {other!r} cannot be walked")else:parts0.append("..")returnPath(*reversed(parts0))