Codegen: move class synth decorators to pragmas

This commit is contained in:
Paolo Tranquilli
2024-09-20 10:29:40 +02:00
parent 9d6ee09f65
commit db00cb6827
7 changed files with 40 additions and 35 deletions

View File

@@ -93,8 +93,6 @@ class Class:
properties: List[Property] = field(default_factory=list) properties: List[Property] = field(default_factory=list)
group: str = "" group: str = ""
pragmas: List[str] | Dict[str, object] = field(default_factory=dict) pragmas: List[str] | Dict[str, object] = field(default_factory=dict)
synth: Optional[Union[SynthInfo, bool]] = None
"""^^^ filled with `True` for non-final classes with only synthesized final descendants """
doc: List[str] = field(default_factory=list) doc: List[str] = field(default_factory=list)
hideable: bool = False hideable: bool = False
test_with: Optional[str] = None test_with: Optional[str] = None
@@ -114,13 +112,21 @@ class Class:
_check_type(d, known) _check_type(d, known)
for p in self.properties: for p in self.properties:
_check_type(p.type, known) _check_type(p.type, known)
if self.synth is not None: if "synth" in self.pragmas:
_check_type(self.synth.from_class, known) synth = self.pragmas["synth"]
if self.synth.on_arguments is not None: _check_type(synth.from_class, known)
for t in self.synth.on_arguments.values(): if synth.on_arguments is not None:
for t in synth.on_arguments.values():
_check_type(t, known) _check_type(t, known)
_check_type(self.test_with, known) _check_type(self.test_with, known)
@property
def synth(self) -> SynthInfo | bool | None:
return self.pragmas.get("synth")
def mark_synth(self):
self.pragmas.setdefault("synth", True)
@dataclass @dataclass
class Schema: class Schema:

View File

@@ -67,9 +67,9 @@ class _Namespace:
""" simple namespacing mechanism """ """ simple namespacing mechanism """
name: str name: str
def add(self, pragma: "_PragmaBase"): def add(self, pragma: "_PragmaBase", key: str | None = None):
self.__dict__[pragma.pragma] = pragma self.__dict__[pragma.pragma] = pragma
pragma.pragma = f"{self.name}_{pragma.pragma}" pragma.pragma = key or f"{self.name}_{pragma.pragma}"
@_dataclass @_dataclass
@@ -142,7 +142,7 @@ class _ParametrizedClassPragma(_PragmaBase):
""" """
_pragma_class: _ClassVar[type] = _ClassPragma _pragma_class: _ClassVar[type] = _ClassPragma
function: _Callable[[...], object] = None function: _Callable[..., object] = None
def __post_init__(self): def __post_init__(self):
self.__signature__ = _inspect.signature(self.function).replace(return_annotation=self._pragma_class) self.__signature__ = _inspect.signature(self.function).replace(return_annotation=self._pragma_class)
@@ -248,10 +248,10 @@ def group(name: str = "") -> _ClassDecorator:
return _annotate(group=name) return _annotate(group=name)
synth.from_class = lambda ref: _annotate(synth=_schema.SynthInfo( synth.add(_ParametrizedClassPragma("from_class", lambda ref: _schema.SynthInfo(
from_class=_schema.get_type_name(ref))) from_class=_schema.get_type_name(ref))), key="synth")
synth.on_arguments = lambda **kwargs: _annotate( synth.add(_ParametrizedClassPragma("on_arguments", lambda **kwargs:
synth=_schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})) _schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})), key="synth")
class _PropertyModifierList(_schema.PropertyModifier): class _PropertyModifierList(_schema.PropertyModifier):

View File

