Source code for elasticai.creator.ir.base.ir_data

from collections.abc import Callable

from .attribute import Attribute
from .attributes_descriptor import AttributesDescriptor
from .ir_data_meta import IrDataMeta


[docs] class IrData(metaclass=IrDataMeta, create_init=False): """Convenience class for creating new Ir data classes. To create a new Ir data class, inherit from `IrData` and define your required fields. Supported field types are - ['RequiredField'](#elasticai.creator.ir.required_field.RequiredField) - [`ReadOnlyField`](#elasticai.creator.ir.required_field.ReadOnlyField) - [`SimpleField`](#elasticai.creator.ir.required_field.SimpleField) - [`StaticMethodField`](#elasticai.creator.ir.required_field.static_required_field) - [`ReadOnlyMethodField`](#elasticai.creator.ir.required_field.read_only_field) Examples: We can define a new class `MyNewIrData` with the two required fields `name` and `length` like this: ```python from elasticai.creator.ir import IrData, SimpleRequiredField, RequiredField class MyNewIrData(IrData): name: SimpleRequiredField[str] = SimpleRequiredField() # <1> length: RequiredField[str, int] = RequiredField(str, int) # <2> d = MyNewIrData({'name': 'my name', 'length': '12'}) d.name = 'new name' # <3> d.length += 3 # <4> ``` 1. We define a simple required field. Data will be stored as string and can be accessed as string. 2. Opposed to 1. this field will store data as a string but every read or write access will convert length to an integer. The constructor `str` will be called when writing a value to the field and `int` will be called on read. 3. `'new name'` will be stored as is inside `d`'s data dictionary. 4 `'12'` will be converted to `12` before adding `3` to it, the subsequent write operation will convert `15` to the string `'15'` again. IMPORTANT: Currently we assume that calling the conversion functions for a field will not result in any side effects. IMPORTANT: While it is ok to extend the available field types by inheritance the *type annotations* still need to refer to one of the provided field types, because they need to be analyzed by the metaclass. """ _fields: dict[str, type] # only here for type checkers attributes: AttributesDescriptor = AttributesDescriptor() def __init__(self, data: dict[str, Attribute]) -> None: self.data = data
[docs] def get_missing_required_fields(self) -> dict[str, type]: missing: dict[str, type] = {} for name, _type in self._fields.items(): if name not in self.data: missing[name] = _type return missing
[docs] def __repr__(self) -> str: return f"{self.__module__}.{self.__class__.__qualname__}({self.data})"
[docs] def __eq__(self, o: object) -> bool: if self is o: return True if hasattr(o, "data"): return o.data == self.data return False
[docs] def ir_data_class(cls) -> Callable[[dict[str, Attribute]], IrData]: return type(cls.__name__, (cls, IrData), {})