Source code for ifgen.config

"""
A module implementing a configuration interface for the package.
"""

# built-in
import re
from typing import Iterator

# third-party
from vcorelib.dict import merge, GenericStrDict
from vcorelib.dict.codec import BasicDictCodec as _BasicDictCodec
from vcorelib.io import ARBITER as _ARBITER
from vcorelib.io import DEFAULT_INCLUDES_KEY
from vcorelib.io.types import JsonObject as _JsonObject
from vcorelib.paths import Pathlike, find_file

# internal
from ifgen import PKG_NAME
from ifgen.schemas import IfgenDictCodec
from ifgen.enums import Generator


[docs] def check_patterns(method: str, name: str, *patterns: str) -> bool: """ Determine if a regular expression method matches any pattern against name. """ matched = False for pattern in patterns: if getattr(re, method)(pattern, name) is not None: matched = True break return matched
[docs] class Config(IfgenDictCodec, _BasicDictCodec): """The top-level configuration object for the package."""
[docs] def init(self, data: _JsonObject) -> None: """Initialize this instance.""" super().init(data) common = ["identifier", "unit_test"] # Load name-matching data. self.names: dict[str, list[str]] = data.get( # type: ignore "names", {} ) self.names.setdefault("search", [".*"]) # Forward enum settings. enum_forwards = common + ["use_map"] enum: GenericStrDict for enum in data.get("enums", {}).values(): # type: ignore for forward in enum_forwards: enum.setdefault( forward, data["enum"][forward], # type: ignore ) # Forward struct settings. struct_forwards = common + [ "codec", "stream", "methods", "default_endianness", "packed", ] struct: GenericStrDict for struct in data.get("structs", {}).values(): # type: ignore for forward in struct_forwards: struct.setdefault( forward, data["struct"][forward], # type: ignore )
[docs] def check_name(self, name: str) -> bool: """Determine if a provided name is included via search patterns.""" result = False for method, patterns in self.names.items(): if check_patterns(method, name, *patterns): result = True break return result
[docs] def generator_tasks( self, generator: Generator ) -> Iterator[tuple[str, GenericStrDict]]: """Handle configured exclusions.""" for name, data in self.data.get(generator.value, {}).items(): if generator.always() or self.check_name(name): yield name, data
[docs] def load(path: Pathlike) -> Config: """Load a configuration object.""" src_config = find_file("default.yaml", package=PKG_NAME) assert src_config is not None data = merge( _ARBITER.decode( src_config, includes_key=DEFAULT_INCLUDES_KEY, require_success=True, ).data, _ARBITER.decode( path, includes_key=DEFAULT_INCLUDES_KEY, require_success=True ).data, # Always allow the project-specific configuration to override package # data. expect_overwrite=True, ) return Config.create(data)