@@ -50,7 +50,6 @@ def _get_class(cls: type) -> schema.Class:
test_with=_get_name(getattr(cls, "_test_with", None)), test_with=_get_name(getattr(cls, "_test_with", None)),
# in the following we don't use `getattr` to avoid inheriting # in the following we don't use `getattr` to avoid inheriting
pragmas=cls.__dict__.get("_pragmas", {}), pragmas=cls.__dict__.get("_pragmas", {}),
synth=cls.__dict__.get("_synth", None),
properties=[ properties=[
a | _PropertyNamer(n) a | _PropertyNamer(n)
for n, a in cls.__dict__.get("__annotations__", {}).items() for n, a in cls.__dict__.get("__annotations__", {}).items()
@@ -100,8 +99,8 @@ def _fill_synth_information(classes: typing.Dict[str, schema.Class]):
fill_is_synth(root) fill_is_synth(root)
for name, cls in classes.items(): for name, cls in classes.items():
if cls.synth is None and is_synth[name]: if is_synth[name]:
cls.synth = True cls.mark_synth()
def _fill_hideable_information(classes: typing.Dict[str, schema.Class]): def _fill_hideable_information(classes: typing.Dict[str, schema.Class]):

View File

@@ -185,15 +185,15 @@ def test_synth_classes_ignored(generate):
assert generate([ assert generate([
schema.Class( schema.Class(
name="W", name="W",
synth=schema.SynthInfo(), pragmas={"synth": schema.SynthInfo()},
), ),
schema.Class( schema.Class(
name="X", name="X",
synth=schema.SynthInfo(from_class="A"), pragmas={"synth": schema.SynthInfo(from_class="A")},
), ),
schema.Class( schema.Class(
name="Y", name="Y",
synth=schema.SynthInfo(on_arguments={"a": "A", "b": "int"}), pragmas={"synth": schema.SynthInfo(on_arguments={"a": "A", "b": "int"})},
), ),
schema.Class( schema.Class(
name="Z", name="Z",

View File

@@ -536,9 +536,9 @@ def test_null_class(generate):
def test_synth_classes_ignored(generate): def test_synth_classes_ignored(generate):
assert generate([ assert generate([
schema.Class(name="A", synth=schema.SynthInfo()), schema.Class(name="A", pragmas={"synth": schema.SynthInfo()}),
schema.Class(name="B", synth=schema.SynthInfo(from_class="A")), schema.Class(name="B", pragmas={"synth": schema.SynthInfo(from_class="A")}),
schema.Class(name="C", synth=schema.SynthInfo(on_arguments={"x": "A"})), schema.Class(name="C", pragmas={"synth": schema.SynthInfo(on_arguments={"x": "A"})}),
]) == dbscheme.Scheme( ]) == dbscheme.Scheme(
src=schema_file.name, src=schema_file.name,
includes=[], includes=[],
@@ -549,7 +549,7 @@ def test_synth_classes_ignored(generate):
def test_synth_derived_classes_ignored(generate): def test_synth_derived_classes_ignored(generate):
assert generate([ assert generate([
schema.Class(name="A", derived={"B", "C"}), schema.Class(name="A", derived={"B", "C"}),
schema.Class(name="B", bases=["A"], synth=schema.SynthInfo()), schema.Class(name="B", bases=["A"], pragmas={"synth": schema.SynthInfo()}),
schema.Class(name="C", bases=["A"]), schema.Class(name="C", bases=["A"]),
]) == dbscheme.Scheme( ]) == dbscheme.Scheme(
src=schema_file.name, src=schema_file.name,

View File

@@ -937,7 +937,7 @@ def test_property_on_class_with_default_doc_name(generate_classes):
def test_stub_on_class_with_synth_from_class(generate_classes): def test_stub_on_class_with_synth_from_class(generate_classes):
assert generate_classes([ assert generate_classes([
schema.Class("MyObject", synth=schema.SynthInfo(from_class="A"), schema.Class("MyObject", pragmas={"synth": schema.SynthInfo(from_class="A")},
properties=[schema.SingleProperty("foo", "bar")]), properties=[schema.SingleProperty("foo", "bar")]),
]) == { ]) == {
"MyObject.qll": (a_ql_class_public(name="MyObject"), a_ql_stub(name="MyObject", synth_accessors=[ "MyObject.qll": (a_ql_class_public(name="MyObject"), a_ql_stub(name="MyObject", synth_accessors=[
@@ -952,7 +952,7 @@ def test_stub_on_class_with_synth_from_class(generate_classes):
def test_stub_on_class_with_synth_on_arguments(generate_classes): def test_stub_on_class_with_synth_on_arguments(generate_classes):
assert generate_classes([ assert generate_classes([
schema.Class("MyObject", synth=schema.SynthInfo(on_arguments={"base": "A", "index": "int", "label": "string"}), schema.Class("MyObject", pragmas={"synth": schema.SynthInfo(on_arguments={"base": "A", "index": "int", "label": "string"})},
properties=[schema.SingleProperty("foo", "bar")]), properties=[schema.SingleProperty("foo", "bar")]),
]) == { ]) == {
"MyObject.qll": (a_ql_class_public(name="MyObject"), a_ql_stub(name="MyObject", synth_accessors=[ "MyObject.qll": (a_ql_class_public(name="MyObject"), a_ql_stub(name="MyObject", synth_accessors=[

View File

@@ -355,8 +355,8 @@ def test_synth_from_class():
pass pass
assert data.classes == { assert data.classes == {
'A': schema.Class('A', derived={'B'}, synth=True), 'A': schema.Class('A', derived={'B'}, pragmas={"synth": True}),
'B': schema.Class('B', bases=['A'], synth=schema.SynthInfo(from_class="A")), 'B': schema.Class('B', bases=['A'], pragmas={"synth": schema.SynthInfo(from_class="A")}),
} }
@@ -371,7 +371,7 @@ def test_synth_from_class_ref():
pass pass
assert data.classes == { assert data.classes == {
'A': schema.Class('A', derived={'B'}, synth=schema.SynthInfo(from_class="B")), 'A': schema.Class('A', derived={'B'}, pragmas={"synth": schema.SynthInfo(from_class="B")}),
'B': schema.Class('B', bases=['A']), 'B': schema.Class('B', bases=['A']),
} }
@@ -396,8 +396,8 @@ def test_synth_class_on():
pass pass
assert data.classes == { assert data.classes == {
'A': schema.Class('A', derived={'B'}, synth=True), 'A': schema.Class('A', derived={'B'}, pragmas={"synth": True}),
'B': schema.Class('B', bases=['A'], synth=schema.SynthInfo(on_arguments={'a': 'A', 'i': 'int'})), 'B': schema.Class('B', bases=['A'], pragmas={"synth": schema.SynthInfo(on_arguments={'a': 'A', 'i': 'int'})}),
} }
@@ -415,7 +415,7 @@ def test_synth_class_on_ref():
pass pass
assert data.classes == { assert data.classes == {
'A': schema.Class('A', derived={'B'}, synth=schema.SynthInfo(on_arguments={'b': 'B', 'i': 'int'})), 'A': schema.Class('A', derived={'B'}, pragmas={"synth": schema.SynthInfo(on_arguments={'b': 'B', 'i': 'int'})}),
'B': schema.Class('B', bases=['A']), 'B': schema.Class('B', bases=['A']),
} }
@@ -454,10 +454,10 @@ def test_synth_class_hierarchy():
assert data.classes == { assert data.classes == {
'Root': schema.Class('Root', derived={'Base', 'C'}), 'Root': schema.Class('Root', derived={'Base', 'C'}),
'Base': schema.Class('Base', bases=['Root'], derived={'Intermediate', 'B'}, synth=True), 'Base': schema.Class('Base', bases=['Root'], derived={'Intermediate', 'B'}, pragmas={"synth": True}),
'Intermediate': schema.Class('Intermediate', bases=['Base'], derived={'A'}, synth=True), 'Intermediate': schema.Class('Intermediate', bases=['Base'], derived={'A'}, pragmas={"synth": True}),
'A': schema.Class('A', bases=['Intermediate'], synth=schema.SynthInfo(on_arguments={'a': 'Base', 'i': 'int'})), 'A': schema.Class('A', bases=['Intermediate'], pragmas={"synth": schema.SynthInfo(on_arguments={'a': 'Base', 'i': 'int'})}),
'B': schema.Class('B', bases=['Base'], synth=schema.SynthInfo(from_class='Base')), 'B': schema.Class('B', bases=['Base'], pragmas={"synth": schema.SynthInfo(from_class='Base')}),
'C': schema.Class('C', bases=['Root']), 'C': schema.Class('C', bases=['Root']),
} }