Source code for codegen.naming

import re
from typing import TYPE_CHECKING, Literal

from codegen.context import current_context

_BOUNDARY = re.compile(r"(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z0-9])(?=[A-Z])")
_SEPARATORS = re.compile(r"[./]")

if TYPE_CHECKING:
    from codegen.imports import ImportCollector


type _LocationType = Literal["generated", "external"]


[docs] class Name: original: str raw_parts: list[str] module_parts: list[str] location: _LocationType def __init__( self, raw: str | None, location: _LocationType = "generated", ) -> None: raw = raw or "" *module_parts, name = _SEPARATORS.split(raw) self.original = name words = [w for w in _BOUNDARY.sub("_", name).split("_") if w] self.module_parts = module_parts self.raw_parts = words self.location = location @staticmethod def from_module_name(module: str | None, name: str) -> Name: if module: return Name(f"{module}.{name}") return Name(name) @property def external(self) -> Name: self.location = "external" return self def __repr__(self) -> str: return f"Name({self.module_path}: '{self.snake}')" def __eq__(self, other: object) -> bool: if not isinstance(other, Name): return NotImplemented assert isinstance(other, Name) return ( self.raw_parts == other.raw_parts and self.module_parts == other.module_parts ) def __hash__(self) -> int: return hash("".join(self.raw_parts) + "".join(self.module_parts)) @property def prefixed_module_parts(self) -> list[str]: if self.location == "external": return self.module_parts ctx = current_context() if ctx: return [ctx.config.package_prefix, *self.module_parts] return self.module_parts @property def raw(self) -> str: return self.snake @property def pascal(self) -> str: return "".join(part.capitalize() for part in self.raw_parts) @property def lower(self) -> str: return "".join(part.lower() for part in self.raw_parts) @property def snake(self) -> str: return "_".join(part.lower() for part in self.raw_parts) @property def slug(self) -> str: return "-".join(part.lower() for part in self.raw_parts) @property def module_path(self) -> str: # Exclude the prefix, that's automatically included by # `codegen` when rendering return f"{'/'.join(self.module_parts)}.py" @property def init_path(self) -> str: # Exclude the prefix, that's automatically included by # `codegen` when rendering parts = [*self.module_parts[:-1], "__init__"] return f"{'/'.join(parts)}.py" @property def module_import(self) -> str: return ".".join(self.prefixed_module_parts) @property def complete_path(self) -> str: return ".".join([*self.prefixed_module_parts, self.original]) def suffixed(self, suffix: str) -> str: # Deprecated return f"{self.pascal}{suffix}" def add_import(self, imports: ImportCollector) -> None: imports.add_from(self.module_import, self.original) @staticmethod def from_dotted(dotted_path: str) -> tuple[str, Name]: # deprecated name = Name(dotted_path) return name.module_import, name def __bool__(self) -> bool: return bool(self.raw_parts)
def split_dotted_class(dotted_path: str) -> tuple[str, str]: # Deprecated name = Name(dotted_path) return name.module_import, name.original
[docs] def prefix_import(prefix: str, *parts: str) -> str: if prefix: return ".".join([prefix, *parts]) return ".".join(parts)