Source code for xsdata.formats.mixins

import abc
from dataclasses import dataclass
from pathlib import Path
from typing import Dict
from typing import Iterator
from typing import List

from jinja2 import Environment
from jinja2 import FileSystemLoader
from jinja2 import Template

from xsdata.codegen.models import Class
from xsdata.exceptions import CodeGenerationError
from xsdata.models.config import GeneratorConfig
from xsdata.models.config import OutputStructure
from xsdata.utils.collections import group_by
from xsdata.utils.package import module_path
from xsdata.utils.package import package_path


[docs]@dataclass(frozen=True) class GeneratorResult: """ Generator easy access output wrapper. :param path: file path to be written :param title: result title for misc usage :param source: source code/output to be written """ path: Path title: str source: str
[docs]class AbstractGenerator(metaclass=abc.ABCMeta): """ Abstract code generator class. :param tpl_dir: Templates directory :param config: Generator configuration """ def __init__(self, tpl_dir: str, config: GeneratorConfig): """ Generator constructor. Initialize jinja2 environment. """ self.env = Environment(loader=FileSystemLoader(tpl_dir), autoescape=False) self.config = config
[docs] def template(self, name: str) -> Template: """Return the named template from the initialized environment.""" return self.env.get_template(f"{name}.jinja2")
[docs] def module_name(self, module: str) -> str: """Convert the given module name to match the generator conventions.""" return module
[docs] def package_name(self, package: str) -> str: """Convert the given module name to match the generator conventions.""" return package
[docs] @abc.abstractmethod def render(self, classes: List[Class]) -> Iterator[GeneratorResult]: """Return a iterator of the generated results."""
[docs] @classmethod def group_by_package(cls, classes: List[Class]) -> Dict[Path, List[Class]]: """Group the given list of classes by the target package directory.""" return group_by(classes, lambda x: package_path(x.target_module))
[docs] @classmethod def group_by_module(cls, classes: List[Class]) -> Dict[Path, List[Class]]: """Group the given list of classes by the target module directory.""" return group_by(classes, lambda x: module_path(x.target_module))
[docs] def designate(self, classes: List[Class]): """ Normalize the target package and module names by the given output generator. :param classes: a list of codegen class instances """ modules = {} packages = {} ns_struct = self.config.output.structure == OutputStructure.NAMESPACES for obj in classes: if ns_struct: obj.package = self.config.output.package obj.module = obj.target_namespace or "" if obj.package is None: raise CodeGenerationError( f"Class `{obj.name}` has not been assign to a package." ) if obj.module not in modules: modules[obj.module] = self.module_name(obj.module) if obj.package not in packages: packages[obj.package] = self.package_name(obj.package) obj.module = modules[obj.module] obj.package = packages[obj.package]