Source code for statham.serializers.python

from typing import Set, Type, Union

from statham.schema.elements import Element, Object
from statham.schema.elements.meta import ObjectMeta
from statham.serializers.orderer import orderer, get_children


[docs]def serialize_python(*elements: Element) -> str: """Serialize schema elements to python declaration string. Captures declaration of the first Object elements, and any subsequent elements this depends on. Module imports and declaration order are dynamically inferred. :param elements: The :class:`~statham.schema.elements.Element` objects to serialize. :return: Python module contents as a string, declaring the element tree. """ declarations = "\n\n".join( [object_model.python() for object_model in orderer(*elements)] ) imports = _get_imports(declarations, *elements) return "\n\n\n".join(block for block in [imports, declarations] if block)
def _get_imports(declarations: str, *elements: Element) -> str: """Get import statements required by the elements.""" imports = [ _get_standard_imports(declarations), _get_statham_imports(declarations, *elements), ] return "\n\n".join(block for block in imports if block) def _get_standard_imports(declaration: str) -> str: """Get group if imports from standard library. Currently only includes type annotations. """ type_imports = ", ".join( [ annotation for annotation in ("Any", "List", "Union") if annotation in declaration ] ) if not type_imports: return "" return f"from typing import {type_imports}" def _get_statham_imports(declaration: str, *elements: Element) -> str: """Construct imports from statham submodules.""" statham_imports = [] if "Maybe" in declaration: statham_imports.append("from statham.schema.constants import Maybe") element_imports = _get_element_imports(*elements) if element_imports: statham_imports.append(element_imports) if "Property" in declaration: statham_imports.append("from statham.schema.property import Property") return "\n".join(statham_imports) def _get_element_imports(*elements: Element) -> str: """Get the import string for the elements in use.""" prefix = "from statham.schema.elements import " max_length = 80 import_names = [ elem_type.__name__ for elem_type in set.union( *(_get_single_element_imports(element) for element in elements) ) ] if not import_names: return "" imports = ", ".join(sorted(import_names)) if max_length < len(prefix) + len(imports): imports = "\n ".join(["("] + imports.split(" ")) + ",\n)" return prefix + imports def _get_single_element_imports( element: Element, ) -> Set[Union[Type[Element], ObjectMeta]]: """Extract the set of element types used by a given element.""" get_type = ( lambda elem: Object if isinstance(elem, ObjectMeta) else type(elem) ) children = [element, *get_children(element)] return set(map(get_type, children)) # type: ignore