Skip to content

Commit

Permalink
add TODO comments on existing issues
Browse files Browse the repository at this point in the history
  • Loading branch information
gilesknap committed Jul 12, 2023
1 parent d5dde2d commit c2cca52
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 32 deletions.
31 changes: 19 additions & 12 deletions src/ibek/ioc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
from typing import Any, Dict, Literal, Sequence, Tuple, Type, Union

from jinja2 import Template
from pydantic import Field, create_model, field_validator
from pydantic import Field, create_model, field_validator, model_validator
from pydantic.fields import FieldInfo

from .globals import BaseSettings
from .globals import BaseSettings, model_config
from .support import Definition, IdArg, ObjectArg, Support
from .utils import UTILS

Expand All @@ -34,15 +34,21 @@ class Entity(BaseSettings):
description="enable or disable this entity instance", default=True
)

# @model_validator(mode="before") # type: ignore
@model_validator(mode="before") # type: ignore
def add_ibek_attributes(cls, entity: Dict):
"""Add attributes used by ibek"""

# add in the global __utils__ object for state sharing
entity["__utils__"] = UTILS
# TODO need to convince pydantic to add this to the class without
# complaining about __ prefix - or use another approach to pass
# the __utils__ object to every jinja template
# entity["__utils__"] = UTILS

# copy 'values' from the definition into the Entity

# TODO this is not literally the Entity Object but a Dictionary of
# its attributes. So need a new approach for linking back to the
# definition and copying in the values out.
# if hasattr(entity, "__definition__"):
# entity.update(entity.__definition__.values)

Expand All @@ -64,16 +70,16 @@ def make_entity_model(definition: Definition, support: Support) -> Type[Entity]:
See :ref:`entities`
"""

def add_entity(name, typ, description, default):
entities[name] = (
def add_arg(name, typ, description, default):
arguments[name] = (
typ,
FieldInfo(
description=description,
default=default,
),
)

entities: Dict[str, Tuple[type, Any]] = {}
arguments: Dict[str, Tuple[type, Any]] = {}
validators: Dict[str, Any] = {}

# fully qualified name of the Entity class including support module
Expand Down Expand Up @@ -102,7 +108,7 @@ def save_instance(cls, id):
if id in id_to_entity:
# TODO we are getting multiple registers of same Arg
pass # raise KeyError(f"id {id} already defined in {list(id_to_entity)}")
id_to_entity[id] = cls
id_to_entity[id] = "test_sub_object"
return id

validators[full_arg_name] = save_instance
Expand All @@ -113,16 +119,17 @@ def save_instance(cls, id):
arg_type = getattr(builtins, arg.type)

default = getattr(arg, "default", None)
add_entity(arg.name, arg_type, arg.description, default)
add_arg(arg.name, arg_type, arg.description, default)

typ = Literal[full_name] # type: ignore
add_entity("type", typ, "The type of this entity", full_name)
add_arg("type", typ, "The type of this entity", full_name)

entity_cls = create_model(
full_name.replace(".", "_"),
**entities,
**arguments,
__validators__=validators,
# __base__=Entity,
__base__=Entity
# __config__=model_config, NOTE: either set config or inherit with __base__
) # type: ignore

# add a link back to the Definition Object that generated this Entity Class
Expand Down
48 changes: 48 additions & 0 deletions tests/samples/pydantic/test.ibek.ioc.schema.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
{
"$defs": {
"pydantic_test_AnAsynPort": {
"additionalProperties": false,
"properties": {
"entity_enabled": {
"default": true,
"description": "enable or disable this entity instance",
"title": "Entity Enabled",
"type": "boolean"
},
"name": {
"default": null,
"description": "Asyn port name",
Expand All @@ -25,7 +32,14 @@
"type": "object"
},
"pydantic_test_Consumer": {
"additionalProperties": false,
"properties": {
"entity_enabled": {
"default": true,
"description": "enable or disable this entity instance",
"title": "Entity Enabled",
"type": "boolean"
},
"name": {
"default": null,
"description": "Consumer name",
Expand All @@ -47,6 +61,37 @@
},
"title": "pydantic_test_Consumer",
"type": "object"
},
"pydantic_test_ConsumerTwo": {
"additionalProperties": false,
"properties": {
"entity_enabled": {
"default": true,
"description": "enable or disable this entity instance",
"title": "Entity Enabled",
"type": "boolean"
},
"name": {
"default": null,
"description": "Consumer name",
"title": "Name",
"type": "string"
},
"PORT": {
"default": null,
"description": "a reference to an AnAsynPort",
"title": "Port",
"type": "string"
},
"type": {
"const": "pydantic_test.ConsumerTwo",
"default": "pydantic_test.ConsumerTwo",
"description": "The type of this entity",
"title": "Type"
}
},
"title": "pydantic_test_ConsumerTwo",
"type": "object"
}
},
"additionalProperties": false,
Expand Down Expand Up @@ -76,6 +121,9 @@
},
{
"$ref": "#/$defs/pydantic_test_Consumer"
},
{
"$ref": "#/$defs/pydantic_test_ConsumerTwo"
}
]
},
Expand Down
26 changes: 17 additions & 9 deletions tests/samples/pydantic/test.ibek.ioc.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# yaml-language-server: $schema=/tmp/pydantic_test/test.ibek.ioc.schema.json
# yaml-language-server: $schema=/scratch/hgv27681/work/ibek/tests/samples/pydantic/test.ibek.support.yaml

ioc_name: test-pydantic-ioc
description: a basic example for testing ioc-template
Expand All @@ -9,14 +9,22 @@ entities:
name: AsynPort
IP: 10.0.0.1

# - type: pydantic_test.AnAsynPort
# name: AsynPort2
# IP: 10.0.0.1

- type: pydantic_test.Consumer
name: A Consumer
PORT: AsynPort
- type: pydantic_test.AnAsynPort
name: AsynPort2
IP: 10.0.0.1

# - type: pydantic_test.Consumer
# name: Another Consumer of same port
# name: A Consumer
# PORT: AsynPort

- type: pydantic_test.Consumer
name: Another Consumer of same port
PORT: AsynPort2

- type: pydantic_test.ConsumerTwo
name: Yet Another Consumer of same port
PORT: AsynPort2

- type: pydantic_test.ConsumerTwo
name: Just One More Consumer of same port
PORT: AsynPort2
35 changes: 24 additions & 11 deletions tests/samples/pydantic/test.ibek.support.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,35 @@ defs:

- name: Consumer
description: |
An object that uses AnAsynPort
A class that uses AnAsynPort
args:
- type: id
name: name
description: Consumer name

- type: object
- type: str
name: PORT
description: a reference to an AnAsynPort

- name: ConsumerTwo
description: |
Another class that uses AnAsynPort
args:
- type: id
name: name
description: Consumer name

- type: str
name: PORT
description: a reference to an AnAsynPort

pre_init:
- type: function
name: exampleTestFunction
args:
AsynPortIP: "{{ PORT.IP }}"
Name: "{{ name }}"
header: |
A function that uses the AsynPortIP and Name
to do something useful
# pre_init:
# - type: function
# name: exampleTestFunction
# args:
# AsynPortIP: "{{ PORT.IP }}"
# Name: "{{ name }}"
# Value: "{{ PORT.test_value }}"
# header: |
# A function that uses the AsynPortIP and Name
# to do something useful

0 comments on commit c2cca52

Please sign in to comment.