From 003f6b234e206ff693559ae8db0586bcad6b8d31 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 17 Jul 2023 14:25:35 +0000 Subject: [PATCH] add example of object ref with createmodel --- examples/test_refs2.py | 75 +++++++++++++++++++++++ src/ibek/globals.py | 1 - tests/samples/pydantic/test.ibek.ioc.yaml | 2 +- 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 examples/test_refs2.py diff --git a/examples/test_refs2.py b/examples/test_refs2.py new file mode 100644 index 000000000..58fcae6af --- /dev/null +++ b/examples/test_refs2.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from typing import Dict, List, Optional + +from pydantic import ( + BaseModel, + ConfigDict, + Field, + create_model, + field_validator, + model_validator, +) + +id_to_entity: Dict[str, Entity] = {} + + +class Entity(BaseModel): + name: str = Field(..., description="The name of this entity") + value: str = Field(..., description="The value of this entity") + ref: Optional[str] = Field( + default=None, description="Reference another Entity name" + ) + model_config = ConfigDict(extra="forbid") + + @model_validator(mode="after") # type: ignore + def add_ibek_attributes(cls, entity: Entity): + id_to_entity[entity.name] = entity + + return entity + + +@field_validator("ref", mode="after") +def lookup_instance(cls, id): + try: + return id_to_entity[id] + except KeyError: + raise KeyError(f"object {id} not found in {list(id_to_entity)}") + + +validators = {"Entity": lookup_instance} + +# add validator to the Entity class using create model +Entity2 = create_model( + "Entity", + __validators__=validators, + __base__=Entity, +) # type: ignore + +args = {"entities": (List[Entity2], None)} +Entities = create_model( + "Entities", **args, __config__=ConfigDict(extra="forbid") +) # type: ignore + + +model1 = Entities( + **{ + "entities": [ + {"name": "one", "value": "OneValue"}, + {"name": "two", "value": "TwoValue", "ref": "one"}, + ] + } +) + +# demonstrate that entity one has a reference to entity two +assert model1.entities[1].ref.value == "OneValue" + +# this should throw an error because entity one has illegal arguments +model2 = Entities( + **{ + "entities": [ + {"name": "one", "value": "OneValue", "illegal": "bad argument"}, + {"name": "two", "value": "TwoValue", "ref": "one"}, + ] + } +) diff --git a/src/ibek/globals.py b/src/ibek/globals.py index aae9fa551..11992837d 100644 --- a/src/ibek/globals.py +++ b/src/ibek/globals.py @@ -14,7 +14,6 @@ class BaseSettings(BaseModel): """A Base class for setting consistent Pydantic model configuration""" model_config = ConfigDict( - arbitrary_types_allowed=True, extra="forbid", ) diff --git a/tests/samples/pydantic/test.ibek.ioc.yaml b/tests/samples/pydantic/test.ibek.ioc.yaml index 51bbeb2f9..398bc42bc 100644 --- a/tests/samples/pydantic/test.ibek.ioc.yaml +++ b/tests/samples/pydantic/test.ibek.ioc.yaml @@ -12,7 +12,7 @@ entities: - type: pydantic_test.AnAsynPort name: AsynPort2 - IP: 10.0.0.2 + IPpp: 10.0.0.2 - type: pydantic_test.Consumer name: A Consumer