From df0d471d6f6ca66bdba48f17ec21f5f267178b6b Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Tue, 11 Jul 2023 09:19:25 +0000 Subject: [PATCH 01/30] switched Support to Pydantic2 (intermediate breaking change) --- src/ibek/__main__.py | 28 +- src/ibek/globals.py | 16 +- src/ibek/support.py | 183 ++-- tests/samples/schemas/ibek.defs.schema.json | 873 ++++++++++++-------- 4 files changed, 619 insertions(+), 481 deletions(-) diff --git a/src/ibek/__main__.py b/src/ibek/__main__.py index 62bf56324..4ec8e46fb 100644 --- a/src/ibek/__main__.py +++ b/src/ibek/__main__.py @@ -1,14 +1,11 @@ import json from pathlib import Path -from typing import Any, List, Mapping, Optional +from typing import List, Optional -import jsonschema import typer -from apischema.json_schema import JsonSchemaVersion, deserialization_schema from ruamel.yaml import YAML -from ibek import __version__ - +from ._version import __version__ from .gen_scripts import create_boot_script, create_db_script, ioc_deserialize from .ioc import IOC, make_entity_classes from .support import Support @@ -17,10 +14,6 @@ yaml = YAML() -def make_schema(cls: type) -> Mapping[str, Any]: - return deserialization_schema(cls, version=JsonSchemaVersion.DRAFT_7) - - def version_callback(value: bool): if value: typer.echo(__version__) @@ -45,8 +38,7 @@ def ibek_schema( output: Path = typer.Argument(..., help="The filename to write the schema to") ): """Produce JSON global schema for all .ibek.support.yaml files""" - schema = json.dumps(make_schema(Support), indent=2) - output.write_text(schema) + output.write_text(Support.get_schema()) @cli.command() @@ -61,18 +53,20 @@ def ioc_schema( Create a json schema from a .ibek.support.yaml file """ - # first check the definition file with jsonschema since it has more - # legible error messages than apischema for definition in definitions: support_dict = YAML(typ="safe").load(definition) if not no_schema: - schema_support = make_schema(Support) - jsonschema.validate(support_dict, schema_support) + # Verify the schema of the support module definition file + Support.model_validate(support_dict) - support = Support.deserialize(support_dict) + # deserialize the support module definition file + support = Support(**support_dict) + # make Entity classes described in the support module definition file make_entity_classes(support) - schema = json.dumps(make_schema(IOC), indent=2) + # Save the schema for IOC - it will include all subclasses of Entity + # that were created in the global namespace by make_entity_classes + schema = json.dumps(IOC.model_json_schema(), indent=2) output.write_text(schema) diff --git a/src/ibek/globals.py b/src/ibek/globals.py index bb4b7e6cf..6a71c1514 100644 --- a/src/ibek/globals.py +++ b/src/ibek/globals.py @@ -1,9 +1,9 @@ """ -A few global defintions +A few global definitions """ from typing import TypeVar -from apischema import schema +from pydantic import BaseModel, ConfigDict, Field #: A generic Type for use in type hints T = TypeVar("T") @@ -11,4 +11,14 @@ def desc(description: str): """a description Annotation to add to our Entity derived Types""" - return schema(description=description) + return Field(description=description) + + +class BaseSettings(BaseModel): + """A Base class for setting Pydantic model configuration""" + + # Pydantic model configuration + model_config = ConfigDict( + # arbitrary_types_allowed=True, + extra="forbid", + ) diff --git a/src/ibek/support.py b/src/ibek/support.py index d8f4548bb..f84680bcb 100644 --- a/src/ibek/support.py +++ b/src/ibek/support.py @@ -1,19 +1,16 @@ """ The Support Class represents a deserialized .ibek.support.yaml file. -It contains a hierarchy of Entity dataclasses. """ from __future__ import annotations -from dataclasses import dataclass +import json from enum import Enum -from typing import Any, Dict, Mapping, Optional, Sequence, Type, Union +from typing import Any, Dict, Optional, Sequence, Union -from apischema import Undefined, UndefinedType, deserialize, deserializer, identity -from apischema.conversions import Conversion -from typing_extensions import Annotated as A +from pydantic import Field from typing_extensions import Literal -from .globals import T, desc +from .globals import BaseSettings class When(Enum): @@ -22,25 +19,17 @@ class When(Enum): last = "last" -@dataclass -class Arg: +class Arg(BaseSettings): """Base class for all Argument Types""" - name: A[str, desc("Name of the argument that the IOC instance should pass")] - description: A[str, desc("Description of what the argument will be used for")] type: str - default: Any - - # https://wyfo.github.io/apischema/latest/examples/subclass_union/ - def __init_subclass__(cls): - # Deserializers stack directly as a Union - deserializer(Conversion(identity, source=cls, target=Arg)) - - -Default = A[ - Union[Optional[T], UndefinedType], - desc("If given, and instance doesn't supply argument, what value should be used"), -] + name: str = Field( + description="Name of the argument that the IOC instance should pass" + ) + description: str = Field( + description="Description of what the argument will be used for" + ) + # __discriminator__ = "type" # FloatArg must be defined before StrArg, otherwise we get: @@ -52,96 +41,90 @@ def __init_subclass__(cls): # Arg. When StrArg is before FloatArg, apischema attempts to deserialize as a # string first. The coercion from str to number requires a trailing f if there # is a decimal. -@dataclass class FloatArg(Arg): """An argument with a float value""" type: Literal["float"] = "float" - default: Default[float] = Undefined + default: Optional[float] = None -@dataclass class StrArg(Arg): """An argument with a str value""" type: Literal["str"] = "str" - default: Default[str] = Undefined + default: Optional[str] = None -@dataclass class IntArg(Arg): """An argument with an int value""" type: Literal["int"] = "int" - default: Default[int] = Undefined + default: Optional[int] = None -@dataclass class BoolArg(Arg): """An argument with an bool value""" type: Literal["bool"] = "bool" - default: Default[bool] = Undefined + default: Optional[bool] = None -@dataclass class ObjectArg(Arg): """A reference to another entity defined in this IOC""" type: Literal["object"] = "object" - default: Default[str] = Undefined + default: Optional[str] = None -@dataclass class IdArg(Arg): """Explicit ID argument that an object can refer to""" type: Literal["id"] = "id" - default: Default[str] = Undefined + default: Optional[str] = None -@dataclass -class Database: +class Database(BaseSettings): """ A database file that should be loaded by the startup script and its args """ - file: A[str, desc("Filename of the database template in /db")] - args: A[ - Dict[str, Optional[str]], - desc( + file: str = Field( + description="Filename of the database template in /db" + ) + + args: Dict[str, Optional[str]] = Field( + description=( "Dictionary of args and values to pass through to database. " "A value of None is equivalent to ARG: '{{ ARG }}'" - ), - ] + ) + ) -@dataclass -class EnvironmentVariable: +class EnvironmentVariable(BaseSettings): """ An environment variable that should be set in the startup script """ - name: A[str, desc("Name of environment variable")] - value: A[str, desc("Value to set")] + name: str = Field(description="Name of environment variable") + value: str = Field(description="Value to set") -@dataclass -class Function: +class Function(BaseSettings): """ A script snippet that defines a function to call """ - name: A[str, desc("Name of the function to call")] - args: A[Dict[str, Any], desc("The arguments to pass to the function")] - header: A[str, desc("commands/comments to appear before the function")] = "" + name: str = Field(description="Name of the function to call") + args: Dict[str, Any] = Field(description="The arguments to pass to the function") + header: str = Field( + description="commands/comments to appear before the function", default="" + ) # TODO will be an enum - when: A[str, desc("one of first / every / last")] = "every" + when: When = Field(description="one of first / every / last", default="every") type: Literal["function"] = "function" -@dataclass -class Comment: +class Comment(BaseSettings): """ A script snippet that will have '# ' prepended to every line for insertion into the startup script @@ -149,29 +132,31 @@ class Comment: type: Literal["comment"] = "comment" # TODO will be an enum - when: A[str, desc("One of first / every / last")] = "every" - value: A[str, desc("A comment to add into the startup script")] = "" + when: When = Field(description="One of first / every / last", default="every") + value: str = Field( + description="A comment to add into the startup script", default="" + ) -@dataclass -class Text: +class Text(BaseSettings): """ A script snippet to insert into the startup script """ type: Literal["text"] = "text" # TODO will be an enum - when: A[str, desc("One of first / every / last")] = "every" - value: A[str, desc("raw text to add to the startup script")] = "" + when: str = Field(description="One of first / every / last", default="every") + value: str = Field(description="raw text to add to the startup script", default="") -@dataclass -class Value: +class Value(BaseSettings): """A calculated string value for a definition""" - name: A[str, desc("Name of the value that the IOC instance will expose")] - description: A[str, desc("Description of what the value will be used for")] - value: A[str, desc("The contents of the value")] + name: str = Field(description="Name of the value that the IOC instance will expose") + description: str = Field( + description="Description of what the value will be used for" + ) + value: str = Field(description="The contents of the value") def __str__(self): return self.value @@ -180,45 +165,51 @@ def __str__(self): Script = Sequence[Union[Function, Comment, Text]] -@dataclass -class Definition: +class Definition(BaseSettings): """ A single definition of a class of Entity that an IOC instance may instantiate """ - name: A[str, desc("Publish Definition as type . for IOC instances")] - description: A[str, desc("Describes the purpose of the definition")] - args: A[Sequence[Arg], desc("The arguments IOC instance should supply")] = () - values: A[Sequence[Value], desc("The values IOC instance should supply")] = () - databases: A[Sequence[Database], desc("Databases to instantiate")] = () - pre_init: A[ - Script, - desc("Startup script snippets to add before iocInit()"), - ] = () - post_init: A[ - Script, - desc("Startup script snippets to add post iocInit(), such as dbpf"), - ] = () - env_vars: A[ - Sequence[EnvironmentVariable], - desc("Environment variables to set in the boot script"), - ] = () - - -@dataclass -class Support: + name: str = Field( + description="Publish Definition as type . for IOC instances" + ) + description: str = Field( + description="A description of the Support module defined here" + ) + # declare Arg as Union of its subclasses for Pydantic to be able to deserialize + args: Sequence[Union[tuple(Arg.__subclasses__())]] = Field( # type: ignore + description="The arguments IOC instance should supply", default=() + ) + values: Sequence[Value] = Field( + description="The values IOC instance should supply", default=() + ) + databases: Sequence[Database] = Field( + description="Databases to instantiate", default=() + ) + pre_init: Script = Field( + description="Startup script snippets to add before iocInit()", default=() + ) + post_init: Script = Field( + description="Startup script snippets to add post iocInit(), such as dbpf", + default=(), + ) + env_vars: Sequence[EnvironmentVariable] = Field( + description="Environment variables to set in the boot script", default=() + ) + + +class Support(BaseSettings): """ Lists the definitions for a support module, this defines what Entities it supports Provides the deserialize entry point. """ - module: A[str, desc("Support module name, normally the repo name")] - defs: A[ - Sequence[Definition], - desc("The definitions an IOC can create using this module"), - ] + module: str = Field(description="Support module name, normally the repo name") + defs: Sequence[Definition] = Field( + description="The definitions an IOC can create using this module" + ) @classmethod - def deserialize(cls: Type[T], d: Mapping[str, Any]) -> T: - return deserialize(cls, d) + def get_schema(cls): + return json.dumps(cls.model_json_schema(), indent=2) diff --git a/tests/samples/schemas/ibek.defs.schema.json b/tests/samples/schemas/ibek.defs.schema.json index 5d46653bc..7a682fc51 100644 --- a/tests/samples/schemas/ibek.defs.schema.json +++ b/tests/samples/schemas/ibek.defs.schema.json @@ -1,419 +1,562 @@ { - "type": "object", - "properties": { - "module": { - "type": "string", - "description": "Support module name, normally the repo name" + "$defs": { + "BoolArg": { + "additionalProperties": false, + "description": "An argument with an bool value", + "properties": { + "type": { + "const": "bool", + "default": "bool", + "title": "Type" + }, + "name": { + "description": "Name of the argument that the IOC instance should pass", + "title": "Name", + "type": "string" + }, + "description": { + "description": "Description of what the argument will be used for", + "title": "Description", + "type": "string" + }, + "default": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Default" + } + }, + "required": [ + "name", + "description" + ], + "title": "BoolArg", + "type": "object" }, - "defs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Publish Definition as type . for IOC instances" + "Comment": { + "additionalProperties": false, + "description": "\n A script snippet that will have '# ' prepended to every line\n for insertion into the startup script\n ", + "properties": { + "type": { + "const": "comment", + "default": "comment", + "title": "Type" + }, + "when": { + "allOf": [ + { + "$ref": "#/$defs/When" + } + ], + "default": "every", + "description": "One of first / every / last" + }, + "value": { + "default": "", + "description": "A comment to add into the startup script", + "title": "Value", + "type": "string" + } + }, + "title": "Comment", + "type": "object" + }, + "Database": { + "additionalProperties": false, + "description": "\n A database file that should be loaded by the startup script and its args\n ", + "properties": { + "file": { + "description": "Filename of the database template in /db", + "title": "File", + "type": "string" + }, + "args": { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, - "description": { - "type": "string", - "description": "Describes the purpose of the definition" + "description": "Dictionary of args and values to pass through to database. A value of None is equivalent to ARG: '{{ ARG }}'", + "title": "Args", + "type": "object" + } + }, + "required": [ + "file", + "args" + ], + "title": "Database", + "type": "object" + }, + "Definition": { + "additionalProperties": false, + "description": "\n A single definition of a class of Entity that an IOC instance may instantiate\n ", + "properties": { + "name": { + "description": "Publish Definition as type . for IOC instances", + "title": "Name", + "type": "string" + }, + "description": { + "description": "A description of the Support module defined here", + "title": "Description", + "type": "string" + }, + "args": { + "default": [], + "description": "The arguments IOC instance should supply", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/FloatArg" + }, + { + "$ref": "#/$defs/StrArg" + }, + { + "$ref": "#/$defs/IntArg" + }, + { + "$ref": "#/$defs/BoolArg" + }, + { + "$ref": "#/$defs/ObjectArg" + }, + { + "$ref": "#/$defs/IdArg" + } + ] }, - "args": { - "type": "array", - "items": { - "anyOf": [ - { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the argument that the IOC instance should pass" - }, - "description": { - "type": "string", - "description": "Description of what the argument will be used for" - }, - "type": { - "type": "string", - "const": "float", - "default": "float" - }, - "default": { - "type": [ - "number", - "null" - ], - "description": "If given, and instance doesn't supply argument, what value should be used" - } - }, - "required": [ - "name", - "description" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the argument that the IOC instance should pass" - }, - "description": { - "type": "string", - "description": "Description of what the argument will be used for" - }, - "type": { - "type": "string", - "const": "str", - "default": "str" - }, - "default": { - "type": [ - "string", - "null" - ], - "description": "If given, and instance doesn't supply argument, what value should be used" - } - }, - "required": [ - "name", - "description" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the argument that the IOC instance should pass" - }, - "description": { - "type": "string", - "description": "Description of what the argument will be used for" - }, - "type": { - "type": "string", - "const": "int", - "default": "int" - }, - "default": { - "type": [ - "integer", - "null" - ], - "description": "If given, and instance doesn't supply argument, what value should be used" - } - }, - "required": [ - "name", - "description" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the argument that the IOC instance should pass" - }, - "description": { - "type": "string", - "description": "Description of what the argument will be used for" - }, - "type": { - "type": "string", - "const": "bool", - "default": "bool" - }, - "default": { - "type": [ - "boolean", - "null" - ], - "description": "If given, and instance doesn't supply argument, what value should be used" - } - }, - "required": [ - "name", - "description" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the argument that the IOC instance should pass" - }, - "description": { - "type": "string", - "description": "Description of what the argument will be used for" - }, - "type": { - "type": "string", - "const": "object", - "default": "object" - }, - "default": { - "type": [ - "string", - "null" - ], - "description": "If given, and instance doesn't supply argument, what value should be used" - } - }, - "required": [ - "name", - "description" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the argument that the IOC instance should pass" - }, - "description": { - "type": "string", - "description": "Description of what the argument will be used for" - }, - "type": { - "type": "string", - "const": "id", - "default": "id" - }, - "default": { - "type": [ - "string", - "null" - ], - "description": "If given, and instance doesn't supply argument, what value should be used" - } - }, - "required": [ - "name", - "description" - ], - "additionalProperties": false - } - ] - }, - "description": "The arguments IOC instance should supply", - "default": [] + "title": "Args", + "type": "array" + }, + "values": { + "default": [], + "description": "The values IOC instance should supply", + "items": { + "$ref": "#/$defs/Value" }, - "values": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the value that the IOC instance will expose" - }, - "description": { - "type": "string", - "description": "Description of what the value will be used for" - }, - "value": { - "type": "string", - "description": "The contents of the value" - } - }, - "required": [ - "name", - "description", - "value" - ], - "additionalProperties": false - }, - "description": "The values IOC instance should supply", - "default": [] + "title": "Values", + "type": "array" + }, + "databases": { + "default": [], + "description": "Databases to instantiate", + "items": { + "$ref": "#/$defs/Database" }, - "databases": { - "type": "array", - "items": { - "type": "object", - "properties": { - "file": { - "type": "string", - "description": "Filename of the database template in /db" - }, - "args": { - "type": "object", - "additionalProperties": { - "type": [ - "string", - "null" - ] - }, - "description": "Dictionary of args and values to pass through to database. A value of None is equivalent to ARG: '{{ ARG }}'" - } + "title": "Databases", + "type": "array" + }, + "pre_init": { + "default": [], + "description": "Startup script snippets to add before iocInit()", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/Function" }, - "required": [ - "file", - "args" - ], - "additionalProperties": false - }, - "description": "Databases to instantiate", - "default": [] + { + "$ref": "#/$defs/Comment" + }, + { + "$ref": "#/$defs/Text" + } + ] }, - "pre_init": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/Function" - }, - { - "$ref": "#/definitions/Comment" - }, - { - "$ref": "#/definitions/Text" - } - ] - }, - "description": "Startup script snippets to add before iocInit()", - "default": [] + "title": "Pre Init", + "type": "array" + }, + "post_init": { + "default": [], + "description": "Startup script snippets to add post iocInit(), such as dbpf", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/Function" + }, + { + "$ref": "#/$defs/Comment" + }, + { + "$ref": "#/$defs/Text" + } + ] }, - "post_init": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/Function" - }, - { - "$ref": "#/definitions/Comment" - }, - { - "$ref": "#/definitions/Text" - } - ] - }, - "description": "Startup script snippets to add post iocInit(), such as dbpf", - "default": [] + "title": "Post Init", + "type": "array" + }, + "env_vars": { + "default": [], + "description": "Environment variables to set in the boot script", + "items": { + "$ref": "#/$defs/EnvironmentVariable" }, - "env_vars": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of environment variable" - }, - "value": { - "type": "string", - "description": "Value to set" - } - }, - "required": [ - "name", - "value" - ], - "additionalProperties": false + "title": "Env Vars", + "type": "array" + } + }, + "required": [ + "name", + "description" + ], + "title": "Definition", + "type": "object" + }, + "EnvironmentVariable": { + "additionalProperties": false, + "description": "\n An environment variable that should be set in the startup script\n ", + "properties": { + "name": { + "description": "Name of environment variable", + "title": "Name", + "type": "string" + }, + "value": { + "description": "Value to set", + "title": "Value", + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "title": "EnvironmentVariable", + "type": "object" + }, + "FloatArg": { + "additionalProperties": false, + "description": "An argument with a float value", + "properties": { + "type": { + "const": "float", + "default": "float", + "title": "Type" + }, + "name": { + "description": "Name of the argument that the IOC instance should pass", + "title": "Name", + "type": "string" + }, + "description": { + "description": "Description of what the argument will be used for", + "title": "Description", + "type": "string" + }, + "default": { + "anyOf": [ + { + "type": "number" }, - "description": "Environment variables to set in the boot script", - "default": [] - } - }, - "required": [ - "name", - "description" - ], - "additionalProperties": false + { + "type": "null" + } + ], + "default": null, + "title": "Default" + } }, - "description": "The definitions an IOC can create using this module" - } - }, - "required": [ - "module", - "defs" - ], - "additionalProperties": false, - "definitions": { + "required": [ + "name", + "description" + ], + "title": "FloatArg", + "type": "object" + }, "Function": { - "type": "object", + "additionalProperties": false, + "description": "\n A script snippet that defines a function to call\n ", "properties": { "name": { - "type": "string", - "description": "Name of the function to call" + "description": "Name of the function to call", + "title": "Name", + "type": "string" }, "args": { - "type": "object", - "description": "The arguments to pass to the function" + "description": "The arguments to pass to the function", + "title": "Args", + "type": "object" }, "header": { - "type": "string", + "default": "", "description": "commands/comments to appear before the function", - "default": "" + "title": "Header", + "type": "string" }, "when": { - "type": "string", - "description": "one of first / every / last", - "default": "every" + "allOf": [ + { + "$ref": "#/$defs/When" + } + ], + "default": "every", + "description": "one of first / every / last" }, "type": { - "type": "string", "const": "function", - "default": "function" + "default": "function", + "title": "Type" } }, "required": [ "name", "args" ], - "additionalProperties": false + "title": "Function", + "type": "object" }, - "Comment": { - "type": "object", + "IdArg": { + "additionalProperties": false, + "description": "Explicit ID argument that an object can refer to", "properties": { "type": { - "type": "string", - "const": "comment", - "default": "comment" + "const": "id", + "default": "id", + "title": "Type" }, - "when": { - "type": "string", - "description": "One of first / every / last", - "default": "every" + "name": { + "description": "Name of the argument that the IOC instance should pass", + "title": "Name", + "type": "string" }, - "value": { - "type": "string", - "description": "A comment to add into the startup script", - "default": "" + "description": { + "description": "Description of what the argument will be used for", + "title": "Description", + "type": "string" + }, + "default": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Default" + } + }, + "required": [ + "name", + "description" + ], + "title": "IdArg", + "type": "object" + }, + "IntArg": { + "additionalProperties": false, + "description": "An argument with an int value", + "properties": { + "type": { + "const": "int", + "default": "int", + "title": "Type" + }, + "name": { + "description": "Name of the argument that the IOC instance should pass", + "title": "Name", + "type": "string" + }, + "description": { + "description": "Description of what the argument will be used for", + "title": "Description", + "type": "string" + }, + "default": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Default" } }, - "additionalProperties": false + "required": [ + "name", + "description" + ], + "title": "IntArg", + "type": "object" + }, + "ObjectArg": { + "additionalProperties": false, + "description": "A reference to another entity defined in this IOC", + "properties": { + "type": { + "const": "object", + "default": "object", + "title": "Type" + }, + "name": { + "description": "Name of the argument that the IOC instance should pass", + "title": "Name", + "type": "string" + }, + "description": { + "description": "Description of what the argument will be used for", + "title": "Description", + "type": "string" + }, + "default": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Default" + } + }, + "required": [ + "name", + "description" + ], + "title": "ObjectArg", + "type": "object" + }, + "StrArg": { + "additionalProperties": false, + "description": "An argument with a str value", + "properties": { + "type": { + "const": "str", + "default": "str", + "title": "Type" + }, + "name": { + "description": "Name of the argument that the IOC instance should pass", + "title": "Name", + "type": "string" + }, + "description": { + "description": "Description of what the argument will be used for", + "title": "Description", + "type": "string" + }, + "default": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Default" + } + }, + "required": [ + "name", + "description" + ], + "title": "StrArg", + "type": "object" }, "Text": { - "type": "object", + "additionalProperties": false, + "description": "\n A script snippet to insert into the startup script\n ", "properties": { "type": { - "type": "string", "const": "text", - "default": "text" + "default": "text", + "title": "Type" }, "when": { - "type": "string", + "default": "every", "description": "One of first / every / last", - "default": "every" + "title": "When", + "type": "string" }, "value": { - "type": "string", + "default": "", "description": "raw text to add to the startup script", - "default": "" + "title": "Value", + "type": "string" } }, - "additionalProperties": false + "title": "Text", + "type": "object" + }, + "Value": { + "additionalProperties": false, + "description": "A calculated string value for a definition", + "properties": { + "name": { + "description": "Name of the value that the IOC instance will expose", + "title": "Name", + "type": "string" + }, + "description": { + "description": "Description of what the value will be used for", + "title": "Description", + "type": "string" + }, + "value": { + "description": "The contents of the value", + "title": "Value", + "type": "string" + } + }, + "required": [ + "name", + "description", + "value" + ], + "title": "Value", + "type": "object" + }, + "When": { + "enum": [ + "first", + "every", + "last" + ], + "title": "When", + "type": "string" } }, - "$schema": "http://json-schema.org/draft-07/schema#" + "additionalProperties": false, + "description": "\n Lists the definitions for a support module, this defines what Entities it supports\n\n Provides the deserialize entry point.\n ", + "properties": { + "module": { + "description": "Support module name, normally the repo name", + "title": "Module", + "type": "string" + }, + "defs": { + "description": "The definitions an IOC can create using this module", + "items": { + "$ref": "#/$defs/Definition" + }, + "title": "Defs", + "type": "array" + } + }, + "required": [ + "module", + "defs" + ], + "title": "Support", + "type": "object" } \ No newline at end of file From 05879b0a5e1f48982f9e0da160b3bf36a71ef1cf Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Tue, 11 Jul 2023 11:18:09 +0000 Subject: [PATCH 02/30] first pydantic pass: ioc.py --- src/ibek/ioc.py | 178 +++++++++++++++++++++++------------------------- 1 file changed, 86 insertions(+), 92 deletions(-) diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index 3570c18e7..1c77a879e 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -5,32 +5,21 @@ from __future__ import annotations import builtins -import types -from dataclasses import Field, dataclass, field, make_dataclass -from typing import Any, Dict, List, Mapping, Sequence, Tuple, Type, cast - -from apischema import ( - Undefined, - ValidationError, - cache, - deserialize, - deserializer, - identity, - schema, -) -from apischema.conversions import Conversion, reset_deserializers -from apischema.metadata import conversion +import json +from typing import Any, Dict, Sequence, Tuple, Type, Union + from jinja2 import Template -from typing_extensions import Annotated as A +from pydantic import Field, create_model from typing_extensions import Literal -from . import modules -from .globals import T, desc +from .globals import BaseSettings, model_config from .support import Definition, IdArg, ObjectArg, Support from .utils import UTILS +# A base class for applying settings to all serializable classes + -class Entity: +class Entity(BaseSettings): """ A baseclass for all generated Entity classes. Provides the deserialize entry point. @@ -39,7 +28,9 @@ class Entity: # a link back to the Definition Object that generated this Definition __definition__: Definition - entity_enabled: bool + entity_enabled: bool = Field( + description="enable or disable this entity instance", default=True + ) def __post_init__(self: "Entity"): # If there is an argument which is an id then allow deserialization by that @@ -73,7 +64,7 @@ def __post_init__(self: "Entity"): id_to_entity: Dict[str, Entity] = {} -def make_entity_class(definition: Definition, support: Support) -> Type[Entity]: +def make_entity_model(definition: Definition, support: Support) -> Type[Entity]: """ We can get a set of Definitions by deserializing an ibek support module definition YAML file. @@ -82,107 +73,110 @@ def make_entity_class(definition: Definition, support: Support) -> Type[Entity]: See :ref:`entities` """ - fields: List[Tuple[str, type, Field[Any]]] = [] + entities: Dict[str, Tuple[type, Any]] = {} - # add in each of the arguments + # add in each of the arguments as a Field in the Entity for arg in definition.args: - # make_dataclass can cope with string types, so cast them here rather - # than lookup metadata: Any = None arg_type: Type - if isinstance(arg, ObjectArg): - def lookup_instance(id): - try: - return id_to_entity[id] - except KeyError: - raise ValidationError(f"{id} is not in {list(id_to_entity)}") - - metadata = conversion( - deserialization=Conversion(lookup_instance, str, Entity) - ) | schema(extra={"vscode_ibek_plugin_type": "type_object"}) + if isinstance(arg, ObjectArg): + pass # TODO + # def lookup_instance(id): + # try: + # return id_to_entity[id] + # except KeyError: + # raise ValidationError(f"{id} is not in {list(id_to_entity)}") + + # metadata = schema(extra={"vscode_ibek_plugin_type": "type_object"}) + # metadata = conversion( + # deserialization=Conversion(lookup_instance, str, Entity) + # ) | schema(extra={"vscode_ibek_plugin_type": "type_object"}) arg_type = Entity elif isinstance(arg, IdArg): arg_type = str - metadata = schema(extra={"vscode_ibek_plugin_type": "type_id"}) + # TODO + # metadata = schema(extra={"vscode_ibek_plugin_type": "type_id"}) else: # arg.type is str, int, float, etc. arg_type = getattr(builtins, arg.type) - if arg.description: - arg_type = A[arg_type, desc(arg.description)] # type: ignore - if arg.default is Undefined: - fld = field(metadata=metadata) - else: - fld = field(metadata=metadata, default=arg.default) - fields.append((arg.name, arg_type, fld)) # type: ignore + + default = getattr(arg, "default", None) + arg_field = Field(arg_type, description=arg.description) + + # TODO where does metadata go? + # fld = Field(arg_type) + + entities[arg.name] = (arg_type, None) # put the literal name in as 'type' for this Entity this gives us # a unique key for each of the entity types we may instantiate full_name = f"{support.module}.{definition.name}" - fields.append( - ( - "type", - Literal[full_name], # type: ignore - field(default=cast(Any, full_name)), - ) + entities["type"] = ( + Literal[full_name], # type: ignore + full_name, ) - # add a field so we can control rendering of the entity without having to delete - # it - fields.append(("entity_enabled", bool, field(default=cast(Any, True)))) - - namespace = dict(__definition__=definition) - - # make the Entity derived dataclass for this EntityClass, with a reference - # to the Definition that created it - entity_cls = make_dataclass(full_name, fields, bases=(Entity,), namespace=namespace) - deserializer(Conversion(identity, source=entity_cls, target=Entity)) + # entity_enabled controls rendering of the entity without having to delete it + entities["entity_enabled"] = (bool, True) + # add a link back to the Definition Object that generated this Definition + # TODO + # entities["__definition__"] = (Definition, None) + + entity_cls = create_model( + "definitions", + **entities, + __config__=model_config, + ) # type: ignore return entity_cls -def make_entity_classes(support: Support) -> types.SimpleNamespace: +def make_entity_models(support: Support): """Create `Entity` subclasses for all `Definition` objects in the given - `Support` instance, put them in a namespace in `ibek.modules` and return - it""" - module = types.SimpleNamespace() - assert not hasattr( - modules, support.module - ), f"Entity classes already created for {support.module}" - setattr(modules, support.module, module) - modules.__all__.append(support.module) + `Support` instance. + + Then create a Pydantic model of an IOC class with its entities field + set to a Union of all the Entity subclasses created.""" + + entity_models = [] + for definition in support.defs: - entity_cls = make_entity_class(definition, support) - setattr(module, definition.name, entity_cls) - return module + entity_models.append(make_entity_model(definition, support)) + + return entity_models def clear_entity_classes(): """Reset the modules namespaces, deserializers and caches of defined Entity subclasses""" - id_to_entity.clear() - while modules.__all__: - delattr(modules, modules.__all__.pop()) - reset_deserializers(Entity) - cache.reset() + # TODO: do we need this for Pydantic? + + +def make_ioc_model(entity_classes: Sequence[Type[Entity]]) -> str: + class NewIOC(IOC): + entities: Sequence[Union[tuple(entity_classes)]] = Field( # type: ignore + description="List of entities this IOC instantiates", default=() + ) + + return json.dumps(NewIOC.model_json_schema(), indent=2) -@dataclass -class IOC: - """ - Used to load an IOC instance entities yaml file into memory using - IOC.deserialize(YAML().load(ioc_instance_yaml)). - Before loading the entities file all Entity classes that it contains - must be defined in modules.py. This is achieved by deserializing all - support module definitions yaml files used by this IOC and calling - make_entity_classes(support_module). +class IOC(BaseSettings): """ + Used to load an IOC instance entities yaml file into memory. - ioc_name: A[str, desc("Name of IOC instance")] - description: A[str, desc("Description of what the IOC does")] - entities: A[Sequence[Entity], desc("List of entities this IOC instantiates")] - generic_ioc_image: A[str, desc("The generic IOC container image registry URL")] + This is the base class that is adjusted at runtime by updating the + type of its entities attribute to be a union of all of the subclasses of Entity + provided by the support module definitions used by the current IOC + """ - @classmethod - def deserialize(cls: Type[T], d: Mapping[str, Any]) -> T: - return deserialize(cls, d) + ioc_name: str = Field(description="Name of IOC instance") + description: str = Field(description="Description of what the IOC does") + generic_ioc_image: str = Field( + description="The generic IOC container image registry URL" + ) + # placeholder for the entities attribute - updated at runtime + entities: Sequence[Entity] = Field( + description="List of entities this IOC instantiates" + ) From 4112595db1c08fdaccb7bc802d4a8d3eb3a20a41 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Tue, 11 Jul 2023 11:56:37 +0000 Subject: [PATCH 03/30] ioc.py pydantic working except objects --- src/ibek/__main__.py | 12 +++++------ src/ibek/ioc.py | 47 +++++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/ibek/__main__.py b/src/ibek/__main__.py index 4ec8e46fb..9da3830e8 100644 --- a/src/ibek/__main__.py +++ b/src/ibek/__main__.py @@ -1,4 +1,3 @@ -import json from pathlib import Path from typing import List, Optional @@ -7,7 +6,7 @@ from ._version import __version__ from .gen_scripts import create_boot_script, create_db_script, ioc_deserialize -from .ioc import IOC, make_entity_classes +from .ioc import make_entity_models, make_ioc_model from .support import Support cli = typer.Typer() @@ -53,6 +52,8 @@ def ioc_schema( Create a json schema from a .ibek.support.yaml file """ + entity_classes = [] + for definition in definitions: support_dict = YAML(typ="safe").load(definition) if not no_schema: @@ -62,11 +63,10 @@ def ioc_schema( # deserialize the support module definition file support = Support(**support_dict) # make Entity classes described in the support module definition file - make_entity_classes(support) + entity_classes += make_entity_models(support) - # Save the schema for IOC - it will include all subclasses of Entity - # that were created in the global namespace by make_entity_classes - schema = json.dumps(IOC.model_json_schema(), indent=2) + # Save the schema for IOC + schema = make_ioc_model(entity_classes) output.write_text(schema) diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index 1c77a879e..89294ef3f 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -9,7 +9,8 @@ from typing import Any, Dict, Sequence, Tuple, Type, Union from jinja2 import Template -from pydantic import Field, create_model +from pydantic import Field, ValidationError, create_model +from pydantic.fields import FieldInfo from typing_extensions import Literal from .globals import BaseSettings, model_config @@ -73,20 +74,24 @@ def make_entity_model(definition: Definition, support: Support) -> Type[Entity]: See :ref:`entities` """ + + def add_entity(name, typ, description, default): + entities[name] = (typ, FieldInfo(description=description, default=default)) + entities: Dict[str, Tuple[type, Any]] = {} # add in each of the arguments as a Field in the Entity for arg in definition.args: - metadata: Any = None arg_type: Type if isinstance(arg, ObjectArg): - pass # TODO - # def lookup_instance(id): - # try: - # return id_to_entity[id] - # except KeyError: - # raise ValidationError(f"{id} is not in {list(id_to_entity)}") + pass + + def lookup_instance(id): + try: + return id_to_entity[id] + except KeyError: + raise ValidationError(f"{id} is not in {list(id_to_entity)}") # metadata = schema(extra={"vscode_ibek_plugin_type": "type_object"}) # metadata = conversion( @@ -95,39 +100,31 @@ def make_entity_model(definition: Definition, support: Support) -> Type[Entity]: arg_type = Entity elif isinstance(arg, IdArg): arg_type = str - # TODO # metadata = schema(extra={"vscode_ibek_plugin_type": "type_id"}) else: # arg.type is str, int, float, etc. arg_type = getattr(builtins, arg.type) default = getattr(arg, "default", None) - arg_field = Field(arg_type, description=arg.description) - - # TODO where does metadata go? - # fld = Field(arg_type) + add_entity(arg.name, arg_type, arg.description, default) - entities[arg.name] = (arg_type, None) - - # put the literal name in as 'type' for this Entity this gives us - # a unique key for each of the entity types we may instantiate + # type is a unique key for each of the entity types we may instantiate full_name = f"{support.module}.{definition.name}" - entities["type"] = ( - Literal[full_name], # type: ignore - full_name, - ) + typ = Literal[full_name] # type: ignore + add_entity("type", typ, "The type of this entity", full_name) # entity_enabled controls rendering of the entity without having to delete it - entities["entity_enabled"] = (bool, True) - # add a link back to the Definition Object that generated this Definition - # TODO - # entities["__definition__"] = (Definition, None) + add_entity("entity_enabled", bool, "enable or disable entity", True) entity_cls = create_model( "definitions", **entities, __config__=model_config, ) # type: ignore + + # add a link back to the Definition Object that generated this Entity Class + entity_cls.__definition__ = definition + return entity_cls From d5dde2dd02c75d80758946712ef9b9e7475f9447 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Wed, 12 Jul 2023 12:48:57 +0000 Subject: [PATCH 04/30] partially working id tracking --- ibek-defs | 2 +- pyproject.toml | 3 +- src/ibek/__main__.py | 27 +- src/ibek/gen_scripts.py | 42 +- src/ibek/globals.py | 21 +- src/ibek/ioc.py | 127 +- src/ibek/support.py | 3 +- tests/conftest.py | 10 +- tests/samples/boot_scripts/st.cmd | 7 - tests/samples/boot_scripts/stbl45p-mo-ioc-03 | 12 - tests/samples/boot_scripts/stbl45p-mo-ioc-04 | 5 - tests/samples/boot_scripts/test.ioc.cmd | 5 - .../samples/boot_scripts/test.ioc.make_db.sh | 1 - tests/samples/example-srrfioc08/st.cmd | 22 - tests/samples/pydantic/generate_samples.sh | 20 + tests/samples/pydantic/st.cmd | 10 + .../pydantic/test.ibek.ioc.schema.json | 93 + tests/samples/pydantic/test.ibek.ioc.yaml | 22 + tests/samples/pydantic/test.ibek.support.yaml | 42 + .../schemas/all.ibek.support.schema.json | 4157 +++++++++-------- .../schemas/asyn.ibek.entities.schema.json | 297 +- .../bl45p-mo-ioc-04.ibek.entities.schema.json | 2151 +++++---- .../container.ibek.entities.schema.json | 2108 +++++---- .../schemas/epics.ibek.support.schema.json | 340 +- .../schemas/pmac.ibek.entities.schema.json | 1845 ++++---- .../schemas/pmac.ibek.support.schema.json | 999 ++++ tests/samples/values_test/st.cmd | 11 - tests/samples/yaml/ADCore.ibek.support.yaml | 182 + .../yaml/bl45p-mo-ioc-02.ibek.ioc.yaml | 2 +- tests/test_cli.py | 24 +- tests/test_conversions.py | 6 +- tests/test_ioc.py | 8 +- tests/test_pydantic.py | 80 + tests/test_temp.py | 4 +- 34 files changed, 7494 insertions(+), 5194 deletions(-) create mode 100755 tests/samples/pydantic/generate_samples.sh create mode 100644 tests/samples/pydantic/st.cmd create mode 100644 tests/samples/pydantic/test.ibek.ioc.schema.json create mode 100644 tests/samples/pydantic/test.ibek.ioc.yaml create mode 100644 tests/samples/pydantic/test.ibek.support.yaml create mode 100644 tests/samples/schemas/pmac.ibek.support.schema.json create mode 100644 tests/samples/yaml/ADCore.ibek.support.yaml create mode 100644 tests/test_pydantic.py diff --git a/ibek-defs b/ibek-defs index 98e748d91..508d36c43 160000 --- a/ibek-defs +++ b/ibek-defs @@ -1 +1 @@ -Subproject commit 98e748d9121aef51b18c652c8f17793302c0d68c +Subproject commit 508d36c431f80fca0b53cb575fd596cc379e1731 diff --git a/pyproject.toml b/pyproject.toml index 9ff97371b..e7423617c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,10 +16,9 @@ classifiers = [ description = "IOC Builder for EPICS and Kubernetes" dependencies = [ "typing-extensions", - "apischema>=0.15", + "pydantic", "typer", "ruamel.yaml", - "jsonschema", "jinja2", "typing-extensions;python_version<'3.8'", ] # Add project dependencies here, e.g. ["click", "numpy"] diff --git a/src/ibek/__main__.py b/src/ibek/__main__.py index 9da3830e8..49f7a172b 100644 --- a/src/ibek/__main__.py +++ b/src/ibek/__main__.py @@ -1,3 +1,4 @@ +import json from pathlib import Path from typing import List, Optional @@ -5,8 +6,12 @@ from ruamel.yaml import YAML from ._version import __version__ -from .gen_scripts import create_boot_script, create_db_script, ioc_deserialize -from .ioc import make_entity_models, make_ioc_model +from .gen_scripts import ( + create_boot_script, + create_db_script, + ioc_create_model, + ioc_deserialize, +) from .support import Support cli = typer.Typer() @@ -46,27 +51,13 @@ def ioc_schema( ..., help="The filepath to a support module definition file" ), output: Path = typer.Argument(..., help="The filename to write the schema to"), - no_schema: bool = typer.Option(False, help="disable schema checking"), ): """ Create a json schema from a .ibek.support.yaml file """ - entity_classes = [] - - for definition in definitions: - support_dict = YAML(typ="safe").load(definition) - if not no_schema: - # Verify the schema of the support module definition file - Support.model_validate(support_dict) - - # deserialize the support module definition file - support = Support(**support_dict) - # make Entity classes described in the support module definition file - entity_classes += make_entity_models(support) - - # Save the schema for IOC - schema = make_ioc_model(entity_classes) + ioc_model = ioc_create_model(definitions) + schema = json.dumps(ioc_model.model_json_schema(), indent=2) output.write_text(schema) diff --git a/src/ibek/gen_scripts.py b/src/ibek/gen_scripts.py index fcae27084..32ec93ee9 100644 --- a/src/ibek/gen_scripts.py +++ b/src/ibek/gen_scripts.py @@ -4,12 +4,12 @@ import logging import re from pathlib import Path -from typing import List +from typing import List, Type from jinja2 import Template from ruamel.yaml.main import YAML -from .ioc import IOC, make_entity_classes +from .ioc import IOC, clear_entity_model_ids, make_entity_models, make_ioc_model from .render import Render from .support import Support @@ -21,20 +21,44 @@ url_f = r"file://" +def ioc_create_model(definitions: List[Path]) -> Type[IOC]: + """ + Take a list of definitions YAML and create an IOC model from it + """ + entity_models = [] + + clear_entity_model_ids() + for definition in definitions: + support_dict = YAML(typ="safe").load(definition) + + Support.model_validate(support_dict) + + # deserialize the support module definition file + support = Support(**support_dict) + # make Entity classes described in the support module definition file + entity_models += make_entity_models(support) + + # Save the schema for IOC + model = make_ioc_model(entity_models) + + return model + + def ioc_deserialize(ioc_instance_yaml: Path, definition_yaml: List[Path]) -> IOC: """ Takes an ioc instance entities file, list of generic ioc definitions files. - Returns an in memory object graph of the resulting ioc instance + Returns a model of the resulting ioc instance """ + ioc_model = ioc_create_model(definition_yaml) + + ioc_instance = YAML(typ="safe").load(ioc_instance_yaml) - # Read and load the support module definitions - for yaml in definition_yaml: - support = Support.deserialize(YAML(typ="safe").load(yaml)) - make_entity_classes(support) + clear_entity_model_ids() + ioc_model.model_validate(ioc_instance) - # Create an IOC instance from it - return IOC.deserialize(YAML(typ="safe").load(ioc_instance_yaml)) + # Create an IOC instance from the entities file and the model + return ioc_model.model_construct(ioc_instance) def create_db_script(ioc_instance: IOC) -> str: diff --git a/src/ibek/globals.py b/src/ibek/globals.py index 6a71c1514..be139d7c9 100644 --- a/src/ibek/globals.py +++ b/src/ibek/globals.py @@ -1,24 +1,17 @@ """ A few global definitions """ -from typing import TypeVar -from pydantic import BaseModel, ConfigDict, Field +from pydantic import BaseModel, ConfigDict -#: A generic Type for use in type hints -T = TypeVar("T") - - -def desc(description: str): - """a description Annotation to add to our Entity derived Types""" - return Field(description=description) +# pydantic model configuration +model_config = ConfigDict( + # arbitrary_types_allowed=True, + extra="forbid", +) class BaseSettings(BaseModel): """A Base class for setting Pydantic model configuration""" - # Pydantic model configuration - model_config = ConfigDict( - # arbitrary_types_allowed=True, - extra="forbid", - ) + model_config = model_config diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index 89294ef3f..d142aec78 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -5,21 +5,22 @@ from __future__ import annotations import builtins -import json -from typing import Any, Dict, Sequence, Tuple, Type, Union +from typing import Any, Dict, Literal, Sequence, Tuple, Type, Union from jinja2 import Template -from pydantic import Field, ValidationError, create_model +from pydantic import Field, create_model, field_validator from pydantic.fields import FieldInfo -from typing_extensions import Literal -from .globals import BaseSettings, model_config +from .globals import BaseSettings from .support import Definition, IdArg, ObjectArg, Support from .utils import UTILS # A base class for applying settings to all serializable classes +id_to_entity: Dict[str, Entity] = {} + + class Entity(BaseSettings): """ A baseclass for all generated Entity classes. Provides the @@ -33,36 +34,24 @@ class Entity(BaseSettings): description="enable or disable this entity instance", default=True ) - def __post_init__(self: "Entity"): - # If there is an argument which is an id then allow deserialization by that - args = self.__definition__.args - ids = set(a.name for a in args if isinstance(a, IdArg)) - assert len(ids) <= 1, f"Multiple id args {list(ids)} defined in {args}" - if ids: - # A string id, use that - inst_id = getattr(self, ids.pop()) - assert inst_id not in id_to_entity, f"Already got an instance {inst_id}" - id_to_entity[inst_id] = self - - # TODO - not working as printing own ID - setattr(self, "__str__", inst_id) + # @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 - self.__utils__ = UTILS + entity["__utils__"] = UTILS # copy 'values' from the definition into the Entity - for value in self.__definition__.values: - setattr(self, value.name, value.value) + + # if hasattr(entity, "__definition__"): + # entity.update(entity.__definition__.values) # Jinja expansion of any string args/values in the Entity's attributes - for arg, value in self.__dict__.items(): + for arg, value in entity.items(): if isinstance(value, str): jinja_template = Template(value) - rendered = jinja_template.render(self.__dict__) - setattr(self, arg, rendered) - - -id_to_entity: Dict[str, Entity] = {} + entity[arg] = jinja_template.render(entity) + return entity def make_entity_model(definition: Definition, support: Support) -> Type[Entity]: @@ -76,31 +65,49 @@ def make_entity_model(definition: Definition, support: Support) -> Type[Entity]: """ def add_entity(name, typ, description, default): - entities[name] = (typ, FieldInfo(description=description, default=default)) + entities[name] = ( + typ, + FieldInfo( + description=description, + default=default, + ), + ) entities: Dict[str, Tuple[type, Any]] = {} + validators: Dict[str, Any] = {} + + # fully qualified name of the Entity class including support module + full_name = f"{support.module}.{definition.name}" # add in each of the arguments as a Field in the Entity for arg in definition.args: - arg_type: Type + full_arg_name = f"{full_name}.{arg.name}" if isinstance(arg, ObjectArg): - pass - def lookup_instance(id): + @field_validator(arg.name) + def lookup_instance(cls, id): try: return id_to_entity[id] except KeyError: - raise ValidationError(f"{id} is not in {list(id_to_entity)}") + raise KeyError(f"object id {id} not in {list(id_to_entity)}") + + validators[full_arg_name] = lookup_instance + arg_type = str - # metadata = schema(extra={"vscode_ibek_plugin_type": "type_object"}) - # metadata = conversion( - # deserialization=Conversion(lookup_instance, str, Entity) - # ) | schema(extra={"vscode_ibek_plugin_type": "type_object"}) - arg_type = Entity elif isinstance(arg, IdArg): + + @field_validator(arg.name) + 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 + return id + + validators[full_arg_name] = save_instance arg_type = str - # metadata = schema(extra={"vscode_ibek_plugin_type": "type_id"}) + else: # arg.type is str, int, float, etc. arg_type = getattr(builtins, arg.type) @@ -108,18 +115,14 @@ def lookup_instance(id): default = getattr(arg, "default", None) add_entity(arg.name, arg_type, arg.description, default) - # type is a unique key for each of the entity types we may instantiate - full_name = f"{support.module}.{definition.name}" typ = Literal[full_name] # type: ignore add_entity("type", typ, "The type of this entity", full_name) - # entity_enabled controls rendering of the entity without having to delete it - add_entity("entity_enabled", bool, "enable or disable entity", True) - entity_cls = create_model( - "definitions", + full_name.replace(".", "_"), **entities, - __config__=model_config, + __validators__=validators, + # __base__=Entity, ) # type: ignore # add a link back to the Definition Object that generated this Entity Class @@ -136,36 +139,36 @@ def make_entity_models(support: Support): set to a Union of all the Entity subclasses created.""" entity_models = [] + entity_names = [] for definition in support.defs: entity_models.append(make_entity_model(definition, support)) + if definition.name in entity_names: + raise ValueError(f"Duplicate entity name {definition.name}") + entity_names.append(definition.name) return entity_models -def clear_entity_classes(): - """Reset the modules namespaces, deserializers and caches of defined Entity - subclasses""" - - # TODO: do we need this for Pydantic? - - -def make_ioc_model(entity_classes: Sequence[Type[Entity]]) -> str: +def make_ioc_model(entity_models: Sequence[Type[Entity]]) -> Type[IOC]: class NewIOC(IOC): - entities: Sequence[Union[tuple(entity_classes)]] = Field( # type: ignore + entities: Sequence[Union[tuple(entity_models)]] = Field( # type: ignore description="List of entities this IOC instantiates", default=() ) - return json.dumps(NewIOC.model_json_schema(), indent=2) + return NewIOC + + +def clear_entity_model_ids(): + """Resets the global id_to_entity dict.""" + global id_to_entity + + id_to_entity.clear() class IOC(BaseSettings): """ - Used to load an IOC instance entities yaml file into memory. - - This is the base class that is adjusted at runtime by updating the - type of its entities attribute to be a union of all of the subclasses of Entity - provided by the support module definitions used by the current IOC + Used to load an IOC instance entities yaml file into a Pydantic Model. """ ioc_name: str = Field(description="Name of IOC instance") @@ -173,7 +176,3 @@ class IOC(BaseSettings): generic_ioc_image: str = Field( description="The generic IOC container image registry URL" ) - # placeholder for the entities attribute - updated at runtime - entities: Sequence[Entity] = Field( - description="List of entities this IOC instantiates" - ) diff --git a/src/ibek/support.py b/src/ibek/support.py index f84680bcb..dbbfb6aca 100644 --- a/src/ibek/support.py +++ b/src/ibek/support.py @@ -29,7 +29,6 @@ class Arg(BaseSettings): description: str = Field( description="Description of what the argument will be used for" ) - # __discriminator__ = "type" # FloatArg must be defined before StrArg, otherwise we get: @@ -40,7 +39,7 @@ class Arg(BaseSettings): # have a trailing 'f'. It is due to the order of declaration of subclasses of # Arg. When StrArg is before FloatArg, apischema attempts to deserialize as a # string first. The coercion from str to number requires a trailing f if there -# is a decimal. +# is a decimal. TODO is this still an issue with Pydantic? class FloatArg(Arg): """An argument with a float value""" diff --git a/tests/conftest.py b/tests/conftest.py index fe1353bd5..81ed2139c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ from pytest import fixture from ruamel.yaml import YAML -from ibek.ioc import clear_entity_classes, make_entity_classes +from ibek.ioc import clear_entity_model_ids, make_entity_models from ibek.support import Support @@ -36,10 +36,10 @@ def pmac_support(ibek_defs): @fixture def pmac_classes(pmac_support): # clear the entity classes to make sure there's nothing left - clear_entity_classes() + clear_entity_model_ids() # make entity subclasses for everything defined in it - namespace = make_entity_classes(pmac_support) + namespace = make_entity_models(pmac_support) # return the namespace so that callers have access to all of the # generated dataclasses @@ -54,10 +54,10 @@ def epics_support(ibek_defs): @fixture def epics_classes(epics_support): # clear the entity classes to make sure there's nothing left - clear_entity_classes() + clear_entity_model_ids() # make entity subclasses for everything defined in it - namespace = make_entity_classes(epics_support) + namespace = make_entity_models(epics_support) # return the namespace so that callers have access to all of the # generated dataclasses diff --git a/tests/samples/boot_scripts/st.cmd b/tests/samples/boot_scripts/st.cmd index 957cf88bc..870df2af5 100644 --- a/tests/samples/boot_scripts/st.cmd +++ b/tests/samples/boot_scripts/st.cmd @@ -5,13 +5,6 @@ dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase -# pmacAsynIPConfigure AsynPortName IPAddress -pmacAsynIPConfigure BRICK1port 192.168.0.12:1112:1025 - -# pmacCreateController AsynPortName PmacAsynPort Address NumAxes MovingPollPeriod IdlePollPeriod -pmacCreateController BL45P-MO-BRICK-01 BRICK1port 0 8 500 100 -pmacCreateAxes BL45P-MO-BRICK-01 8 - dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/boot_scripts/stbl45p-mo-ioc-03 b/tests/samples/boot_scripts/stbl45p-mo-ioc-03 index 06302a347..870df2af5 100644 --- a/tests/samples/boot_scripts/stbl45p-mo-ioc-03 +++ b/tests/samples/boot_scripts/stbl45p-mo-ioc-03 @@ -5,18 +5,6 @@ dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase -# pmacAsynIPConfigure AsynPortName IPAddress -pmacAsynIPConfigure BRICK1port 192.168.0.12:1112:1025 - -# pmacCreateController AsynPortName PmacAsynPort Address NumAxes MovingPollPeriod IdlePollPeriod -pmacCreateController BL45P-MO-BRICK-01 BRICK1port 0 8 500 100 -pmacCreateAxes BL45P-MO-BRICK-01 8 -# ASYNSerial Startup ENTRY -# TODO provide Jinja to generate ASYN Startup Entries -# note this is interesting because builder.py has a few if clauses -# for generating the necessary script -# - dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/boot_scripts/stbl45p-mo-ioc-04 b/tests/samples/boot_scripts/stbl45p-mo-ioc-04 index 888f1f0c4..870df2af5 100644 --- a/tests/samples/boot_scripts/stbl45p-mo-ioc-04 +++ b/tests/samples/boot_scripts/stbl45p-mo-ioc-04 @@ -8,8 +8,3 @@ ioc_registerRecordDeviceDriver pdbbase dbLoadRecords /tmp/ioc.db iocInit - - -# dbpf pv value -dbpf BL45P-MO-THIN-01:Y1.TWV 0.5 - diff --git a/tests/samples/boot_scripts/test.ioc.cmd b/tests/samples/boot_scripts/test.ioc.cmd index d946f599f..870df2af5 100644 --- a/tests/samples/boot_scripts/test.ioc.cmd +++ b/tests/samples/boot_scripts/test.ioc.cmd @@ -1,14 +1,9 @@ # EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek cd "/repos/epics/ioc" - -epicsEnvSet EPICS_CA_MAX_ARRAY_BYTES 6000000 -epicsEnvSet EPICS_CA_SERVER_PORT 7064 - dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase -dbLoadRecords("config/ioc.db") dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/boot_scripts/test.ioc.make_db.sh b/tests/samples/boot_scripts/test.ioc.make_db.sh index fca3baaa7..a9bf588e2 100644 --- a/tests/samples/boot_scripts/test.ioc.make_db.sh +++ b/tests/samples/boot_scripts/test.ioc.make_db.sh @@ -1,2 +1 @@ #!/bin/bash -msi -I${EPICS_DB_INCLUDE_PATH} -M"IOC=test-ibek-ioc" "iocAdminSoft.db" diff --git a/tests/samples/example-srrfioc08/st.cmd b/tests/samples/example-srrfioc08/st.cmd index b372e63c8..870df2af5 100644 --- a/tests/samples/example-srrfioc08/st.cmd +++ b/tests/samples/example-srrfioc08/st.cmd @@ -1,32 +1,10 @@ # EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek cd "/repos/epics/ioc" - -epicsEnvSet EPICS_TS_NTP_INET 172.23.194.5 -epicsEnvSet EPICS_TS_MIN_WEST 0 -epicsEnvSet Vec0 192 -epicsEnvSet Vec1 193 -epicsEnvSet Vec2 194 - dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase -# ipacAddHy8002 "slot, interrupt_level" -# Create a new Hy8002 carrier. -# The resulting carrier handle (card id) is saved in an env variable. -ipacAddHy8002 "4, 2" -epicsEnvSet IPAC4 0 -ipacAddHy8002 "5, 2" -epicsEnvSet IPAC5 1 - -# Hy8401ipConfigure CardId IPACid IpSiteNumber InterruptVector InterruptEnable AiType ExternalClock ClockRate Inhibit SampleCount SampleSpacing SampleSize -# IpSlot 0=A 1=B 2=C 3=D -# ClockRate 0=1Hz 1=2Hz 2=5Hz 3=10Hz 4=20Hz 5=50Hz 6=100Hz7=200Hz 8=500Hz 9=1kHz 10=2kHz11=5kHz 12=10kHz 13=20kHz 14=50kHz 15=100kHz -Hy8401ipConfigure 40 $(IPAC4) 0 $(Vec0) 0 0 0 15 0 1 1 0 -Hy8401ipConfigure 42 $(IPAC4) 2 $(Vec1) 0 0 0 15 0 1 1 0 -Hy8401ipConfigure 50 $(IPAC5) 0 $(Vec2) 0 0 0 15 0 1 1 0 - dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/pydantic/generate_samples.sh b/tests/samples/pydantic/generate_samples.sh new file mode 100755 index 000000000..e0292056b --- /dev/null +++ b/tests/samples/pydantic/generate_samples.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# this script regenerates the files used in tests +# it is useful after making changes to the code that affect the schemas etc. +# +# please bear in mind that this is cheating tests! It requires visual +# verifiction of the files in the samples folders after running. +# + +export PYDANTIC_DIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))/ +export DEFS=${PYDANTIC_DIR}/../../ibek-defs + +# this is so relative schema mode lines work +cd $PYDANTIC_DIR + +echo making the support yaml schema +ibek ibek-schema ${PYDANTIC_DIR}/../schemas/ibek.defs.schema.json + +echo making the pydantic test definition schema +ibek ioc-schema ${PYDANTIC_DIR}/test.ibek.support.yaml $PYDANTIC_DIR/test.ibek.ioc.schema.json diff --git a/tests/samples/pydantic/st.cmd b/tests/samples/pydantic/st.cmd new file mode 100644 index 000000000..870df2af5 --- /dev/null +++ b/tests/samples/pydantic/st.cmd @@ -0,0 +1,10 @@ +# EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek + +cd "/repos/epics/ioc" +dbLoadDatabase dbd/ioc.dbd +ioc_registerRecordDeviceDriver pdbbase + + +dbLoadRecords /tmp/ioc.db +iocInit + diff --git a/tests/samples/pydantic/test.ibek.ioc.schema.json b/tests/samples/pydantic/test.ibek.ioc.schema.json new file mode 100644 index 000000000..350c4696c --- /dev/null +++ b/tests/samples/pydantic/test.ibek.ioc.schema.json @@ -0,0 +1,93 @@ +{ + "$defs": { + "pydantic_test_AnAsynPort": { + "properties": { + "name": { + "default": null, + "description": "Asyn port name", + "title": "Name", + "type": "string" + }, + "IP": { + "default": null, + "description": "IP address of port", + "title": "Ip", + "type": "string" + }, + "type": { + "const": "pydantic_test.AnAsynPort", + "default": "pydantic_test.AnAsynPort", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pydantic_test_AnAsynPort", + "type": "object" + }, + "pydantic_test_Consumer": { + "properties": { + "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.Consumer", + "default": "pydantic_test.Consumer", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pydantic_test_Consumer", + "type": "object" + } + }, + "additionalProperties": false, + "properties": { + "ioc_name": { + "description": "Name of IOC instance", + "title": "Ioc Name", + "type": "string" + }, + "description": { + "description": "Description of what the IOC does", + "title": "Description", + "type": "string" + }, + "generic_ioc_image": { + "description": "The generic IOC container image registry URL", + "title": "Generic Ioc Image", + "type": "string" + }, + "entities": { + "default": [], + "description": "List of entities this IOC instantiates", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/pydantic_test_AnAsynPort" + }, + { + "$ref": "#/$defs/pydantic_test_Consumer" + } + ] + }, + "title": "Entities", + "type": "array" + } + }, + "required": [ + "ioc_name", + "description", + "generic_ioc_image" + ], + "title": "NewIOC", + "type": "object" +} \ No newline at end of file diff --git a/tests/samples/pydantic/test.ibek.ioc.yaml b/tests/samples/pydantic/test.ibek.ioc.yaml new file mode 100644 index 000000000..407f33fb5 --- /dev/null +++ b/tests/samples/pydantic/test.ibek.ioc.yaml @@ -0,0 +1,22 @@ +# yaml-language-server: $schema=/tmp/pydantic_test/test.ibek.ioc.schema.json + +ioc_name: test-pydantic-ioc +description: a basic example for testing ioc-template +generic_ioc_image: ghcr.io/epics-containers/ioc-template:23.3.2 + +entities: + - type: pydantic_test.AnAsynPort + 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.Consumer + # name: Another Consumer of same port + # PORT: AsynPort diff --git a/tests/samples/pydantic/test.ibek.support.yaml b/tests/samples/pydantic/test.ibek.support.yaml new file mode 100644 index 000000000..71abad450 --- /dev/null +++ b/tests/samples/pydantic/test.ibek.support.yaml @@ -0,0 +1,42 @@ +# yaml-language-server: $schema=../schemas/ibek.defs.schema.json +module: pydantic_test + +defs: + - name: AnAsynPort + description: | + Example + args: + - type: id + name: name + description: Asyn port name + + - type: str + name: IP + description: IP address of port + + values: + - name: test_value + value: "{{ name }}.{{ IP }}" + description: test jinja render of arg values + + - name: Consumer + description: | + An object that uses AnAsynPort + args: + - type: id + name: name + description: Consumer name + + - type: object + 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 diff --git a/tests/samples/schemas/all.ibek.support.schema.json b/tests/samples/schemas/all.ibek.support.schema.json index dec373d13..a6b16c00f 100644 --- a/tests/samples/schemas/all.ibek.support.schema.json +++ b/tests/samples/schemas/all.ibek.support.schema.json @@ -1,1964 +1,2371 @@ { - "type": "object", + "$defs": { + "ADAravis_ADAravis": { + "additionalProperties": false, + "properties": { + "PORT": { + "default": null, + "description": "Port Name for teh camera", + "title": "Port", + "type": "string" + }, + "P": { + "default": null, + "description": "The PV prefix", + "title": "P", + "type": "string" + }, + "R": { + "default": null, + "description": "The PV suffix", + "title": "R", + "type": "string" + }, + "ID": { + "default": null, + "description": "Cam ip address, hostname, MAC address, or ID -,\n(e.g. Prosilica-02-2166A-06844)\n", + "title": "Id", + "type": "string" + }, + "BUFFERS": { + "default": 50, + "description": "Max NDArray buffers to be created for plugin callbacks", + "title": "Buffers", + "type": "integer" + }, + "MEMORY": { + "default": -1, + "description": "Max memory to allocate, should be maxw*maxh*nbuffer\nfor driver and all attached plugins or -1 for unlimited\n", + "title": "Memory", + "type": "integer" + }, + "TIMEOUT": { + "default": 1, + "description": "timeout for communication with camera", + "title": "Timeout", + "type": "integer" + }, + "PV_ALIAS": { + "default": "", + "description": "TODO this need to look into the purpose of this in builder.py\ndetermine its function and see if we can do the equivalent in ibek\n", + "title": "Pv Alias", + "type": "string" + }, + "type": { + "const": "ADAravis.ADAravis", + "default": "ADAravis.ADAravis", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "ADAravis_ADAravis", + "type": "object" + }, + "ADAravis_Mako_G234B": { + "additionalProperties": false, + "properties": { + "camera": { + "default": null, + "description": "reference to ADAravis.ADAravis instance", + "title": "Camera", + "type": "string" + }, + "type": { + "const": "ADAravis.Mako_G234B", + "default": "ADAravis.Mako_G234B", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "ADAravis_Mako_G234B", + "type": "object" + }, + "ADAravis_MantaG235B": { + "additionalProperties": false, + "properties": { + "camera": { + "default": null, + "description": "reference to ADAravis.ADAravis instance", + "title": "Camera", + "type": "string" + }, + "type": { + "const": "ADAravis.MantaG235B", + "default": "ADAravis.MantaG235B", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "ADAravis_MantaG235B", + "type": "object" + }, + "ADCore_NDRoi": { + "additionalProperties": false, + "properties": { + "PORT": { + "default": null, + "description": "Port for this plugin", + "title": "Port", + "type": "string" + }, + "NDARRAY_PORT": { + "default": null, + "description": "Port Name for input NDArray plugin", + "title": "Ndarray Port", + "type": "string" + }, + "P": { + "default": null, + "description": "The PV prefix", + "title": "P", + "type": "string" + }, + "R": { + "default": null, + "description": "The PV suffix", + "title": "R", + "type": "string" + }, + "TIMEOUT": { + "default": 1, + "description": "Timeout for ASYN communications", + "title": "Timeout", + "type": "integer" + }, + "ADDR": { + "default": 0, + "description": "ASYN Address this plugin", + "title": "Addr", + "type": "integer" + }, + "NDARRAY_ADDR": { + "default": 0, + "description": "ASYN Address for input NDArray plugin", + "title": "Ndarray Addr", + "type": "integer" + }, + "ENABLED": { + "default": true, + "description": "Enable/Disable this plugin at startup", + "title": "Enabled", + "type": "boolean" + }, + "SCANRATE": { + "default": "I/O Intr", + "description": "Epics record scan rate", + "title": "Scanrate", + "type": "string" + }, + "QUEUE": { + "default": 2, + "description": "Number of NDArray buffers to be created for plugin callbacks", + "title": "Queue", + "type": "integer" + }, + "BLOCK": { + "default": false, + "description": "blocking callbacks?", + "title": "Block", + "type": "boolean" + }, + "MAX_THREADS": { + "default": 1, + "description": "Maximum number of threads to use", + "title": "Max Threads", + "type": "integer" + }, + "type": { + "const": "ADCore.NDRoi", + "default": "ADCore.NDRoi", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "ADCore_NDRoi", + "type": "object" + }, + "ADCore_NDStats": { + "additionalProperties": false, + "properties": { + "PORT": { + "default": null, + "description": "Port for this plugin", + "title": "Port", + "type": "string" + }, + "NDARRAY_PORT": { + "default": null, + "description": "Port Name for input NDArray plugin", + "title": "Ndarray Port", + "type": "string" + }, + "P": { + "default": null, + "description": "The PV prefix", + "title": "P", + "type": "string" + }, + "R": { + "default": null, + "description": "The PV suffix", + "title": "R", + "type": "string" + }, + "TIMEOUT": { + "default": 1, + "description": "Timeout for ASYN communications", + "title": "Timeout", + "type": "integer" + }, + "ADDR": { + "default": 0, + "description": "ASYN Address this plugin", + "title": "Addr", + "type": "integer" + }, + "NDARRAY_ADDR": { + "default": 0, + "description": "ASYN Address for input NDArray plugin", + "title": "Ndarray Addr", + "type": "integer" + }, + "ENABLED": { + "default": true, + "description": "Enable/Disable this plugin at startup", + "title": "Enabled", + "type": "boolean" + }, + "SCANRATE": { + "default": "I/O Intr", + "description": "Epics record scan rate", + "title": "Scanrate", + "type": "string" + }, + "QUEUE": { + "default": 2, + "description": "Number of NDArray buffers to be created for plugin callbacks", + "title": "Queue", + "type": "integer" + }, + "BLOCK": { + "default": false, + "description": "blocking callbacks?", + "title": "Block", + "type": "boolean" + }, + "MAX_THREADS": { + "default": 1, + "description": "Maximum number of threads to use", + "title": "Max Threads", + "type": "integer" + }, + "type": { + "const": "ADCore.NDStats", + "default": "ADCore.NDStats", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "ADCore_NDStats", + "type": "object" + }, + "Hy8401ip_Hy8401Channel": { + "additionalProperties": false, + "properties": { + "card": { + "default": null, + "description": "8401 card identifier", + "title": "Card", + "type": "string" + }, + "signal": { + "default": null, + "description": "8401 signal number (0-7)", + "title": "Signal", + "type": "integer" + }, + "type": { + "const": "Hy8401ip.Hy8401Channel", + "default": "Hy8401ip.Hy8401Channel", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "Hy8401ip_Hy8401Channel", + "type": "object" + }, + "Hy8401ip_Hy8401ip": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Name to refer to when making a channel", + "title": "Name", + "type": "string" + }, + "carrier": { + "default": null, + "description": "Carrier Board Identifier", + "title": "Carrier", + "type": "string" + }, + "ip_site_number": { + "default": null, + "description": "IP Site Number 0=A, 1=B, 2=C, 3=D", + "title": "Ip Site Number", + "type": "integer" + }, + "vector": { + "default": null, + "description": "Interrupt Vector", + "title": "Vector", + "type": "string" + }, + "int_enable": { + "default": false, + "description": "Interrupt Enable", + "title": "Int Enable", + "type": "boolean" + }, + "external_clock": { + "default": false, + "description": "Use External Clock", + "title": "External Clock", + "type": "boolean" + }, + "clock_rate": { + "default": 15, + "description": "Clock Rate", + "title": "Clock Rate", + "type": "integer" + }, + "inhibit": { + "default": false, + "description": "Enable front panel inhibit signal", + "title": "Inhibit", + "type": "boolean" + }, + "sample_size": { + "default": 0, + "description": "Number of samples for triggered capture", + "title": "Sample Size", + "type": "integer" + }, + "card_id": { + "default": "{{ carrier.slot }}{{ ip_site_number }}", + "description": "Card Identifier", + "title": "Card Id", + "type": "string" + }, + "type": { + "const": "Hy8401ip.Hy8401ip", + "default": "Hy8401ip.Hy8401ip", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "Hy8401ip_Hy8401ip", + "type": "object" + }, + "Hy8403ip_Hy8403Channel": { + "additionalProperties": false, + "properties": { + "device": { + "default": null, + "description": "Device Name, PV Suffix", + "title": "Device", + "type": "string" + }, + "card": { + "default": null, + "description": "8403 card identifier", + "title": "Card", + "type": "string" + }, + "type": { + "const": "Hy8403ip.Hy8403Channel", + "default": "Hy8403ip.Hy8403Channel", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "Hy8403ip_Hy8403Channel", + "type": "object" + }, + "Hy8403ip_Hy8403ip": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Name to refer to when making a channel", + "title": "Name", + "type": "string" + }, + "carrier": { + "default": null, + "description": "Carrier Board Identifier", + "title": "Carrier", + "type": "string" + }, + "ip_site_number": { + "default": null, + "description": "IP Site Number 0=A, 1=B, 2=C, 3=D", + "title": "Ip Site Number", + "type": "integer" + }, + "vector": { + "default": null, + "description": "Interrupt Vector", + "title": "Vector", + "type": "string" + }, + "aitype": { + "default": null, + "description": "0=differential, 1=single ended, 2=PT100, 3=Thermocouple, 4=PT100 with 8212 Transition Card, 5=Thermocouples with 8212 Transition Card", + "title": "Aitype", + "type": "integer" + }, + "memsize": { + "default": null, + "description": "1=1MB memory, 2=2MB memory", + "title": "Memsize", + "type": "integer" + }, + "clock_source": { + "default": null, + "description": "0=internal, 1=external", + "title": "Clock Source", + "type": "integer" + }, + "clock_rate": { + "default": null, + "description": "Xilinx scanning frequency in Hertz. Valid values: 1,2,5,10,20,50,100 and 200 Hz.", + "title": "Clock Rate", + "type": "integer" + }, + "gain": { + "default": null, + "description": "Gain for all ADC inputs. Valid values are: 1,2,4,8,16,32,64, 128", + "title": "Gain", + "type": "integer" + }, + "vref": { + "default": null, + "description": "Determine the internal ADC reference voltage: =1: 1.25V =2: 2.5V", + "title": "Vref", + "type": "integer" + }, + "card_id": { + "default": "{{ carrier.slot }}{{ ip_site_number }}", + "description": "Card Identifier", + "title": "Card Id", + "type": "string" + }, + "type": { + "const": "Hy8403ip.Hy8403ip", + "default": "Hy8403ip.Hy8403ip", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "Hy8403ip_Hy8403ip", + "type": "object" + }, + "PT100_PT100": { + "additionalProperties": false, + "properties": { + "PT": { + "default": null, + "description": "Process Variable prefix", + "title": "Pt", + "type": "string" + }, + "ADC_REF_CHAN": { + "default": null, + "description": "adc reference channel PV", + "title": "Adc Ref Chan", + "type": "string" + }, + "ADC_CHAN": { + "default": null, + "description": "ADC channel PV", + "title": "Adc Chan", + "type": "string" + }, + "deadband": { + "default": null, + "description": "hysteresis value for monitor updates in Deg.C", + "title": "Deadband", + "type": "number" + }, + "hihi": { + "default": null, + "description": "hihi alarm", + "title": "Hihi", + "type": "number" + }, + "hi": { + "default": null, + "description": "hi alarm", + "title": "Hi", + "type": "number" + }, + "lo": { + "default": null, + "description": "lo alarm", + "title": "Lo", + "type": "number" + }, + "lolo": { + "default": null, + "description": "lolo alarm", + "title": "Lolo", + "type": "number" + }, + "scan": { + "default": 1.0, + "description": "scan period in seconds", + "title": "Scan", + "type": "number" + }, + "prec": { + "default": 0, + "description": "record display precision", + "title": "Prec", + "type": "integer" + }, + "hopr": { + "default": 100.0, + "description": "high operating range", + "title": "Hopr", + "type": "number" + }, + "lopr": { + "default": 0.0, + "description": "low operating range", + "title": "Lopr", + "type": "number" + }, + "type": { + "const": "PT100.PT100", + "default": "PT100.PT100", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "PT100_PT100", + "type": "object" + }, + "TimingTemplates_DefaultEVR": { + "additionalProperties": false, + "properties": { + "device": { + "default": null, + "description": "The device PV prefix", + "title": "Device", + "type": "string" + }, + "event_receiver": { + "default": null, + "description": "reference to EventReceiverPMC entry", + "title": "Event Receiver", + "type": "string" + }, + "er": { + "default": "SET-ER", + "description": "Event Receiver record suffix", + "title": "Er", + "type": "string" + }, + "type": { + "const": "TimingTemplates.DefaultEVR", + "default": "TimingTemplates.DefaultEVR", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "TimingTemplates_DefaultEVR", + "type": "object" + }, + "TimingTemplates_EvrAlive": { + "additionalProperties": false, + "properties": { + "default_evr": { + "default": null, + "description": "reference to DefaultEVR entry", + "title": "Default Evr", + "type": "string" + }, + "type": { + "const": "TimingTemplates.EvrAlive", + "default": "TimingTemplates.EvrAlive", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "TimingTemplates_EvrAlive", + "type": "object" + }, + "TimingTemplates_GeneralTime": { + "additionalProperties": false, + "properties": { + "device": { + "default": null, + "description": "device name", + "title": "Device", + "type": "string" + }, + "gt": { + "default": "GT:", + "description": "generalTime PV Prefix", + "title": "Gt", + "type": "string" + }, + "scan": { + "default": "10 second", + "description": "scan rate", + "title": "Scan", + "type": "string" + }, + "type": { + "const": "TimingTemplates.GeneralTime", + "default": "TimingTemplates.GeneralTime", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "TimingTemplates_GeneralTime", + "type": "object" + }, + "asyn_AsynIP": { + "additionalProperties": false, + "properties": { + "port": { + "default": null, + "description": "Serial port tty name / IP address optionally followed by protocol", + "title": "Port", + "type": "string" + }, + "name": { + "default": null, + "description": "Name for the Asyn Port", + "title": "Name", + "type": "string" + }, + "input_eos": { + "default": null, + "description": "Input end of string (terminator)", + "title": "Input Eos", + "type": "string" + }, + "output_eos": { + "default": null, + "description": "Output end of string (terminator)", + "title": "Output Eos", + "type": "string" + }, + "priority": { + "default": 100, + "description": "Priority", + "title": "Priority", + "type": "integer" + }, + "no_auto_connect": { + "default": null, + "description": "Set to stop auto connect", + "title": "No Auto Connect", + "type": "boolean" + }, + "no_process_eos": { + "default": null, + "description": "Set to avoid processing end of string", + "title": "No Process Eos", + "type": "boolean" + }, + "simulation": { + "default": null, + "description": "IP port to connect to if in simulation mode", + "title": "Simulation", + "type": "string" + }, + "type": { + "const": "asyn.AsynIP", + "default": "asyn.AsynIP", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "asyn_AsynIP", + "type": "object" + }, + "asyn_AsynSerial": { + "additionalProperties": false, + "properties": { + "port": { + "default": null, + "description": "The port name for this asyn object", + "title": "Port", + "type": "string" + }, + "input_eos": { + "default": null, + "description": "Input end of string (terminator)", + "title": "Input Eos", + "type": "string" + }, + "output_eos": { + "default": null, + "description": "Output end of string (terminator)", + "title": "Output Eos", + "type": "string" + }, + "priority": { + "default": 100, + "description": "Priority", + "title": "Priority", + "type": "integer" + }, + "no_auto_connect": { + "default": null, + "description": "Set to stop auto connect", + "title": "No Auto Connect", + "type": "boolean" + }, + "no_process_eos": { + "default": null, + "description": "Set to avoid processing end of string", + "title": "No Process Eos", + "type": "boolean" + }, + "simulation": { + "default": null, + "description": "IP port to connect to if in simulation mode", + "title": "Simulation", + "type": "string" + }, + "baud": { + "default": null, + "description": "Baud Rate", + "title": "Baud", + "type": "integer" + }, + "bits": { + "default": null, + "description": "Bits [8,7,6,5]", + "title": "Bits", + "type": "integer" + }, + "parity": { + "default": null, + "description": "Parity [null,even,odd]", + "title": "Parity", + "type": "string" + }, + "stop": { + "default": null, + "description": "Stop Bits [1,2]", + "title": "Stop", + "type": "integer" + }, + "crtscts": { + "default": null, + "description": "Set hardware flow control on", + "title": "Crtscts", + "type": "boolean" + }, + "type": { + "const": "asyn.AsynSerial", + "default": "asyn.AsynSerial", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "asyn_AsynSerial", + "type": "object" + }, + "devIocStats_IocAdminSoft": { + "additionalProperties": false, + "properties": { + "ioc": { + "default": null, + "description": "Device Prefix for this IOC", + "title": "Ioc", + "type": "string" + }, + "type": { + "const": "devIocStats.IocAdminSoft", + "default": "devIocStats.IocAdminSoft", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "devIocStats_IocAdminSoft", + "type": "object" + }, + "epics_Dbpf": { + "additionalProperties": false, + "properties": { + "pv": { + "default": null, + "description": "Name of PV", + "title": "Pv", + "type": "string" + }, + "value": { + "default": null, + "description": "Value to set", + "title": "Value", + "type": "string" + }, + "type": { + "const": "epics.Dbpf", + "default": "epics.Dbpf", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_Dbpf", + "type": "object" + }, + "epics_EpicsCaMaxArrayBytes": { + "additionalProperties": false, + "properties": { + "max_bytes": { + "default": 6000000, + "description": "Max size in bytes for sending arrays over channel access", + "title": "Max Bytes", + "type": "integer" + }, + "type": { + "const": "epics.EpicsCaMaxArrayBytes", + "default": "epics.EpicsCaMaxArrayBytes", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_EpicsCaMaxArrayBytes", + "type": "object" + }, + "epics_EpicsEnvSet": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Name of environment variable", + "title": "Name", + "type": "string" + }, + "value": { + "default": null, + "description": "Value of environment variable", + "title": "Value", + "type": "string" + }, + "type": { + "const": "epics.EpicsEnvSet", + "default": "epics.EpicsEnvSet", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_EpicsEnvSet", + "type": "object" + }, + "epics_EpicsTsMinWest": { + "additionalProperties": false, + "properties": { + "minutes_west": { + "default": 0, + "description": "relative time zone minutes", + "title": "Minutes West", + "type": "integer" + }, + "type": { + "const": "epics.EpicsTsMinWest", + "default": "epics.EpicsTsMinWest", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_EpicsTsMinWest", + "type": "object" + }, + "epics_InterruptVectorVME": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "A name for an interrupt vector variable", + "title": "Name", + "type": "string" + }, + "count": { + "default": 1, + "description": "The number of interrupt vectors to reserve", + "title": "Count", + "type": "integer" + }, + "type": { + "const": "epics.InterruptVectorVME", + "default": "epics.InterruptVectorVME", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_InterruptVectorVME", + "type": "object" + }, + "epics_PostStartupCommand": { + "additionalProperties": false, + "properties": { + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" + }, + "type": { + "const": "epics.PostStartupCommand", + "default": "epics.PostStartupCommand", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_PostStartupCommand", + "type": "object" + }, + "epics_StartupCommand": { + "additionalProperties": false, + "properties": { + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" + }, + "type": { + "const": "epics.StartupCommand", + "default": "epics.StartupCommand", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_StartupCommand", + "type": "object" + }, + "ipac_Hy8002": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "IPAC identifier (suggested: IPAC)", + "title": "Name", + "type": "string" + }, + "slot": { + "default": null, + "description": "Crate Slot number", + "title": "Slot", + "type": "integer" + }, + "int_level": { + "default": 2, + "description": "Interrupt level", + "title": "Int Level", + "type": "integer" + }, + "type": { + "const": "ipac.Hy8002", + "default": "ipac.Hy8002", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "ipac_Hy8002", + "type": "object" + }, + "mrfTiming_EventReceiverInit": { + "additionalProperties": false, + "properties": { + "priority": { + "default": 10, + "description": "Time provider priority", + "title": "Priority", + "type": "integer" + }, + "type": { + "const": "mrfTiming.EventReceiverInit", + "default": "mrfTiming.EventReceiverInit", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "mrfTiming_EventReceiverInit", + "type": "object" + }, + "mrfTiming_EventReceiverPMC": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "A name to reference this EVR", + "title": "Name", + "type": "string" + }, + "card_id": { + "default": null, + "description": "EPICS Card id", + "title": "Card Id", + "type": "integer" + }, + "card_index": { + "default": 0, + "description": "PMC slot number", + "title": "Card Index", + "type": "integer" + }, + "type": { + "const": "mrfTiming.EventReceiverPMC", + "default": "mrfTiming.EventReceiverPMC", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "mrfTiming_EventReceiverPMC", + "type": "object" + }, + "pmac_CS": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name for this object", + "title": "Name", + "type": "string" + }, + "Controller": { + "default": null, + "description": "the PMAC Controller", + "title": "Controller", + "type": "string" + }, + "CS": { + "default": null, + "description": "Coordinate system number", + "title": "Cs", + "type": "integer" + }, + "NAxes": { + "default": 9, + "description": "number of CS axes", + "title": "Naxes", + "type": "integer" + }, + "Program": { + "default": 10, + "description": "PROG number for CS motion", + "title": "Program", + "type": "integer" + }, + "type": { + "const": "pmac.CS", + "default": "pmac.CS", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_CS", + "type": "object" + }, + "pmac_DlsCsPmacAsynMotor": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Object name and gui association name", + "title": "Name", + "type": "string" + }, + "CsController": { + "default": null, + "description": "Coordinate system controller to attach to", + "title": "Cscontroller", + "type": "string" + }, + "axis": { + "default": null, + "description": "which axis number this motor drives", + "title": "Axis", + "type": "integer" + }, + "P": { + "default": null, + "description": "PV prefix name for this motor", + "title": "P", + "type": "string" + }, + "M": { + "default": null, + "description": "PV motor name for this motor", + "title": "M", + "type": "string" + }, + "DESC": { + "default": "", + "description": "Description, displayed on EDM screen", + "title": "Desc", + "type": "string" + }, + "MRES": { + "default": 0.0001, + "description": "Motor Step Size (EGU)", + "title": "Mres", + "type": "number" + }, + "VELO": { + "default": 1.0, + "description": "axis Velocity (EGU/s)", + "title": "Velo", + "type": "number" + }, + "PREC": { + "default": 3, + "description": "Display Precision", + "title": "Prec", + "type": "integer" + }, + "EGU": { + "default": "mm", + "description": "Engineering Units", + "title": "Egu", + "type": "string" + }, + "TWV": { + "default": 1.0, + "description": "Tweak Step Size (EGU)", + "title": "Twv", + "type": "number" + }, + "DTYP": { + "default": "asynMotor", + "description": "Datatype of record", + "title": "Dtyp", + "type": "string" + }, + "DIR": { + "default": 0, + "description": "User direction", + "title": "Dir", + "type": "integer" + }, + "VBAS": { + "default": 1.0, + "description": "Base Velocity (EGU/s)", + "title": "Vbas", + "type": "number" + }, + "VMAX": { + "default": "{{VELO}}", + "description": "Max Velocity (EGU/s)", + "title": "Vmax", + "type": "string" + }, + "ACCL": { + "default": 0.5, + "description": "Seconds to Velocity", + "title": "Accl", + "type": "number" + }, + "BDST": { + "default": 0.0, + "description": "BL Distance (EGU)", + "title": "Bdst", + "type": "number" + }, + "BVEL": { + "default": 0.0, + "description": "BL Velocity(EGU/s)", + "title": "Bvel", + "type": "number" + }, + "BACC": { + "default": 0.0, + "description": "BL Seconds to Veloc", + "title": "Bacc", + "type": "number" + }, + "DHLM": { + "default": 10000.0, + "description": "Dial High Limit", + "title": "Dhlm", + "type": "number" + }, + "DLLM": { + "default": -10000.0, + "description": "Dial low limit", + "title": "Dllm", + "type": "number" + }, + "HLM": { + "default": 0.0, + "description": "User High Limit", + "title": "Hlm", + "type": "number" + }, + "LLM": { + "default": 0.0, + "description": "User Low Limit", + "title": "Llm", + "type": "number" + }, + "HLSV": { + "default": "MAJOR", + "description": "HW Lim, Violation Svr", + "title": "Hlsv", + "type": "string" + }, + "INIT": { + "default": "", + "description": "Startup commands", + "title": "Init", + "type": "string" + }, + "SREV": { + "default": 1000, + "description": "Steps per Revolution", + "title": "Srev", + "type": "integer" + }, + "RRES": { + "default": 0.0, + "description": "Readback Step Size (EGU", + "title": "Rres", + "type": "number" + }, + "ERES": { + "default": 0.0, + "description": "Encoder Step Size (EGU)", + "title": "Eres", + "type": "number" + }, + "JAR": { + "default": 0.0, + "description": "Jog Acceleration (EGU/s^2)", + "title": "Jar", + "type": "number" + }, + "UEIP": { + "default": 0, + "description": "Use Encoder If Present", + "title": "Ueip", + "type": "integer" + }, + "URIP": { + "default": 0, + "description": "Use RDBL If Present", + "title": "Urip", + "type": "integer" + }, + "RDBL": { + "default": "0", + "description": "Readback Location, set URIP =1 if you specify this", + "title": "Rdbl", + "type": "string" + }, + "RLNK": { + "default": "", + "description": "Readback output link", + "title": "Rlnk", + "type": "string" + }, + "RTRY": { + "default": 0, + "description": "Max retry count", + "title": "Rtry", + "type": "integer" + }, + "DLY": { + "default": 0.0, + "description": "Readback settle time (s)", + "title": "Dly", + "type": "number" + }, + "OFF": { + "default": 0.0, + "description": "User Offset (EGU)", + "title": "Off", + "type": "number" + }, + "RDBD": { + "default": 0.0, + "description": "Retry Deadband (EGU)", + "title": "Rdbd", + "type": "number" + }, + "FOFF": { + "default": 0, + "description": "Freeze Offset, 0=variable, 1=frozen", + "title": "Foff", + "type": "integer" + }, + "ADEL": { + "default": 0.0, + "description": "Alarm monitor deadband (EGU)", + "title": "Adel", + "type": "number" + }, + "NTM": { + "default": 1, + "description": "New Target Monitor, only set to 0 for soft motors", + "title": "Ntm", + "type": "integer" + }, + "FEHEIGH": { + "default": 0.0, + "description": "HIGH limit for following error", + "title": "Feheigh", + "type": "number" + }, + "FEHIHI": { + "default": 0.0, + "description": "HIHI limit for following error", + "title": "Fehihi", + "type": "number" + }, + "FEHHSV": { + "default": "NO_ALARM", + "description": "HIHI alarm severity for following error", + "title": "Fehhsv", + "type": "string" + }, + "FEHSV": { + "default": "NO_ALARM", + "description": "HIGH alarm severity for following error", + "title": "Fehsv", + "type": "string" + }, + "SCALE": { + "default": 1, + "description": "", + "title": "Scale", + "type": "integer" + }, + "HOMEVIS": { + "default": 1, + "description": "If 1 then home is visible on the gui", + "title": "Homevis", + "type": "integer" + }, + "HOMEVISSTR": { + "default": "Use motor summary screen", + "description": "", + "title": "Homevisstr", + "type": "string" + }, + "alh": { + "default": "", + "description": "Set this to alh to add the motor to the alarm handler and send emails", + "title": "Alh", + "type": "string" + }, + "HOME": { + "default": "{{P}}", + "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", + "title": "Home", + "type": "string" + }, + "ALLOW_HOMED_SET": { + "default": "#", + "description": "Set to a blank to allow this axis to have its homed", + "title": "Allow Homed Set", + "type": "string" + }, + "type": { + "const": "pmac.DlsCsPmacAsynMotor", + "default": "pmac.DlsCsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_DlsCsPmacAsynMotor", + "type": "object" + }, + "pmac_DlsPmacAsynMotor": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Object name and gui association name", + "title": "Name", + "type": "string" + }, + "Controller": { + "default": null, + "description": "PMAC Controller to attach to", + "title": "Controller", + "type": "string" + }, + "axis": { + "default": null, + "description": "which axis number this motor drives", + "title": "Axis", + "type": "integer" + }, + "P": { + "default": null, + "description": "PV prefix name for this motor", + "title": "P", + "type": "string" + }, + "M": { + "default": null, + "description": "PV motor name for this motor", + "title": "M", + "type": "string" + }, + "DESC": { + "default": "", + "description": "Description, displayed on EDM screen", + "title": "Desc", + "type": "string" + }, + "MRES": { + "default": 0.0001, + "description": "Motor Step Size (EGU)", + "title": "Mres", + "type": "number" + }, + "VELO": { + "default": 1.0, + "description": "axis Velocity (EGU/s)", + "title": "Velo", + "type": "number" + }, + "PREC": { + "default": 3, + "description": "Display Precision", + "title": "Prec", + "type": "integer" + }, + "EGU": { + "default": "mm", + "description": "Engineering Units", + "title": "Egu", + "type": "string" + }, + "TWV": { + "default": 1.0, + "description": "Tweak Step Size (EGU)", + "title": "Twv", + "type": "number" + }, + "DTYP": { + "default": "asynMotor", + "description": "Datatype of record", + "title": "Dtyp", + "type": "string" + }, + "DIR": { + "default": 0, + "description": "User direction", + "title": "Dir", + "type": "integer" + }, + "VBAS": { + "default": 1.0, + "description": "Base Velocity (EGU/s)", + "title": "Vbas", + "type": "number" + }, + "VMAX": { + "default": "{{VELO}}", + "description": "Max Velocity (EGU/s)", + "title": "Vmax", + "type": "string" + }, + "ACCL": { + "default": 0.5, + "description": "Seconds to Velocity", + "title": "Accl", + "type": "number" + }, + "BDST": { + "default": 0.0, + "description": "BL Distance (EGU)", + "title": "Bdst", + "type": "number" + }, + "BVEL": { + "default": 0.0, + "description": "BL Velocity(EGU/s)", + "title": "Bvel", + "type": "number" + }, + "BACC": { + "default": 0.0, + "description": "BL Seconds to Veloc", + "title": "Bacc", + "type": "number" + }, + "DHLM": { + "default": 10000.0, + "description": "Dial High Limit", + "title": "Dhlm", + "type": "number" + }, + "DLLM": { + "default": -10000.0, + "description": "Dial low limit", + "title": "Dllm", + "type": "number" + }, + "HLM": { + "default": 0.0, + "description": "User High Limit", + "title": "Hlm", + "type": "number" + }, + "LLM": { + "default": 0.0, + "description": "User Low Limit", + "title": "Llm", + "type": "number" + }, + "HLSV": { + "default": "MAJOR", + "description": "HW Lim, Violation Svr", + "title": "Hlsv", + "type": "string" + }, + "INIT": { + "default": "", + "description": "Startup commands", + "title": "Init", + "type": "string" + }, + "SREV": { + "default": 1000, + "description": "Steps per Revolution", + "title": "Srev", + "type": "integer" + }, + "RRES": { + "default": 0.0, + "description": "Readback Step Size (EGU", + "title": "Rres", + "type": "number" + }, + "ERES": { + "default": 0.0, + "description": "Encoder Step Size (EGU)", + "title": "Eres", + "type": "number" + }, + "JAR": { + "default": 0.0, + "description": "Jog Acceleration (EGU/s^2)", + "title": "Jar", + "type": "number" + }, + "UEIP": { + "default": 0, + "description": "Use Encoder If Present", + "title": "Ueip", + "type": "integer" + }, + "URIP": { + "default": 0, + "description": "Use RDBL If Present", + "title": "Urip", + "type": "integer" + }, + "RDBL": { + "default": "0", + "description": "Readback Location, set URIP =1 if you specify this", + "title": "Rdbl", + "type": "string" + }, + "RLNK": { + "default": "", + "description": "Readback output link", + "title": "Rlnk", + "type": "string" + }, + "RTRY": { + "default": 0, + "description": "Max retry count", + "title": "Rtry", + "type": "integer" + }, + "DLY": { + "default": 0.0, + "description": "Readback settle time (s)", + "title": "Dly", + "type": "number" + }, + "OFF": { + "default": 0.0, + "description": "User Offset (EGU)", + "title": "Off", + "type": "number" + }, + "RDBD": { + "default": 0.0, + "description": "Retry Deadband (EGU)", + "title": "Rdbd", + "type": "number" + }, + "FOFF": { + "default": 0, + "description": "Freeze Offset, 0=variable, 1=frozen", + "title": "Foff", + "type": "integer" + }, + "ADEL": { + "default": 0.0, + "description": "Alarm monitor deadband (EGU)", + "title": "Adel", + "type": "number" + }, + "NTM": { + "default": 1, + "description": "New Target Monitor, only set to 0 for soft motors", + "title": "Ntm", + "type": "integer" + }, + "FEHIGH": { + "default": 0.0, + "description": "HIGH limit for following error", + "title": "Fehigh", + "type": "number" + }, + "FEHIHI": { + "default": 0.0, + "description": "HIHI limit for following error", + "title": "Fehihi", + "type": "number" + }, + "FEHHSV": { + "default": "NO_ALARM", + "description": "HIHI alarm severity for following error", + "title": "Fehhsv", + "type": "string" + }, + "FEHSV": { + "default": "NO_ALARM", + "description": "HIGH alarm severity for following error", + "title": "Fehsv", + "type": "string" + }, + "SCALE": { + "default": 1, + "description": "", + "title": "Scale", + "type": "integer" + }, + "HOMEVIS": { + "default": 1, + "description": "If 1 then home is visible on the gui", + "title": "Homevis", + "type": "integer" + }, + "HOMEVISSTR": { + "default": "Use motor summary screen", + "description": "", + "title": "Homevisstr", + "type": "string" + }, + "alh": { + "default": "", + "description": "Set this to alh to add the motor to the alarm handler and send emails", + "title": "Alh", + "type": "string" + }, + "HOME": { + "default": "{{P}}", + "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", + "title": "Home", + "type": "string" + }, + "ALLOW_HOMED_SET": { + "default": "#", + "description": "Set to a blank to allow this axis to have its homed", + "title": "Allow Homed Set", + "type": "string" + }, + "RLINK": { + "default": "", + "description": "not sure what this is", + "title": "Rlink", + "type": "string" + }, + "type": { + "const": "pmac.DlsPmacAsynMotor", + "default": "pmac.DlsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_DlsPmacAsynMotor", + "type": "object" + }, + "pmac_Geobrick": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Name to use for the geobrick's asyn port", + "title": "Name", + "type": "string" + }, + "PORT": { + "default": null, + "description": "Asyn port name for PmacAsynIPPort to connect to", + "title": "Port", + "type": "string" + }, + "P": { + "default": null, + "description": "PV Prefix for all pmac db templates", + "title": "P", + "type": "string" + }, + "numAxes": { + "default": 8, + "description": "number of axes to initialize for the controller", + "title": "Numaxes", + "type": "integer" + }, + "idlePoll": { + "default": 500, + "description": "Idle Poll Period in ms", + "title": "Idlepoll", + "type": "integer" + }, + "movingPoll": { + "default": 100, + "description": "Moving Poll Period in ms", + "title": "Movingpoll", + "type": "integer" + }, + "TIMEOUT": { + "default": 4, + "description": "timeout in seconds for asyn", + "title": "Timeout", + "type": "integer" + }, + "FEEDRATE": { + "default": 100, + "description": "feedrate below which we go into error", + "title": "Feedrate", + "type": "integer" + }, + "CSG0": { + "default": "", + "description": "Name for Coordinate System Group 0", + "title": "Csg0", + "type": "string" + }, + "CSG1": { + "default": "", + "description": "Name for Coordinate System Group 1", + "title": "Csg1", + "type": "string" + }, + "CSG2": { + "default": "", + "description": "Name for Coordinate System Group 2", + "title": "Csg2", + "type": "string" + }, + "CSG3": { + "default": "", + "description": "Name for Coordinate System Group 3", + "title": "Csg3", + "type": "string" + }, + "CSG4": { + "default": "", + "description": "Name for Coordinate System Group 3", + "title": "Csg4", + "type": "string" + }, + "type": { + "const": "pmac.Geobrick", + "default": "pmac.Geobrick", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_Geobrick", + "type": "object" + }, + "pmac_PmacAsynIPPort": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name", + "title": "Name", + "type": "string" + }, + "IP": { + "default": null, + "description": "IP address of pmac", + "title": "Ip", + "type": "string" + }, + "PORT": { + "default": 1025, + "description": "TCP port for connection", + "title": "Port", + "type": "integer" + }, + "type": { + "const": "pmac.PmacAsynIPPort", + "default": "pmac.PmacAsynIPPort", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_PmacAsynIPPort", + "type": "object" + }, + "pmac_PmacAsynSSHPort": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name", + "title": "Name", + "type": "string" + }, + "IP": { + "default": null, + "description": "IP address of Power pmac", + "title": "Ip", + "type": "string" + }, + "USERNAME": { + "default": "root", + "description": "Username for login", + "title": "Username", + "type": "string" + }, + "PASSWORD": { + "default": "deltatau", + "description": "Password for login", + "title": "Password", + "type": "string" + }, + "PRIORITY": { + "default": 0, + "description": "Priority of the port", + "title": "Priority", + "type": "integer" + }, + "NOAUTOCONNECT": { + "default": 0, + "description": "Disables autoconnect if set to 1", + "title": "Noautoconnect", + "type": "integer" + }, + "NOEOS": { + "default": 0, + "description": "No EOS used if set to 1", + "title": "Noeos", + "type": "integer" + }, + "type": { + "const": "pmac.PmacAsynSSHPort", + "default": "pmac.PmacAsynSSHPort", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_PmacAsynSSHPort", + "type": "object" + }, + "pmac_autohome": { + "additionalProperties": false, + "properties": { + "Controller": { + "default": null, + "description": "the PMAC Controller", + "title": "Controller", + "type": "string" + }, + "PLC": { + "default": null, + "description": "PLC number of the auto home PLC", + "title": "Plc", + "type": "integer" + }, + "P": { + "default": null, + "description": "Prefix for auto home PVs", + "title": "P", + "type": "string" + }, + "GRP1": { + "default": "All", + "description": "name of the 'ALL' group of auto home axes", + "title": "Grp1", + "type": "string" + }, + "GRP2": { + "default": "", + "description": "name of the second group of auto home axes", + "title": "Grp2", + "type": "string" + }, + "GRP3": { + "default": "", + "description": "name of the third group of auto home axes", + "title": "Grp3", + "type": "string" + }, + "GRP4": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp4", + "type": "string" + }, + "GRP5": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp5", + "type": "string" + }, + "GRP6": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp6", + "type": "string" + }, + "GRP7": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp7", + "type": "string" + }, + "GRP8": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp8", + "type": "string" + }, + "GRP9": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp9", + "type": "string" + }, + "type": { + "const": "pmac.autohome", + "default": "pmac.autohome", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_autohome", + "type": "object" + }, + "pmac_pmacDisableLimitsCheck": { + "additionalProperties": false, + "properties": { + "Controller": { + "default": null, + "description": "Geobrick on which to disable limits", + "title": "Controller", + "type": "string" + }, + "Axis": { + "default": null, + "description": "Axis to have limits disabled", + "title": "Axis", + "type": "integer" + }, + "type": { + "const": "pmac.pmacDisableLimitsCheck", + "default": "pmac.pmacDisableLimitsCheck", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_pmacDisableLimitsCheck", + "type": "object" + }, + "psc_PscIpModule": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "A name this IP module", + "title": "Name", + "type": "string" + }, + "carrier": { + "default": null, + "description": "IPAC carrier name", + "title": "Carrier", + "type": "string" + }, + "ip_site_number": { + "default": null, + "description": "Site on the carrier for this IP Module (0=A, 1=B, 2=C, 3=D)", + "title": "Ip Site Number", + "type": "integer" + }, + "interrupt_vector": { + "default": null, + "description": "Interrupt Vector reserved with epics.InterruptVectorVME, count=3", + "title": "Interrupt Vector", + "type": "string" + }, + "link": { + "default": 0, + "description": "Link number on this IP module (0 or 1)", + "title": "Link", + "type": "integer" + }, + "type": { + "const": "psc.PscIpModule", + "default": "psc.PscIpModule", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "psc_PscIpModule", + "type": "object" + }, + "psc_PscTemplate": { + "additionalProperties": false, + "properties": { + "device": { + "default": null, + "description": "Device Name, PV Suffix", + "title": "Device", + "type": "string" + }, + "ip_module": { + "default": null, + "description": "PscIpModule object", + "title": "Ip Module", + "type": "string" + }, + "link": { + "default": null, + "description": "Link number on this IP module (0 or 1)", + "title": "Link", + "type": "integer" + }, + "i_abserr": { + "default": 0.0005, + "description": "Absolute error limit (TODO what is i_abserr vs abserr ?)", + "title": "I Abserr", + "type": "number" + }, + "abserr": { + "default": 0.0005, + "description": "Absolute error limit [0..1]", + "title": "Abserr", + "type": "number" + }, + "relerr": { + "default": 0.0002, + "description": "Relative error limit [0..1]", + "title": "Relerr", + "type": "number" + }, + "controlerr": { + "default": 0.0005, + "description": "Control Error", + "title": "Controlerr", + "type": "number" + }, + "startsw_evnt": { + "default": 53, + "description": "Event to start Soft ramps (ignore)", + "title": "Startsw Evnt", + "type": "integer" + }, + "syncsw_evnt": { + "default": 54, + "description": "Event to synchronise Soft ramps (ignore)", + "title": "Syncsw Evnt", + "type": "integer" + }, + "hyscycle_dly": { + "default": 3, + "description": "Seconds to wait in hysteresis cycle: time of PS between min and max value\n", + "title": "Hyscycle Dly", + "type": "integer" + }, + "hyscydir": { + "default": 0, + "description": "Direction of hysteresis cycle:\napproaching set point from above (-) or below (+) at the end of the cycle\n", + "title": "Hyscydir", + "type": "integer" + }, + "hyscmask": { + "default": 3, + "description": "Defines the number of hysteresis cycles to run (for values >1 (3, 7, ...)\nthe seq delay has to be specified in an extra template)\n", + "title": "Hyscmask", + "type": "integer" + }, + "hyslock": { + "default": 0, + "description": "The value \"locked\" will force the PS to do a full cycle,\nwhenever the value I-SET is changed in the wrong direction (against HYCDIR)\n", + "title": "Hyslock", + "type": "integer" + }, + "hysimin": { + "default": -3, + "description": "Minimum value for hysteresis cycle", + "title": "Hysimin", + "type": "integer" + }, + "hysimax": { + "default": 3, + "description": "Maximum value for hysteresis cycle", + "title": "Hysimax", + "type": "integer" + }, + "oninitcycle": { + "default": false, + "description": "Flag to determine if power supply should do a hysteresis cycle\nwhen it is switched ON\n", + "title": "Oninitcycle", + "type": "boolean" + }, + "vdclink_adel": { + "default": 0.3, + "description": "UNKNOWN", + "title": "Vdclink Adel", + "type": "number" + }, + "vload_adel": { + "default": 0.3, + "description": "UNKNOWN", + "title": "Vload Adel", + "type": "number" + }, + "icharge_adel": { + "default": 0.0005, + "description": "UNKNOWN", + "title": "Icharge Adel", + "type": "number" + }, + "type": { + "const": "psc.PscTemplate", + "default": "psc.PscTemplate", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "psc_PscTemplate", + "type": "object" + }, + "psc_pscHy8401Channel-BS": { + "additionalProperties": false, + "properties": { + "card": { + "default": null, + "description": "8401 card identifier", + "title": "Card", + "type": "string" + }, + "psc_template": { + "default": null, + "description": "The PSC template instance", + "title": "Psc Template", + "type": "string" + }, + "channel": { + "default": null, + "description": "8401 channel number (0-7)", + "title": "Channel", + "type": "integer" + }, + "name": { + "default": null, + "description": "Suffix for PV name for this channel", + "title": "Name", + "type": "string" + }, + "cal_m": { + "default": null, + "description": "Calibrated current multiplier", + "title": "Cal M", + "type": "number" + }, + "cal_c": { + "default": null, + "description": "Calibrated current constant", + "title": "Cal C", + "type": "number" + }, + "adel": { + "default": null, + "description": "Archive deadband for calibrated current", + "title": "Adel", + "type": "number" + }, + "type": { + "const": "psc.pscHy8401Channel-BS", + "default": "psc.pscHy8401Channel-BS", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "psc_pscHy8401Channel-BS", + "type": "object" + } + }, + "additionalProperties": false, "properties": { "ioc_name": { - "type": "string", - "description": "Name of IOC instance" + "description": "Name of IOC instance", + "title": "Ioc Name", + "type": "string" }, "description": { - "type": "string", - "description": "Description of what the IOC does" + "description": "Description of what the IOC does", + "title": "Description", + "type": "string" + }, + "generic_ioc_image": { + "description": "The generic IOC container image registry URL", + "title": "Generic Ioc Image", + "type": "string" }, "entities": { - "type": "array", + "default": [], + "description": "List of entities this IOC instantiates", "items": { "anyOf": [ { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "PORT": { - "type": "string", - "description": "Port Name for teh camera", - "vscode_ibek_plugin_type": "type_id" - }, - "P": { - "type": "string", - "description": "The PV prefix" - }, - "R": { - "type": "string", - "description": "The PV suffix" - }, - "ID": { - "type": "string", - "description": "Cam ip address, hostname, MAC address, or ID -,\n(e.g. Prosilica-02-2166A-06844)\n" - }, - "BUFFERS": { - "type": "integer", - "description": "Max NDArray buffers to be created for plugin callbacks", - "default": 50 - }, - "MEMORY": { - "type": "integer", - "description": "Max memory to allocate, should be maxw*maxh*nbuffer\nfor driver and all attached plugins or -1 for unlimited\n", - "default": -1 - }, - "TIMEOUT": { - "type": "integer", - "description": "timeout for communication with camera", - "default": 1 - }, - "PV_ALIAS": { - "type": "string", - "description": "TODO this need to look into the purpose of this in builder.py\ndetermine its function and see if we can do the equivalent in ibek\n", - "default": "" - }, - "type": { - "type": "string", - "const": "ADAravis.ADAravis", - "default": "ADAravis.ADAravis" - } - }, - "required": [ - "PORT", - "P", - "R", - "ID" - ], - "additionalProperties": false + "$ref": "#/$defs/ADAravis_ADAravis" + }, + { + "$ref": "#/$defs/ADAravis_MantaG235B" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "camera": { - "type": "string", - "description": "reference to ADAravis.ADAravis instance", - "vscode_ibek_plugin_type": "type_object" - }, - "type": { - "type": "string", - "const": "ADAravis.MantaG235B", - "default": "ADAravis.MantaG235B" - } - }, - "required": [ - "camera" - ], - "additionalProperties": false + "$ref": "#/$defs/ADAravis_Mako_G234B" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "camera": { - "type": "string", - "description": "reference to ADAravis.ADAravis instance", - "vscode_ibek_plugin_type": "type_object" - }, - "type": { - "type": "string", - "const": "ADAravis.Mako_G234B", - "default": "ADAravis.Mako_G234B" - } - }, - "required": [ - "camera" - ], - "additionalProperties": false + "$ref": "#/$defs/ADCore_NDRoi" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Name to refer to when making a channel", - "vscode_ibek_plugin_type": "type_id" - }, - "carrier": { - "type": "string", - "description": "Carrier Board Identifier", - "vscode_ibek_plugin_type": "type_object" - }, - "ip_site_number": { - "type": "integer", - "description": "IP Site Number 0=A, 1=B, 2=C, 3=D" - }, - "vector": { - "type": "string", - "description": "Interrupt Vector", - "vscode_ibek_plugin_type": "type_object" - }, - "int_enable": { - "type": "boolean", - "description": "Interrupt Enable", - "default": false - }, - "external_clock": { - "type": "boolean", - "description": "Use External Clock", - "default": false - }, - "clock_rate": { - "type": "integer", - "description": "Clock Rate", - "default": 15 - }, - "inhibit": { - "type": "boolean", - "description": "Enable front panel inhibit signal", - "default": false - }, - "sample_size": { - "type": "integer", - "description": "Number of samples for triggered capture", - "default": 0 - }, - "card_id": { - "type": "string", - "description": "Card Identifier", - "default": "{{ carrier.slot }}{{ ip_site_number }}" - }, - "type": { - "type": "string", - "const": "Hy8401ip.Hy8401ip", - "default": "Hy8401ip.Hy8401ip" - } - }, - "required": [ - "name", - "carrier", - "ip_site_number", - "vector" - ], - "additionalProperties": false + "$ref": "#/$defs/ADCore_NDStats" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "card": { - "type": "string", - "description": "8401 card identifier", - "vscode_ibek_plugin_type": "type_object" - }, - "signal": { - "type": "integer", - "description": "8401 signal number (0-7)" - }, - "type": { - "type": "string", - "const": "Hy8401ip.Hy8401Channel", - "default": "Hy8401ip.Hy8401Channel" - } - }, - "required": [ - "card", - "signal" - ], - "additionalProperties": false + "$ref": "#/$defs/Hy8401ip_Hy8401ip" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Name to refer to when making a channel", - "vscode_ibek_plugin_type": "type_id" - }, - "carrier": { - "type": "string", - "description": "Carrier Board Identifier", - "vscode_ibek_plugin_type": "type_object" - }, - "ip_site_number": { - "type": "integer", - "description": "IP Site Number 0=A, 1=B, 2=C, 3=D" - }, - "vector": { - "type": "string", - "description": "Interrupt Vector", - "vscode_ibek_plugin_type": "type_object" - }, - "aitype": { - "type": "integer", - "description": "0=differential, 1=single ended, 2=PT100, 3=Thermocouple, 4=PT100 with 8212 Transition Card, 5=Thermocouples with 8212 Transition Card" - }, - "memsize": { - "type": "integer", - "description": "1=1MB memory, 2=2MB memory" - }, - "clock_source": { - "type": "integer", - "description": "0=internal, 1=external" - }, - "clock_rate": { - "type": "integer", - "description": "Xilinx scanning frequency in Hertz. Valid values: 1,2,5,10,20,50,100 and 200 Hz." - }, - "gain": { - "type": "integer", - "description": "Gain for all ADC inputs. Valid values are: 1,2,4,8,16,32,64, 128" - }, - "vref": { - "type": "integer", - "description": "Determine the internal ADC reference voltage: =1: 1.25V =2: 2.5V" - }, - "card_id": { - "type": "string", - "description": "Card Identifier", - "default": "{{ carrier.slot }}{{ ip_site_number }}" - }, - "type": { - "type": "string", - "const": "Hy8403ip.Hy8403ip", - "default": "Hy8403ip.Hy8403ip" - } - }, - "required": [ - "name", - "carrier", - "ip_site_number", - "vector", - "aitype", - "memsize", - "clock_source", - "clock_rate", - "gain", - "vref" - ], - "additionalProperties": false + "$ref": "#/$defs/Hy8401ip_Hy8401Channel" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "device": { - "type": "string", - "description": "Device Name, PV Suffix" - }, - "card": { - "type": "string", - "description": "8403 card identifier", - "vscode_ibek_plugin_type": "type_object" - }, - "type": { - "type": "string", - "const": "Hy8403ip.Hy8403Channel", - "default": "Hy8403ip.Hy8403Channel" - } - }, - "required": [ - "device", - "card" - ], - "additionalProperties": false + "$ref": "#/$defs/Hy8403ip_Hy8403ip" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "PT": { - "type": "string", - "description": "Process Variable prefix" - }, - "ADC_REF_CHAN": { - "type": "string", - "description": "adc reference channel PV" - }, - "ADC_CHAN": { - "type": "string", - "description": "ADC channel PV" - }, - "deadband": { - "type": "number", - "description": "hysteresis value for monitor updates in Deg.C" - }, - "hihi": { - "type": "number", - "description": "hihi alarm" - }, - "hi": { - "type": "number", - "description": "hi alarm" - }, - "lo": { - "type": "number", - "description": "lo alarm" - }, - "lolo": { - "type": "number", - "description": "lolo alarm" - }, - "scan": { - "type": "number", - "description": "scan period in seconds", - "default": 1.0 - }, - "prec": { - "type": "integer", - "description": "record display precision", - "default": 0 - }, - "hopr": { - "type": "number", - "description": "high operating range", - "default": 100.0 - }, - "lopr": { - "type": "number", - "description": "low operating range", - "default": 0.0 - }, - "type": { - "type": "string", - "const": "PT100.PT100", - "default": "PT100.PT100" - } - }, - "required": [ - "PT", - "ADC_REF_CHAN", - "ADC_CHAN", - "deadband", - "hihi", - "hi", - "lo", - "lolo" - ], - "additionalProperties": false + "$ref": "#/$defs/Hy8403ip_Hy8403Channel" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "device": { - "type": "string", - "description": "The device PV prefix", - "vscode_ibek_plugin_type": "type_id" - }, - "event_receiver": { - "type": "string", - "description": "reference to EventReceiverPMC entry", - "vscode_ibek_plugin_type": "type_object" - }, - "er": { - "type": "string", - "description": "Event Receiver record suffix", - "default": "SET-ER" - }, - "type": { - "type": "string", - "const": "TimingTemplates.DefaultEVR", - "default": "TimingTemplates.DefaultEVR" - } - }, - "required": [ - "device", - "event_receiver" - ], - "additionalProperties": false + "$ref": "#/$defs/PT100_PT100" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "default_evr": { - "type": "string", - "description": "reference to DefaultEVR entry", - "vscode_ibek_plugin_type": "type_object" - }, - "type": { - "type": "string", - "const": "TimingTemplates.EvrAlive", - "default": "TimingTemplates.EvrAlive" - } - }, - "required": [ - "default_evr" - ], - "additionalProperties": false + "$ref": "#/$defs/TimingTemplates_DefaultEVR" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "device": { - "type": "string", - "description": "device name", - "vscode_ibek_plugin_type": "type_id" - }, - "gt": { - "type": "string", - "description": "generalTime PV Prefix", - "default": "GT:" - }, - "scan": { - "type": "string", - "description": "scan rate", - "default": "10 second" - }, - "type": { - "type": "string", - "const": "TimingTemplates.GeneralTime", - "default": "TimingTemplates.GeneralTime" - } - }, - "required": [ - "device" - ], - "additionalProperties": false + "$ref": "#/$defs/TimingTemplates_EvrAlive" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "ioc": { - "type": "string", - "description": "Device Prefix for this IOC" - }, - "type": { - "type": "string", - "const": "devIocStats.IocAdminSoft", - "default": "devIocStats.IocAdminSoft" - } - }, - "required": [ - "ioc" - ], - "additionalProperties": false + "$ref": "#/$defs/TimingTemplates_GeneralTime" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "max_bytes": { - "type": "integer", - "description": "Max size in bytes for sending arrays over channel access", - "default": 6000000 - }, - "type": { - "type": "string", - "const": "epics.EpicsCaMaxArrayBytes", - "default": "epics.EpicsCaMaxArrayBytes" - } - }, - "additionalProperties": false + "$ref": "#/$defs/devIocStats_IocAdminSoft" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "minutes_west": { - "type": "integer", - "description": "relative time zone minutes", - "default": 0 - }, - "type": { - "type": "string", - "const": "epics.EpicsTsMinWest", - "default": "epics.EpicsTsMinWest" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_EpicsCaMaxArrayBytes" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "pv": { - "type": "string", - "description": "Name of PV" - }, - "value": { - "type": "string", - "description": "Value to set" - }, - "type": { - "type": "string", - "const": "epics.Dbpf", - "default": "epics.Dbpf" - } - }, - "required": [ - "pv", - "value" - ], - "additionalProperties": false + "$ref": "#/$defs/epics_EpicsTsMinWest" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Name of environment variable" - }, - "value": { - "type": "string", - "description": "Value of environment variable" - }, - "type": { - "type": "string", - "const": "epics.EpicsEnvSet", - "default": "epics.EpicsEnvSet" - } - }, - "required": [ - "name", - "value" - ], - "additionalProperties": false + "$ref": "#/$defs/epics_Dbpf" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "command": { - "type": "string", - "description": "command string", - "default": "" - }, - "type": { - "type": "string", - "const": "epics.StartupCommand", - "default": "epics.StartupCommand" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_EpicsEnvSet" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "command": { - "type": "string", - "description": "command string", - "default": "" - }, - "type": { - "type": "string", - "const": "epics.PostStartupCommand", - "default": "epics.PostStartupCommand" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_StartupCommand" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "A name for an interrupt vector variable", - "vscode_ibek_plugin_type": "type_id" - }, - "count": { - "type": "integer", - "description": "The number of interrupt vectors to reserve", - "default": 1 - }, - "type": { - "type": "string", - "const": "epics.InterruptVectorVME", - "default": "epics.InterruptVectorVME" - } - }, - "required": [ - "name" - ], - "additionalProperties": false + "$ref": "#/$defs/epics_PostStartupCommand" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "port": { - "type": "string", - "description": "The port name for this asyn object" - }, - "input_eos": { - "type": "string", - "description": "Input end of string (terminator)" - }, - "output_eos": { - "type": "string", - "description": "Output end of string (terminator)" - }, - "priority": { - "type": "integer", - "description": "Priority", - "default": 100 - }, - "no_auto_connect": { - "type": "boolean", - "description": "Set to stop auto connect" - }, - "no_process_eos": { - "type": "boolean", - "description": "Set to avoid processing end of string" - }, - "simulation": { - "type": "string", - "description": "IP port to connect to if in simulation mode" - }, - "baud": { - "type": "integer", - "description": "Baud Rate" - }, - "bits": { - "type": "integer", - "description": "Bits [8,7,6,5]" - }, - "parity": { - "type": "string", - "description": "Parity [null,even,odd]" - }, - "stop": { - "type": "integer", - "description": "Stop Bits [1,2]" - }, - "crtscts": { - "type": "boolean", - "description": "Set hardware flow control on" - }, - "type": { - "type": "string", - "const": "asyn.AsynSerial", - "default": "asyn.AsynSerial" - } - }, - "required": [ - "port" - ], - "additionalProperties": false + "$ref": "#/$defs/epics_InterruptVectorVME" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "port": { - "type": "string", - "description": "Serial port tty name / IP address optionally followed by protocol" - }, - "name": { - "type": "string", - "description": "Name for the Asyn Port" - }, - "input_eos": { - "type": "string", - "description": "Input end of string (terminator)" - }, - "output_eos": { - "type": "string", - "description": "Output end of string (terminator)" - }, - "priority": { - "type": "integer", - "description": "Priority", - "default": 100 - }, - "no_auto_connect": { - "type": "boolean", - "description": "Set to stop auto connect" - }, - "no_process_eos": { - "type": "boolean", - "description": "Set to avoid processing end of string" - }, - "simulation": { - "type": "string", - "description": "IP port to connect to if in simulation mode" - }, - "type": { - "type": "string", - "const": "asyn.AsynIP", - "default": "asyn.AsynIP" - } - }, - "required": [ - "port", - "name" - ], - "additionalProperties": false + "$ref": "#/$defs/asyn_AsynSerial" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "IPAC identifier (suggested: IPAC)", - "vscode_ibek_plugin_type": "type_id" - }, - "slot": { - "type": "integer", - "description": "Crate Slot number" - }, - "int_level": { - "type": "integer", - "description": "Interrupt level", - "default": 2 - }, - "type": { - "type": "string", - "const": "ipac.Hy8002", - "default": "ipac.Hy8002" - } - }, - "required": [ - "name", - "slot" - ], - "additionalProperties": false + "$ref": "#/$defs/asyn_AsynIP" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "priority": { - "type": "integer", - "description": "Time provider priority", - "default": 10 - }, - "type": { - "type": "string", - "const": "mrfTiming.EventReceiverInit", - "default": "mrfTiming.EventReceiverInit" - } - }, - "additionalProperties": false + "$ref": "#/$defs/ipac_Hy8002" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "A name to reference this EVR", - "vscode_ibek_plugin_type": "type_id" - }, - "card_id": { - "type": "integer", - "description": "EPICS Card id" - }, - "card_index": { - "type": "integer", - "description": "PMC slot number", - "default": 0 - }, - "type": { - "type": "string", - "const": "mrfTiming.EventReceiverPMC", - "default": "mrfTiming.EventReceiverPMC" - } - }, - "required": [ - "name", - "card_id" - ], - "additionalProperties": false + "$ref": "#/$defs/mrfTiming_EventReceiverInit" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name", - "vscode_ibek_plugin_type": "type_id" - }, - "IP": { - "type": "string", - "description": "IP address of Power pmac" - }, - "USERNAME": { - "type": "string", - "description": "Username for login", - "default": "root" - }, - "PASSWORD": { - "type": "string", - "description": "Password for login", - "default": "deltatau" - }, - "PRIORITY": { - "type": "integer", - "description": "Priority of the port", - "default": 0 - }, - "NOAUTOCONNECT": { - "type": "integer", - "description": "Disables autoconnect if set to 1", - "default": 0 - }, - "NOEOS": { - "type": "integer", - "description": "No EOS used if set to 1", - "default": 0 - }, - "type": { - "type": "string", - "const": "pmac.PmacAsynSSHPort", - "default": "pmac.PmacAsynSSHPort" - } - }, - "required": [ - "name", - "IP" - ], - "additionalProperties": false + "$ref": "#/$defs/mrfTiming_EventReceiverPMC" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name", - "vscode_ibek_plugin_type": "type_id" - }, - "IP": { - "type": "string", - "description": "IP address of pmac" - }, - "PORT": { - "type": "integer", - "description": "TCP port for connection", - "default": 1025 - }, - "type": { - "type": "string", - "const": "pmac.PmacAsynIPPort", - "default": "pmac.PmacAsynIPPort" - } - }, - "required": [ - "name", - "IP" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_PmacAsynSSHPort" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Name to use for the geobrick's asyn port", - "vscode_ibek_plugin_type": "type_id" - }, - "PORT": { - "type": "string", - "description": "Asyn port name for PmacAsynIPPort to connect to", - "vscode_ibek_plugin_type": "type_object" - }, - "P": { - "type": "string", - "description": "PV Prefix for all pmac db templates" - }, - "numAxes": { - "type": "integer", - "description": "number of axes to initialize for the controller", - "default": 8 - }, - "idlePoll": { - "type": "integer", - "description": "Idle Poll Period in ms", - "default": 500 - }, - "movingPoll": { - "type": "integer", - "description": "Moving Poll Period in ms", - "default": 100 - }, - "TIMEOUT": { - "type": "integer", - "description": "timeout in seconds for asyn", - "default": 4 - }, - "FEEDRATE": { - "type": "integer", - "description": "feedrate below which we go into error", - "default": 100 - }, - "CSG0": { - "type": "string", - "description": "Name for Coordinate System Group 0", - "default": "" - }, - "CSG1": { - "type": "string", - "description": "Name for Coordinate System Group 1", - "default": "" - }, - "CSG2": { - "type": "string", - "description": "Name for Coordinate System Group 2", - "default": "" - }, - "CSG3": { - "type": "string", - "description": "Name for Coordinate System Group 3", - "default": "" - }, - "CSG4": { - "type": "string", - "description": "Name for Coordinate System Group 3", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.Geobrick", - "default": "pmac.Geobrick" - } - }, - "required": [ - "name", - "PORT", - "P" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_PmacAsynIPPort" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Object name and gui association name" - }, - "Controller": { - "type": "string", - "description": "PMAC Controller to attach to", - "vscode_ibek_plugin_type": "type_object" - }, - "axis": { - "type": "integer", - "description": "which axis number this motor drives" - }, - "P": { - "type": "string", - "description": "PV prefix name for this motor" - }, - "M": { - "type": "string", - "description": "PV motor name for this motor" - }, - "DESC": { - "type": "string", - "description": "Description, displayed on EDM screen", - "default": "" - }, - "MRES": { - "type": "number", - "description": "Motor Step Size (EGU)", - "default": 0.0001 - }, - "VELO": { - "type": "number", - "description": "axis Velocity (EGU/s)", - "default": 1.0 - }, - "PREC": { - "type": "integer", - "description": "Display Precision", - "default": 3 - }, - "EGU": { - "type": "string", - "description": "Engineering Units", - "default": "mm" - }, - "TWV": { - "type": "number", - "description": "Tweak Step Size (EGU)", - "default": 1.0 - }, - "DTYP": { - "type": "string", - "description": "Datatype of record", - "default": "asynMotor" - }, - "DIR": { - "type": "integer", - "description": "User direction", - "default": 0 - }, - "VBAS": { - "type": "number", - "description": "Base Velocity (EGU/s)", - "default": 1.0 - }, - "VMAX": { - "type": "string", - "description": "Max Velocity (EGU/s)", - "default": "{{VELO}}" - }, - "ACCL": { - "type": "number", - "description": "Seconds to Velocity", - "default": 0.5 - }, - "BDST": { - "type": "number", - "description": "BL Distance (EGU)", - "default": 0.0 - }, - "BVEL": { - "type": "number", - "description": "BL Velocity(EGU/s)", - "default": 0.0 - }, - "BACC": { - "type": "number", - "description": "BL Seconds to Veloc", - "default": 0.0 - }, - "DHLM": { - "type": "number", - "description": "Dial High Limit", - "default": 10000.0 - }, - "DLLM": { - "type": "number", - "description": "Dial low limit", - "default": -10000.0 - }, - "HLM": { - "type": "number", - "description": "User High Limit", - "default": 0.0 - }, - "LLM": { - "type": "number", - "description": "User Low Limit", - "default": 0.0 - }, - "HLSV": { - "type": "string", - "description": "HW Lim, Violation Svr", - "default": "MAJOR" - }, - "INIT": { - "type": "string", - "description": "Startup commands", - "default": "" - }, - "SREV": { - "type": "integer", - "description": "Steps per Revolution", - "default": 1000 - }, - "RRES": { - "type": "number", - "description": "Readback Step Size (EGU", - "default": 0.0 - }, - "ERES": { - "type": "number", - "description": "Encoder Step Size (EGU)", - "default": 0.0 - }, - "JAR": { - "type": "number", - "description": "Jog Acceleration (EGU/s^2)", - "default": 0.0 - }, - "UEIP": { - "type": "integer", - "description": "Use Encoder If Present", - "default": 0 - }, - "URIP": { - "type": "integer", - "description": "Use RDBL If Present", - "default": 0 - }, - "RDBL": { - "type": "string", - "description": "Readback Location, set URIP =1 if you specify this", - "default": "0" - }, - "RLNK": { - "type": "string", - "description": "Readback output link", - "default": "" - }, - "RTRY": { - "type": "integer", - "description": "Max retry count", - "default": 0 - }, - "DLY": { - "type": "number", - "description": "Readback settle time (s)", - "default": 0.0 - }, - "OFF": { - "type": "number", - "description": "User Offset (EGU)", - "default": 0.0 - }, - "RDBD": { - "type": "number", - "description": "Retry Deadband (EGU)", - "default": 0.0 - }, - "FOFF": { - "type": "integer", - "description": "Freeze Offset, 0=variable, 1=frozen", - "default": 0 - }, - "ADEL": { - "type": "number", - "description": "Alarm monitor deadband (EGU)", - "default": 0.0 - }, - "NTM": { - "type": "integer", - "description": "New Target Monitor, only set to 0 for soft motors", - "default": 1 - }, - "FEHIGH": { - "type": "number", - "description": "HIGH limit for following error", - "default": 0.0 - }, - "FEHIHI": { - "type": "number", - "description": "HIHI limit for following error", - "default": 0.0 - }, - "FEHHSV": { - "type": "string", - "description": "HIHI alarm severity for following error", - "default": "NO_ALARM" - }, - "FEHSV": { - "type": "string", - "description": "HIGH alarm severity for following error", - "default": "NO_ALARM" - }, - "SCALE": { - "type": "integer", - "default": 1 - }, - "HOMEVIS": { - "type": "integer", - "description": "If 1 then home is visible on the gui", - "default": 1 - }, - "HOMEVISSTR": { - "type": "string", - "default": "Use motor summary screen" - }, - "alh": { - "type": "string", - "description": "Set this to alh to add the motor to the alarm handler and send emails", - "default": "" - }, - "HOME": { - "type": "string", - "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", - "default": "{{P}}" - }, - "ALLOW_HOMED_SET": { - "type": "string", - "description": "Set to a blank to allow this axis to have its homed", - "default": "#" - }, - "RLINK": { - "type": "string", - "description": "not sure what this is", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.DlsPmacAsynMotor", - "default": "pmac.DlsPmacAsynMotor" - } - }, - "required": [ - "name", - "Controller", - "axis", - "P", - "M" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_Geobrick" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Object name and gui association name" - }, - "CsController": { - "type": "string", - "description": "Coordinate system controller to attach to", - "vscode_ibek_plugin_type": "type_object" - }, - "axis": { - "type": "integer", - "description": "which axis number this motor drives" - }, - "P": { - "type": "string", - "description": "PV prefix name for this motor" - }, - "M": { - "type": "string", - "description": "PV motor name for this motor" - }, - "DESC": { - "type": "string", - "description": "Description, displayed on EDM screen", - "default": "" - }, - "MRES": { - "type": "number", - "description": "Motor Step Size (EGU)", - "default": 0.0001 - }, - "VELO": { - "type": "number", - "description": "axis Velocity (EGU/s)", - "default": 1.0 - }, - "PREC": { - "type": "integer", - "description": "Display Precision", - "default": 3 - }, - "EGU": { - "type": "string", - "description": "Engineering Units", - "default": "mm" - }, - "TWV": { - "type": "number", - "description": "Tweak Step Size (EGU)", - "default": 1.0 - }, - "DTYP": { - "type": "string", - "description": "Datatype of record", - "default": "asynMotor" - }, - "DIR": { - "type": "integer", - "description": "User direction", - "default": 0 - }, - "VBAS": { - "type": "number", - "description": "Base Velocity (EGU/s)", - "default": 1.0 - }, - "VMAX": { - "type": "string", - "description": "Max Velocity (EGU/s)", - "default": "{{VELO}}" - }, - "ACCL": { - "type": "number", - "description": "Seconds to Velocity", - "default": 0.5 - }, - "BDST": { - "type": "number", - "description": "BL Distance (EGU)", - "default": 0.0 - }, - "BVEL": { - "type": "number", - "description": "BL Velocity(EGU/s)", - "default": 0.0 - }, - "BACC": { - "type": "number", - "description": "BL Seconds to Veloc", - "default": 0.0 - }, - "DHLM": { - "type": "number", - "description": "Dial High Limit", - "default": 10000.0 - }, - "DLLM": { - "type": "number", - "description": "Dial low limit", - "default": -10000.0 - }, - "HLM": { - "type": "number", - "description": "User High Limit", - "default": 0.0 - }, - "LLM": { - "type": "number", - "description": "User Low Limit", - "default": 0.0 - }, - "HLSV": { - "type": "string", - "description": "HW Lim, Violation Svr", - "default": "MAJOR" - }, - "INIT": { - "type": "string", - "description": "Startup commands", - "default": "" - }, - "SREV": { - "type": "integer", - "description": "Steps per Revolution", - "default": 1000 - }, - "RRES": { - "type": "number", - "description": "Readback Step Size (EGU", - "default": 0.0 - }, - "ERES": { - "type": "number", - "description": "Encoder Step Size (EGU)", - "default": 0.0 - }, - "JAR": { - "type": "number", - "description": "Jog Acceleration (EGU/s^2)", - "default": 0.0 - }, - "UEIP": { - "type": "integer", - "description": "Use Encoder If Present", - "default": 0 - }, - "URIP": { - "type": "integer", - "description": "Use RDBL If Present", - "default": 0 - }, - "RDBL": { - "type": "string", - "description": "Readback Location, set URIP =1 if you specify this", - "default": "0" - }, - "RLNK": { - "type": "string", - "description": "Readback output link", - "default": "" - }, - "RTRY": { - "type": "integer", - "description": "Max retry count", - "default": 0 - }, - "DLY": { - "type": "number", - "description": "Readback settle time (s)", - "default": 0.0 - }, - "OFF": { - "type": "number", - "description": "User Offset (EGU)", - "default": 0.0 - }, - "RDBD": { - "type": "number", - "description": "Retry Deadband (EGU)", - "default": 0.0 - }, - "FOFF": { - "type": "integer", - "description": "Freeze Offset, 0=variable, 1=frozen", - "default": 0 - }, - "ADEL": { - "type": "number", - "description": "Alarm monitor deadband (EGU)", - "default": 0.0 - }, - "NTM": { - "type": "integer", - "description": "New Target Monitor, only set to 0 for soft motors", - "default": 1 - }, - "FEHEIGH": { - "type": "number", - "description": "HIGH limit for following error", - "default": 0.0 - }, - "FEHIHI": { - "type": "number", - "description": "HIHI limit for following error", - "default": 0.0 - }, - "FEHHSV": { - "type": "string", - "description": "HIHI alarm severity for following error", - "default": "NO_ALARM" - }, - "FEHSV": { - "type": "string", - "description": "HIGH alarm severity for following error", - "default": "NO_ALARM" - }, - "SCALE": { - "type": "integer", - "default": 1 - }, - "HOMEVIS": { - "type": "integer", - "description": "If 1 then home is visible on the gui", - "default": 1 - }, - "HOMEVISSTR": { - "type": "string", - "default": "Use motor summary screen" - }, - "alh": { - "type": "string", - "description": "Set this to alh to add the motor to the alarm handler and send emails", - "default": "" - }, - "HOME": { - "type": "string", - "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", - "default": "{{P}}" - }, - "ALLOW_HOMED_SET": { - "type": "string", - "description": "Set to a blank to allow this axis to have its homed", - "default": "#" - }, - "type": { - "type": "string", - "const": "pmac.DlsCsPmacAsynMotor", - "default": "pmac.DlsCsPmacAsynMotor" - } - }, - "required": [ - "name", - "CsController", - "axis", - "P", - "M" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_DlsPmacAsynMotor" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "Controller": { - "type": "string", - "description": "Geobrick on which to disable limits", - "vscode_ibek_plugin_type": "type_object" - }, - "Axis": { - "type": "integer", - "description": "Axis to have limits disabled" - }, - "type": { - "type": "string", - "const": "pmac.pmacDisableLimitsCheck", - "default": "pmac.pmacDisableLimitsCheck" - } - }, - "required": [ - "Controller", - "Axis" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "Controller": { - "type": "string", - "description": "the PMAC Controller", - "vscode_ibek_plugin_type": "type_object" - }, - "PLC": { - "type": "integer", - "description": "PLC number of the auto home PLC" - }, - "P": { - "type": "string", - "description": "Prefix for auto home PVs" - }, - "GRP1": { - "type": "string", - "description": "name of the 'ALL' group of auto home axes", - "default": "All" - }, - "GRP2": { - "type": "string", - "description": "name of the second group of auto home axes", - "default": "" - }, - "GRP3": { - "type": "string", - "description": "name of the third group of auto home axes", - "default": "" - }, - "GRP4": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP5": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP6": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP7": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP8": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP9": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.autohome", - "default": "pmac.autohome" - } - }, - "required": [ - "Controller", - "PLC", - "P" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name for this object", - "vscode_ibek_plugin_type": "type_id" - }, - "Controller": { - "type": "string", - "description": "the PMAC Controller", - "vscode_ibek_plugin_type": "type_object" - }, - "CS": { - "type": "integer", - "description": "Coordinate system number" - }, - "NAxes": { - "type": "integer", - "description": "number of CS axes", - "default": 9 - }, - "Program": { - "type": "integer", - "description": "PROG number for CS motion", - "default": 10 - }, - "type": { - "type": "string", - "const": "pmac.CS", - "default": "pmac.CS" - } - }, - "required": [ - "name", - "Controller", - "CS" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_autohome" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "A name this IP module", - "vscode_ibek_plugin_type": "type_id" - }, - "carrier": { - "type": "string", - "description": "IPAC carrier name", - "vscode_ibek_plugin_type": "type_object" - }, - "ip_site_number": { - "type": "integer", - "description": "Site on the carrier for this IP Module (0=A, 1=B, 2=C, 3=D)" - }, - "interrupt_vector": { - "type": "string", - "description": "Interrupt Vector reserved with epics.InterruptVectorVME, count=3", - "vscode_ibek_plugin_type": "type_object" - }, - "link": { - "type": "integer", - "description": "Link number on this IP module (0 or 1)", - "default": 0 - }, - "type": { - "type": "string", - "const": "psc.PscIpModule", - "default": "psc.PscIpModule" - } - }, - "required": [ - "name", - "carrier", - "ip_site_number", - "interrupt_vector" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_CS" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "device": { - "type": "string", - "description": "Device Name, PV Suffix", - "vscode_ibek_plugin_type": "type_id" - }, - "ip_module": { - "type": "string", - "description": "PscIpModule object", - "vscode_ibek_plugin_type": "type_object" - }, - "link": { - "type": "integer", - "description": "Link number on this IP module (0 or 1)" - }, - "i_abserr": { - "type": "number", - "description": "Absolute error limit (TODO what is i_abserr vs abserr ?)", - "default": 0.0005 - }, - "abserr": { - "type": "number", - "description": "Absolute error limit [0..1]", - "default": 0.0005 - }, - "relerr": { - "type": "number", - "description": "Relative error limit [0..1]", - "default": 0.0002 - }, - "controlerr": { - "type": "number", - "description": "Control Error", - "default": 0.0005 - }, - "startsw_evnt": { - "type": "integer", - "description": "Event to start Soft ramps (ignore)", - "default": 53 - }, - "syncsw_evnt": { - "type": "integer", - "description": "Event to synchronise Soft ramps (ignore)", - "default": 54 - }, - "hyscycle_dly": { - "type": "integer", - "description": "Seconds to wait in hysteresis cycle: time of PS between min and max value\n", - "default": 3 - }, - "hyscydir": { - "type": "integer", - "description": "Direction of hysteresis cycle:\napproaching set point from above (-) or below (+) at the end of the cycle\n", - "default": 0 - }, - "hyscmask": { - "type": "integer", - "description": "Defines the number of hysteresis cycles to run (for values >1 (3, 7, ...)\nthe seq delay has to be specified in an extra template)\n", - "default": 3 - }, - "hyslock": { - "type": "integer", - "description": "The value \"locked\" will force the PS to do a full cycle,\nwhenever the value I-SET is changed in the wrong direction (against HYCDIR)\n", - "default": 0 - }, - "hysimin": { - "type": "integer", - "description": "Minimum value for hysteresis cycle", - "default": -3 - }, - "hysimax": { - "type": "integer", - "description": "Maximum value for hysteresis cycle", - "default": 3 - }, - "oninitcycle": { - "type": "boolean", - "description": "Flag to determine if power supply should do a hysteresis cycle\nwhen it is switched ON\n", - "default": false - }, - "vdclink_adel": { - "type": "number", - "description": "UNKNOWN", - "default": 0.3 - }, - "vload_adel": { - "type": "number", - "description": "UNKNOWN", - "default": 0.3 - }, - "icharge_adel": { - "type": "number", - "description": "UNKNOWN", - "default": 0.0005 - }, - "type": { - "type": "string", - "const": "psc.PscTemplate", - "default": "psc.PscTemplate" - } - }, - "required": [ - "device", - "ip_module", - "link" - ], - "additionalProperties": false + "$ref": "#/$defs/psc_PscIpModule" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "card": { - "type": "string", - "description": "8401 card identifier", - "vscode_ibek_plugin_type": "type_object" - }, - "psc_template": { - "type": "string", - "description": "The PSC template instance", - "vscode_ibek_plugin_type": "type_object" - }, - "channel": { - "type": "integer", - "description": "8401 channel number (0-7)" - }, - "name": { - "type": "string", - "description": "Suffix for PV name for this channel" - }, - "cal_m": { - "type": "number", - "description": "Calibrated current multiplier" - }, - "cal_c": { - "type": "number", - "description": "Calibrated current constant" - }, - "adel": { - "type": "number", - "description": "Archive deadband for calibrated current" - }, - "type": { - "type": "string", - "const": "psc.pscHy8401Channel-BS", - "default": "psc.pscHy8401Channel-BS" - } - }, - "required": [ - "card", - "psc_template", - "channel", - "name", - "cal_m", - "cal_c", - "adel" - ], - "additionalProperties": false + "$ref": "#/$defs/psc_PscTemplate" + }, + { + "$ref": "#/$defs/psc_pscHy8401Channel-BS" } ] }, - "description": "List of entities this IOC instantiates" - }, - "generic_ioc_image": { - "type": "string", - "description": "The generic IOC container image registry URL" + "title": "Entities", + "type": "array" } }, "required": [ "ioc_name", "description", - "entities", "generic_ioc_image" ], - "additionalProperties": false, - "$schema": "http://json-schema.org/draft-07/schema#" + "title": "NewIOC", + "type": "object" } \ No newline at end of file diff --git a/tests/samples/schemas/asyn.ibek.entities.schema.json b/tests/samples/schemas/asyn.ibek.entities.schema.json index 301b369b0..c9c077781 100644 --- a/tests/samples/schemas/asyn.ibek.entities.schema.json +++ b/tests/samples/schemas/asyn.ibek.entities.schema.json @@ -1,152 +1,191 @@ { - "type": "object", + "$defs": { + "asyn_AsynIP": { + "additionalProperties": false, + "properties": { + "port": { + "default": null, + "description": "Serial port tty name / IP address optionally followed by protocol", + "title": "Port", + "type": "string" + }, + "name": { + "default": null, + "description": "Name for the Asyn Port", + "title": "Name", + "type": "string" + }, + "input_eos": { + "default": null, + "description": "Input end of string (terminator)", + "title": "Input Eos", + "type": "string" + }, + "output_eos": { + "default": null, + "description": "Output end of string (terminator)", + "title": "Output Eos", + "type": "string" + }, + "priority": { + "default": 100, + "description": "Priority", + "title": "Priority", + "type": "integer" + }, + "no_auto_connect": { + "default": null, + "description": "Set to stop auto connect", + "title": "No Auto Connect", + "type": "boolean" + }, + "no_process_eos": { + "default": null, + "description": "Set to avoid processing end of string", + "title": "No Process Eos", + "type": "boolean" + }, + "simulation": { + "default": null, + "description": "IP port to connect to if in simulation mode", + "title": "Simulation", + "type": "string" + }, + "type": { + "const": "asyn.AsynIP", + "default": "asyn.AsynIP", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "asyn_AsynIP", + "type": "object" + }, + "asyn_AsynSerial": { + "additionalProperties": false, + "properties": { + "port": { + "default": null, + "description": "The port name for this asyn object", + "title": "Port", + "type": "string" + }, + "input_eos": { + "default": null, + "description": "Input end of string (terminator)", + "title": "Input Eos", + "type": "string" + }, + "output_eos": { + "default": null, + "description": "Output end of string (terminator)", + "title": "Output Eos", + "type": "string" + }, + "priority": { + "default": 100, + "description": "Priority", + "title": "Priority", + "type": "integer" + }, + "no_auto_connect": { + "default": null, + "description": "Set to stop auto connect", + "title": "No Auto Connect", + "type": "boolean" + }, + "no_process_eos": { + "default": null, + "description": "Set to avoid processing end of string", + "title": "No Process Eos", + "type": "boolean" + }, + "simulation": { + "default": null, + "description": "IP port to connect to if in simulation mode", + "title": "Simulation", + "type": "string" + }, + "baud": { + "default": null, + "description": "Baud Rate", + "title": "Baud", + "type": "integer" + }, + "bits": { + "default": null, + "description": "Bits [8,7,6,5]", + "title": "Bits", + "type": "integer" + }, + "parity": { + "default": null, + "description": "Parity [null,even,odd]", + "title": "Parity", + "type": "string" + }, + "stop": { + "default": null, + "description": "Stop Bits [1,2]", + "title": "Stop", + "type": "integer" + }, + "crtscts": { + "default": null, + "description": "Set hardware flow control on", + "title": "Crtscts", + "type": "boolean" + }, + "type": { + "const": "asyn.AsynSerial", + "default": "asyn.AsynSerial", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "asyn_AsynSerial", + "type": "object" + } + }, + "additionalProperties": false, "properties": { "ioc_name": { - "type": "string", - "description": "Name of IOC instance" + "description": "Name of IOC instance", + "title": "Ioc Name", + "type": "string" }, "description": { - "type": "string", - "description": "Description of what the IOC does" + "description": "Description of what the IOC does", + "title": "Description", + "type": "string" + }, + "generic_ioc_image": { + "description": "The generic IOC container image registry URL", + "title": "Generic Ioc Image", + "type": "string" }, "entities": { - "type": "array", + "default": [], + "description": "List of entities this IOC instantiates", "items": { "anyOf": [ { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "port": { - "type": "string", - "description": "The port name for this asyn object" - }, - "input_eos": { - "type": "string", - "description": "Input end of string (terminator)" - }, - "output_eos": { - "type": "string", - "description": "Output end of string (terminator)" - }, - "priority": { - "type": "integer", - "description": "Priority", - "default": 100 - }, - "no_auto_connect": { - "type": "boolean", - "description": "Set to stop auto connect" - }, - "no_process_eos": { - "type": "boolean", - "description": "Set to avoid processing end of string" - }, - "simulation": { - "type": "string", - "description": "IP port to connect to if in simulation mode" - }, - "baud": { - "type": "integer", - "description": "Baud Rate" - }, - "bits": { - "type": "integer", - "description": "Bits [8,7,6,5]" - }, - "parity": { - "type": "string", - "description": "Parity [null,even,odd]" - }, - "stop": { - "type": "integer", - "description": "Stop Bits [1,2]" - }, - "crtscts": { - "type": "boolean", - "description": "Set hardware flow control on" - }, - "type": { - "type": "string", - "const": "asyn.AsynSerial", - "default": "asyn.AsynSerial" - } - }, - "required": [ - "port" - ], - "additionalProperties": false + "$ref": "#/$defs/asyn_AsynSerial" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "port": { - "type": "string", - "description": "Serial port tty name / IP address optionally followed by protocol" - }, - "name": { - "type": "string", - "description": "Name for the Asyn Port" - }, - "input_eos": { - "type": "string", - "description": "Input end of string (terminator)" - }, - "output_eos": { - "type": "string", - "description": "Output end of string (terminator)" - }, - "priority": { - "type": "integer", - "description": "Priority", - "default": 100 - }, - "no_auto_connect": { - "type": "boolean", - "description": "Set to stop auto connect" - }, - "no_process_eos": { - "type": "boolean", - "description": "Set to avoid processing end of string" - }, - "simulation": { - "type": "string", - "description": "IP port to connect to if in simulation mode" - }, - "type": { - "type": "string", - "const": "asyn.AsynIP", - "default": "asyn.AsynIP" - } - }, - "required": [ - "port", - "name" - ], - "additionalProperties": false + "$ref": "#/$defs/asyn_AsynIP" } ] }, - "description": "List of entities this IOC instantiates" - }, - "generic_ioc_image": { - "type": "string", - "description": "The generic IOC container image registry URL" + "title": "Entities", + "type": "array" } }, "required": [ "ioc_name", "description", - "entities", "generic_ioc_image" ], - "additionalProperties": false, - "$schema": "http://json-schema.org/draft-07/schema#" + "title": "NewIOC", + "type": "object" } \ No newline at end of file diff --git a/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json b/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json index 84c0f9d96..3427a8ea2 100644 --- a/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json +++ b/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json @@ -1,1052 +1,1197 @@ { - "type": "object", + "$defs": { + "epics_Dbpf": { + "additionalProperties": false, + "properties": { + "pv": { + "default": null, + "description": "Name of PV", + "title": "Pv", + "type": "string" + }, + "value": { + "default": null, + "description": "Value to set", + "title": "Value", + "type": "string" + }, + "type": { + "const": "epics.Dbpf", + "default": "epics.Dbpf", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_Dbpf", + "type": "object" + }, + "epics_EpicsCaMaxArrayBytes": { + "additionalProperties": false, + "properties": { + "max_bytes": { + "default": 6000000, + "description": "Max size in bytes for sending arrays over channel access", + "title": "Max Bytes", + "type": "integer" + }, + "type": { + "const": "epics.EpicsCaMaxArrayBytes", + "default": "epics.EpicsCaMaxArrayBytes", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_EpicsCaMaxArrayBytes", + "type": "object" + }, + "epics_EpicsEnvSet": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Name of environment variable", + "title": "Name", + "type": "string" + }, + "value": { + "default": null, + "description": "Value of environment variable", + "title": "Value", + "type": "string" + }, + "type": { + "const": "epics.EpicsEnvSet", + "default": "epics.EpicsEnvSet", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_EpicsEnvSet", + "type": "object" + }, + "epics_EpicsTsMinWest": { + "additionalProperties": false, + "properties": { + "minutes_west": { + "default": 0, + "description": "relative time zone minutes", + "title": "Minutes West", + "type": "integer" + }, + "type": { + "const": "epics.EpicsTsMinWest", + "default": "epics.EpicsTsMinWest", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_EpicsTsMinWest", + "type": "object" + }, + "epics_InterruptVectorVME": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "A name for an interrupt vector variable", + "title": "Name", + "type": "string" + }, + "count": { + "default": 1, + "description": "The number of interrupt vectors to reserve", + "title": "Count", + "type": "integer" + }, + "type": { + "const": "epics.InterruptVectorVME", + "default": "epics.InterruptVectorVME", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_InterruptVectorVME", + "type": "object" + }, + "epics_PostStartupCommand": { + "additionalProperties": false, + "properties": { + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" + }, + "type": { + "const": "epics.PostStartupCommand", + "default": "epics.PostStartupCommand", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_PostStartupCommand", + "type": "object" + }, + "epics_StartupCommand": { + "additionalProperties": false, + "properties": { + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" + }, + "type": { + "const": "epics.StartupCommand", + "default": "epics.StartupCommand", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_StartupCommand", + "type": "object" + }, + "pmac_CS": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name for this object", + "title": "Name", + "type": "string" + }, + "Controller": { + "default": null, + "description": "the PMAC Controller", + "title": "Controller", + "type": "string" + }, + "CS": { + "default": null, + "description": "Coordinate system number", + "title": "Cs", + "type": "integer" + }, + "NAxes": { + "default": 9, + "description": "number of CS axes", + "title": "Naxes", + "type": "integer" + }, + "Program": { + "default": 10, + "description": "PROG number for CS motion", + "title": "Program", + "type": "integer" + }, + "type": { + "const": "pmac.CS", + "default": "pmac.CS", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_CS", + "type": "object" + }, + "pmac_DlsCsPmacAsynMotor": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Object name and gui association name", + "title": "Name", + "type": "string" + }, + "CsController": { + "default": null, + "description": "Coordinate system controller to attach to", + "title": "Cscontroller", + "type": "string" + }, + "axis": { + "default": null, + "description": "which axis number this motor drives", + "title": "Axis", + "type": "integer" + }, + "P": { + "default": null, + "description": "PV prefix name for this motor", + "title": "P", + "type": "string" + }, + "M": { + "default": null, + "description": "PV motor name for this motor", + "title": "M", + "type": "string" + }, + "DESC": { + "default": "", + "description": "Description, displayed on EDM screen", + "title": "Desc", + "type": "string" + }, + "MRES": { + "default": 0.0001, + "description": "Motor Step Size (EGU)", + "title": "Mres", + "type": "number" + }, + "VELO": { + "default": 1.0, + "description": "axis Velocity (EGU/s)", + "title": "Velo", + "type": "number" + }, + "PREC": { + "default": 3, + "description": "Display Precision", + "title": "Prec", + "type": "integer" + }, + "EGU": { + "default": "mm", + "description": "Engineering Units", + "title": "Egu", + "type": "string" + }, + "TWV": { + "default": 1.0, + "description": "Tweak Step Size (EGU)", + "title": "Twv", + "type": "number" + }, + "DTYP": { + "default": "asynMotor", + "description": "Datatype of record", + "title": "Dtyp", + "type": "string" + }, + "DIR": { + "default": 0, + "description": "User direction", + "title": "Dir", + "type": "integer" + }, + "VBAS": { + "default": 1.0, + "description": "Base Velocity (EGU/s)", + "title": "Vbas", + "type": "number" + }, + "VMAX": { + "default": "{{VELO}}", + "description": "Max Velocity (EGU/s)", + "title": "Vmax", + "type": "string" + }, + "ACCL": { + "default": 0.5, + "description": "Seconds to Velocity", + "title": "Accl", + "type": "number" + }, + "BDST": { + "default": 0.0, + "description": "BL Distance (EGU)", + "title": "Bdst", + "type": "number" + }, + "BVEL": { + "default": 0.0, + "description": "BL Velocity(EGU/s)", + "title": "Bvel", + "type": "number" + }, + "BACC": { + "default": 0.0, + "description": "BL Seconds to Veloc", + "title": "Bacc", + "type": "number" + }, + "DHLM": { + "default": 10000.0, + "description": "Dial High Limit", + "title": "Dhlm", + "type": "number" + }, + "DLLM": { + "default": -10000.0, + "description": "Dial low limit", + "title": "Dllm", + "type": "number" + }, + "HLM": { + "default": 0.0, + "description": "User High Limit", + "title": "Hlm", + "type": "number" + }, + "LLM": { + "default": 0.0, + "description": "User Low Limit", + "title": "Llm", + "type": "number" + }, + "HLSV": { + "default": "MAJOR", + "description": "HW Lim, Violation Svr", + "title": "Hlsv", + "type": "string" + }, + "INIT": { + "default": "", + "description": "Startup commands", + "title": "Init", + "type": "string" + }, + "SREV": { + "default": 1000, + "description": "Steps per Revolution", + "title": "Srev", + "type": "integer" + }, + "RRES": { + "default": 0.0, + "description": "Readback Step Size (EGU", + "title": "Rres", + "type": "number" + }, + "ERES": { + "default": 0.0, + "description": "Encoder Step Size (EGU)", + "title": "Eres", + "type": "number" + }, + "JAR": { + "default": 0.0, + "description": "Jog Acceleration (EGU/s^2)", + "title": "Jar", + "type": "number" + }, + "UEIP": { + "default": 0, + "description": "Use Encoder If Present", + "title": "Ueip", + "type": "integer" + }, + "URIP": { + "default": 0, + "description": "Use RDBL If Present", + "title": "Urip", + "type": "integer" + }, + "RDBL": { + "default": "0", + "description": "Readback Location, set URIP =1 if you specify this", + "title": "Rdbl", + "type": "string" + }, + "RLNK": { + "default": "", + "description": "Readback output link", + "title": "Rlnk", + "type": "string" + }, + "RTRY": { + "default": 0, + "description": "Max retry count", + "title": "Rtry", + "type": "integer" + }, + "DLY": { + "default": 0.0, + "description": "Readback settle time (s)", + "title": "Dly", + "type": "number" + }, + "OFF": { + "default": 0.0, + "description": "User Offset (EGU)", + "title": "Off", + "type": "number" + }, + "RDBD": { + "default": 0.0, + "description": "Retry Deadband (EGU)", + "title": "Rdbd", + "type": "number" + }, + "FOFF": { + "default": 0, + "description": "Freeze Offset, 0=variable, 1=frozen", + "title": "Foff", + "type": "integer" + }, + "ADEL": { + "default": 0.0, + "description": "Alarm monitor deadband (EGU)", + "title": "Adel", + "type": "number" + }, + "NTM": { + "default": 1, + "description": "New Target Monitor, only set to 0 for soft motors", + "title": "Ntm", + "type": "integer" + }, + "FEHEIGH": { + "default": 0.0, + "description": "HIGH limit for following error", + "title": "Feheigh", + "type": "number" + }, + "FEHIHI": { + "default": 0.0, + "description": "HIHI limit for following error", + "title": "Fehihi", + "type": "number" + }, + "FEHHSV": { + "default": "NO_ALARM", + "description": "HIHI alarm severity for following error", + "title": "Fehhsv", + "type": "string" + }, + "FEHSV": { + "default": "NO_ALARM", + "description": "HIGH alarm severity for following error", + "title": "Fehsv", + "type": "string" + }, + "SCALE": { + "default": 1, + "description": "", + "title": "Scale", + "type": "integer" + }, + "HOMEVIS": { + "default": 1, + "description": "If 1 then home is visible on the gui", + "title": "Homevis", + "type": "integer" + }, + "HOMEVISSTR": { + "default": "Use motor summary screen", + "description": "", + "title": "Homevisstr", + "type": "string" + }, + "alh": { + "default": "", + "description": "Set this to alh to add the motor to the alarm handler and send emails", + "title": "Alh", + "type": "string" + }, + "HOME": { + "default": "{{P}}", + "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", + "title": "Home", + "type": "string" + }, + "ALLOW_HOMED_SET": { + "default": "#", + "description": "Set to a blank to allow this axis to have its homed", + "title": "Allow Homed Set", + "type": "string" + }, + "type": { + "const": "pmac.DlsCsPmacAsynMotor", + "default": "pmac.DlsCsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_DlsCsPmacAsynMotor", + "type": "object" + }, + "pmac_DlsPmacAsynMotor": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Object name and gui association name", + "title": "Name", + "type": "string" + }, + "Controller": { + "default": null, + "description": "PMAC Controller to attach to", + "title": "Controller", + "type": "string" + }, + "axis": { + "default": null, + "description": "which axis number this motor drives", + "title": "Axis", + "type": "integer" + }, + "P": { + "default": null, + "description": "PV prefix name for this motor", + "title": "P", + "type": "string" + }, + "M": { + "default": null, + "description": "PV motor name for this motor", + "title": "M", + "type": "string" + }, + "DESC": { + "default": "", + "description": "Description, displayed on EDM screen", + "title": "Desc", + "type": "string" + }, + "MRES": { + "default": 0.0001, + "description": "Motor Step Size (EGU)", + "title": "Mres", + "type": "number" + }, + "VELO": { + "default": 1.0, + "description": "axis Velocity (EGU/s)", + "title": "Velo", + "type": "number" + }, + "PREC": { + "default": 3, + "description": "Display Precision", + "title": "Prec", + "type": "integer" + }, + "EGU": { + "default": "mm", + "description": "Engineering Units", + "title": "Egu", + "type": "string" + }, + "TWV": { + "default": 1.0, + "description": "Tweak Step Size (EGU)", + "title": "Twv", + "type": "number" + }, + "DTYP": { + "default": "asynMotor", + "description": "Datatype of record", + "title": "Dtyp", + "type": "string" + }, + "DIR": { + "default": 0, + "description": "User direction", + "title": "Dir", + "type": "integer" + }, + "VBAS": { + "default": 1.0, + "description": "Base Velocity (EGU/s)", + "title": "Vbas", + "type": "number" + }, + "VMAX": { + "default": "{{VELO}}", + "description": "Max Velocity (EGU/s)", + "title": "Vmax", + "type": "string" + }, + "ACCL": { + "default": 0.5, + "description": "Seconds to Velocity", + "title": "Accl", + "type": "number" + }, + "BDST": { + "default": 0.0, + "description": "BL Distance (EGU)", + "title": "Bdst", + "type": "number" + }, + "BVEL": { + "default": 0.0, + "description": "BL Velocity(EGU/s)", + "title": "Bvel", + "type": "number" + }, + "BACC": { + "default": 0.0, + "description": "BL Seconds to Veloc", + "title": "Bacc", + "type": "number" + }, + "DHLM": { + "default": 10000.0, + "description": "Dial High Limit", + "title": "Dhlm", + "type": "number" + }, + "DLLM": { + "default": -10000.0, + "description": "Dial low limit", + "title": "Dllm", + "type": "number" + }, + "HLM": { + "default": 0.0, + "description": "User High Limit", + "title": "Hlm", + "type": "number" + }, + "LLM": { + "default": 0.0, + "description": "User Low Limit", + "title": "Llm", + "type": "number" + }, + "HLSV": { + "default": "MAJOR", + "description": "HW Lim, Violation Svr", + "title": "Hlsv", + "type": "string" + }, + "INIT": { + "default": "", + "description": "Startup commands", + "title": "Init", + "type": "string" + }, + "SREV": { + "default": 1000, + "description": "Steps per Revolution", + "title": "Srev", + "type": "integer" + }, + "RRES": { + "default": 0.0, + "description": "Readback Step Size (EGU", + "title": "Rres", + "type": "number" + }, + "ERES": { + "default": 0.0, + "description": "Encoder Step Size (EGU)", + "title": "Eres", + "type": "number" + }, + "JAR": { + "default": 0.0, + "description": "Jog Acceleration (EGU/s^2)", + "title": "Jar", + "type": "number" + }, + "UEIP": { + "default": 0, + "description": "Use Encoder If Present", + "title": "Ueip", + "type": "integer" + }, + "URIP": { + "default": 0, + "description": "Use RDBL If Present", + "title": "Urip", + "type": "integer" + }, + "RDBL": { + "default": "0", + "description": "Readback Location, set URIP =1 if you specify this", + "title": "Rdbl", + "type": "string" + }, + "RLNK": { + "default": "", + "description": "Readback output link", + "title": "Rlnk", + "type": "string" + }, + "RTRY": { + "default": 0, + "description": "Max retry count", + "title": "Rtry", + "type": "integer" + }, + "DLY": { + "default": 0.0, + "description": "Readback settle time (s)", + "title": "Dly", + "type": "number" + }, + "OFF": { + "default": 0.0, + "description": "User Offset (EGU)", + "title": "Off", + "type": "number" + }, + "RDBD": { + "default": 0.0, + "description": "Retry Deadband (EGU)", + "title": "Rdbd", + "type": "number" + }, + "FOFF": { + "default": 0, + "description": "Freeze Offset, 0=variable, 1=frozen", + "title": "Foff", + "type": "integer" + }, + "ADEL": { + "default": 0.0, + "description": "Alarm monitor deadband (EGU)", + "title": "Adel", + "type": "number" + }, + "NTM": { + "default": 1, + "description": "New Target Monitor, only set to 0 for soft motors", + "title": "Ntm", + "type": "integer" + }, + "FEHIGH": { + "default": 0.0, + "description": "HIGH limit for following error", + "title": "Fehigh", + "type": "number" + }, + "FEHIHI": { + "default": 0.0, + "description": "HIHI limit for following error", + "title": "Fehihi", + "type": "number" + }, + "FEHHSV": { + "default": "NO_ALARM", + "description": "HIHI alarm severity for following error", + "title": "Fehhsv", + "type": "string" + }, + "FEHSV": { + "default": "NO_ALARM", + "description": "HIGH alarm severity for following error", + "title": "Fehsv", + "type": "string" + }, + "SCALE": { + "default": 1, + "description": "", + "title": "Scale", + "type": "integer" + }, + "HOMEVIS": { + "default": 1, + "description": "If 1 then home is visible on the gui", + "title": "Homevis", + "type": "integer" + }, + "HOMEVISSTR": { + "default": "Use motor summary screen", + "description": "", + "title": "Homevisstr", + "type": "string" + }, + "alh": { + "default": "", + "description": "Set this to alh to add the motor to the alarm handler and send emails", + "title": "Alh", + "type": "string" + }, + "HOME": { + "default": "{{P}}", + "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", + "title": "Home", + "type": "string" + }, + "ALLOW_HOMED_SET": { + "default": "#", + "description": "Set to a blank to allow this axis to have its homed", + "title": "Allow Homed Set", + "type": "string" + }, + "RLINK": { + "default": "", + "description": "not sure what this is", + "title": "Rlink", + "type": "string" + }, + "type": { + "const": "pmac.DlsPmacAsynMotor", + "default": "pmac.DlsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_DlsPmacAsynMotor", + "type": "object" + }, + "pmac_Geobrick": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Name to use for the geobrick's asyn port", + "title": "Name", + "type": "string" + }, + "PORT": { + "default": null, + "description": "Asyn port name for PmacAsynIPPort to connect to", + "title": "Port", + "type": "string" + }, + "P": { + "default": null, + "description": "PV Prefix for all pmac db templates", + "title": "P", + "type": "string" + }, + "numAxes": { + "default": 8, + "description": "number of axes to initialize for the controller", + "title": "Numaxes", + "type": "integer" + }, + "idlePoll": { + "default": 500, + "description": "Idle Poll Period in ms", + "title": "Idlepoll", + "type": "integer" + }, + "movingPoll": { + "default": 100, + "description": "Moving Poll Period in ms", + "title": "Movingpoll", + "type": "integer" + }, + "TIMEOUT": { + "default": 4, + "description": "timeout in seconds for asyn", + "title": "Timeout", + "type": "integer" + }, + "FEEDRATE": { + "default": 100, + "description": "feedrate below which we go into error", + "title": "Feedrate", + "type": "integer" + }, + "CSG0": { + "default": "", + "description": "Name for Coordinate System Group 0", + "title": "Csg0", + "type": "string" + }, + "CSG1": { + "default": "", + "description": "Name for Coordinate System Group 1", + "title": "Csg1", + "type": "string" + }, + "CSG2": { + "default": "", + "description": "Name for Coordinate System Group 2", + "title": "Csg2", + "type": "string" + }, + "CSG3": { + "default": "", + "description": "Name for Coordinate System Group 3", + "title": "Csg3", + "type": "string" + }, + "CSG4": { + "default": "", + "description": "Name for Coordinate System Group 3", + "title": "Csg4", + "type": "string" + }, + "type": { + "const": "pmac.Geobrick", + "default": "pmac.Geobrick", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_Geobrick", + "type": "object" + }, + "pmac_PmacAsynIPPort": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name", + "title": "Name", + "type": "string" + }, + "IP": { + "default": null, + "description": "IP address of pmac", + "title": "Ip", + "type": "string" + }, + "PORT": { + "default": 1025, + "description": "TCP port for connection", + "title": "Port", + "type": "integer" + }, + "type": { + "const": "pmac.PmacAsynIPPort", + "default": "pmac.PmacAsynIPPort", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_PmacAsynIPPort", + "type": "object" + }, + "pmac_PmacAsynSSHPort": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name", + "title": "Name", + "type": "string" + }, + "IP": { + "default": null, + "description": "IP address of Power pmac", + "title": "Ip", + "type": "string" + }, + "USERNAME": { + "default": "root", + "description": "Username for login", + "title": "Username", + "type": "string" + }, + "PASSWORD": { + "default": "deltatau", + "description": "Password for login", + "title": "Password", + "type": "string" + }, + "PRIORITY": { + "default": 0, + "description": "Priority of the port", + "title": "Priority", + "type": "integer" + }, + "NOAUTOCONNECT": { + "default": 0, + "description": "Disables autoconnect if set to 1", + "title": "Noautoconnect", + "type": "integer" + }, + "NOEOS": { + "default": 0, + "description": "No EOS used if set to 1", + "title": "Noeos", + "type": "integer" + }, + "type": { + "const": "pmac.PmacAsynSSHPort", + "default": "pmac.PmacAsynSSHPort", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_PmacAsynSSHPort", + "type": "object" + }, + "pmac_autohome": { + "additionalProperties": false, + "properties": { + "Controller": { + "default": null, + "description": "the PMAC Controller", + "title": "Controller", + "type": "string" + }, + "PLC": { + "default": null, + "description": "PLC number of the auto home PLC", + "title": "Plc", + "type": "integer" + }, + "P": { + "default": null, + "description": "Prefix for auto home PVs", + "title": "P", + "type": "string" + }, + "GRP1": { + "default": "All", + "description": "name of the 'ALL' group of auto home axes", + "title": "Grp1", + "type": "string" + }, + "GRP2": { + "default": "", + "description": "name of the second group of auto home axes", + "title": "Grp2", + "type": "string" + }, + "GRP3": { + "default": "", + "description": "name of the third group of auto home axes", + "title": "Grp3", + "type": "string" + }, + "GRP4": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp4", + "type": "string" + }, + "GRP5": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp5", + "type": "string" + }, + "GRP6": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp6", + "type": "string" + }, + "GRP7": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp7", + "type": "string" + }, + "GRP8": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp8", + "type": "string" + }, + "GRP9": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp9", + "type": "string" + }, + "type": { + "const": "pmac.autohome", + "default": "pmac.autohome", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_autohome", + "type": "object" + }, + "pmac_pmacDisableLimitsCheck": { + "additionalProperties": false, + "properties": { + "Controller": { + "default": null, + "description": "Geobrick on which to disable limits", + "title": "Controller", + "type": "string" + }, + "Axis": { + "default": null, + "description": "Axis to have limits disabled", + "title": "Axis", + "type": "integer" + }, + "type": { + "const": "pmac.pmacDisableLimitsCheck", + "default": "pmac.pmacDisableLimitsCheck", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_pmacDisableLimitsCheck", + "type": "object" + } + }, + "additionalProperties": false, "properties": { "ioc_name": { - "type": "string", - "description": "Name of IOC instance" + "description": "Name of IOC instance", + "title": "Ioc Name", + "type": "string" }, "description": { - "type": "string", - "description": "Description of what the IOC does" + "description": "Description of what the IOC does", + "title": "Description", + "type": "string" + }, + "generic_ioc_image": { + "description": "The generic IOC container image registry URL", + "title": "Generic Ioc Image", + "type": "string" }, "entities": { - "type": "array", + "default": [], + "description": "List of entities this IOC instantiates", "items": { "anyOf": [ { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "max_bytes": { - "type": "integer", - "description": "Max size in bytes for sending arrays over channel access", - "default": 6000000 - }, - "type": { - "type": "string", - "const": "epics.EpicsCaMaxArrayBytes", - "default": "epics.EpicsCaMaxArrayBytes" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_EpicsCaMaxArrayBytes" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "minutes_west": { - "type": "integer", - "description": "relative time zone minutes", - "default": 0 - }, - "type": { - "type": "string", - "const": "epics.EpicsTsMinWest", - "default": "epics.EpicsTsMinWest" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_EpicsTsMinWest" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "pv": { - "type": "string", - "description": "Name of PV" - }, - "value": { - "type": "string", - "description": "Value to set" - }, - "type": { - "type": "string", - "const": "epics.Dbpf", - "default": "epics.Dbpf" - } - }, - "required": [ - "pv", - "value" - ], - "additionalProperties": false + "$ref": "#/$defs/epics_Dbpf" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Name of environment variable" - }, - "value": { - "type": "string", - "description": "Value of environment variable" - }, - "type": { - "type": "string", - "const": "epics.EpicsEnvSet", - "default": "epics.EpicsEnvSet" - } - }, - "required": [ - "name", - "value" - ], - "additionalProperties": false + "$ref": "#/$defs/epics_EpicsEnvSet" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "command": { - "type": "string", - "description": "command string", - "default": "" - }, - "type": { - "type": "string", - "const": "epics.StartupCommand", - "default": "epics.StartupCommand" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_StartupCommand" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "command": { - "type": "string", - "description": "command string", - "default": "" - }, - "type": { - "type": "string", - "const": "epics.PostStartupCommand", - "default": "epics.PostStartupCommand" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_PostStartupCommand" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "A name for an interrupt vector variable", - "vscode_ibek_plugin_type": "type_id" - }, - "count": { - "type": "integer", - "description": "The number of interrupt vectors to reserve", - "default": 1 - }, - "type": { - "type": "string", - "const": "epics.InterruptVectorVME", - "default": "epics.InterruptVectorVME" - } - }, - "required": [ - "name" - ], - "additionalProperties": false + "$ref": "#/$defs/epics_InterruptVectorVME" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name", - "vscode_ibek_plugin_type": "type_id" - }, - "IP": { - "type": "string", - "description": "IP address of Power pmac" - }, - "USERNAME": { - "type": "string", - "description": "Username for login", - "default": "root" - }, - "PASSWORD": { - "type": "string", - "description": "Password for login", - "default": "deltatau" - }, - "PRIORITY": { - "type": "integer", - "description": "Priority of the port", - "default": 0 - }, - "NOAUTOCONNECT": { - "type": "integer", - "description": "Disables autoconnect if set to 1", - "default": 0 - }, - "NOEOS": { - "type": "integer", - "description": "No EOS used if set to 1", - "default": 0 - }, - "type": { - "type": "string", - "const": "pmac.PmacAsynSSHPort", - "default": "pmac.PmacAsynSSHPort" - } - }, - "required": [ - "name", - "IP" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_PmacAsynSSHPort" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name", - "vscode_ibek_plugin_type": "type_id" - }, - "IP": { - "type": "string", - "description": "IP address of pmac" - }, - "PORT": { - "type": "integer", - "description": "TCP port for connection", - "default": 1025 - }, - "type": { - "type": "string", - "const": "pmac.PmacAsynIPPort", - "default": "pmac.PmacAsynIPPort" - } - }, - "required": [ - "name", - "IP" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_PmacAsynIPPort" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Name to use for the geobrick's asyn port", - "vscode_ibek_plugin_type": "type_id" - }, - "PORT": { - "type": "string", - "description": "Asyn port name for PmacAsynIPPort to connect to", - "vscode_ibek_plugin_type": "type_object" - }, - "P": { - "type": "string", - "description": "PV Prefix for all pmac db templates" - }, - "numAxes": { - "type": "integer", - "description": "number of axes to initialize for the controller", - "default": 8 - }, - "idlePoll": { - "type": "integer", - "description": "Idle Poll Period in ms", - "default": 500 - }, - "movingPoll": { - "type": "integer", - "description": "Moving Poll Period in ms", - "default": 100 - }, - "TIMEOUT": { - "type": "integer", - "description": "timeout in seconds for asyn", - "default": 4 - }, - "FEEDRATE": { - "type": "integer", - "description": "feedrate below which we go into error", - "default": 100 - }, - "CSG0": { - "type": "string", - "description": "Name for Coordinate System Group 0", - "default": "" - }, - "CSG1": { - "type": "string", - "description": "Name for Coordinate System Group 1", - "default": "" - }, - "CSG2": { - "type": "string", - "description": "Name for Coordinate System Group 2", - "default": "" - }, - "CSG3": { - "type": "string", - "description": "Name for Coordinate System Group 3", - "default": "" - }, - "CSG4": { - "type": "string", - "description": "Name for Coordinate System Group 3", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.Geobrick", - "default": "pmac.Geobrick" - } - }, - "required": [ - "name", - "PORT", - "P" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_Geobrick" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Object name and gui association name" - }, - "Controller": { - "type": "string", - "description": "PMAC Controller to attach to", - "vscode_ibek_plugin_type": "type_object" - }, - "axis": { - "type": "integer", - "description": "which axis number this motor drives" - }, - "P": { - "type": "string", - "description": "PV prefix name for this motor" - }, - "M": { - "type": "string", - "description": "PV motor name for this motor" - }, - "DESC": { - "type": "string", - "description": "Description, displayed on EDM screen", - "default": "" - }, - "MRES": { - "type": "number", - "description": "Motor Step Size (EGU)", - "default": 0.0001 - }, - "VELO": { - "type": "number", - "description": "axis Velocity (EGU/s)", - "default": 1.0 - }, - "PREC": { - "type": "integer", - "description": "Display Precision", - "default": 3 - }, - "EGU": { - "type": "string", - "description": "Engineering Units", - "default": "mm" - }, - "TWV": { - "type": "number", - "description": "Tweak Step Size (EGU)", - "default": 1.0 - }, - "DTYP": { - "type": "string", - "description": "Datatype of record", - "default": "asynMotor" - }, - "DIR": { - "type": "integer", - "description": "User direction", - "default": 0 - }, - "VBAS": { - "type": "number", - "description": "Base Velocity (EGU/s)", - "default": 1.0 - }, - "VMAX": { - "type": "string", - "description": "Max Velocity (EGU/s)", - "default": "{{VELO}}" - }, - "ACCL": { - "type": "number", - "description": "Seconds to Velocity", - "default": 0.5 - }, - "BDST": { - "type": "number", - "description": "BL Distance (EGU)", - "default": 0.0 - }, - "BVEL": { - "type": "number", - "description": "BL Velocity(EGU/s)", - "default": 0.0 - }, - "BACC": { - "type": "number", - "description": "BL Seconds to Veloc", - "default": 0.0 - }, - "DHLM": { - "type": "number", - "description": "Dial High Limit", - "default": 10000.0 - }, - "DLLM": { - "type": "number", - "description": "Dial low limit", - "default": -10000.0 - }, - "HLM": { - "type": "number", - "description": "User High Limit", - "default": 0.0 - }, - "LLM": { - "type": "number", - "description": "User Low Limit", - "default": 0.0 - }, - "HLSV": { - "type": "string", - "description": "HW Lim, Violation Svr", - "default": "MAJOR" - }, - "INIT": { - "type": "string", - "description": "Startup commands", - "default": "" - }, - "SREV": { - "type": "integer", - "description": "Steps per Revolution", - "default": 1000 - }, - "RRES": { - "type": "number", - "description": "Readback Step Size (EGU", - "default": 0.0 - }, - "ERES": { - "type": "number", - "description": "Encoder Step Size (EGU)", - "default": 0.0 - }, - "JAR": { - "type": "number", - "description": "Jog Acceleration (EGU/s^2)", - "default": 0.0 - }, - "UEIP": { - "type": "integer", - "description": "Use Encoder If Present", - "default": 0 - }, - "URIP": { - "type": "integer", - "description": "Use RDBL If Present", - "default": 0 - }, - "RDBL": { - "type": "string", - "description": "Readback Location, set URIP =1 if you specify this", - "default": "0" - }, - "RLNK": { - "type": "string", - "description": "Readback output link", - "default": "" - }, - "RTRY": { - "type": "integer", - "description": "Max retry count", - "default": 0 - }, - "DLY": { - "type": "number", - "description": "Readback settle time (s)", - "default": 0.0 - }, - "OFF": { - "type": "number", - "description": "User Offset (EGU)", - "default": 0.0 - }, - "RDBD": { - "type": "number", - "description": "Retry Deadband (EGU)", - "default": 0.0 - }, - "FOFF": { - "type": "integer", - "description": "Freeze Offset, 0=variable, 1=frozen", - "default": 0 - }, - "ADEL": { - "type": "number", - "description": "Alarm monitor deadband (EGU)", - "default": 0.0 - }, - "NTM": { - "type": "integer", - "description": "New Target Monitor, only set to 0 for soft motors", - "default": 1 - }, - "FEHIGH": { - "type": "number", - "description": "HIGH limit for following error", - "default": 0.0 - }, - "FEHIHI": { - "type": "number", - "description": "HIHI limit for following error", - "default": 0.0 - }, - "FEHHSV": { - "type": "string", - "description": "HIHI alarm severity for following error", - "default": "NO_ALARM" - }, - "FEHSV": { - "type": "string", - "description": "HIGH alarm severity for following error", - "default": "NO_ALARM" - }, - "SCALE": { - "type": "integer", - "default": 1 - }, - "HOMEVIS": { - "type": "integer", - "description": "If 1 then home is visible on the gui", - "default": 1 - }, - "HOMEVISSTR": { - "type": "string", - "default": "Use motor summary screen" - }, - "alh": { - "type": "string", - "description": "Set this to alh to add the motor to the alarm handler and send emails", - "default": "" - }, - "HOME": { - "type": "string", - "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", - "default": "{{P}}" - }, - "ALLOW_HOMED_SET": { - "type": "string", - "description": "Set to a blank to allow this axis to have its homed", - "default": "#" - }, - "RLINK": { - "type": "string", - "description": "not sure what this is", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.DlsPmacAsynMotor", - "default": "pmac.DlsPmacAsynMotor" - } - }, - "required": [ - "name", - "Controller", - "axis", - "P", - "M" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_DlsPmacAsynMotor" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Object name and gui association name" - }, - "CsController": { - "type": "string", - "description": "Coordinate system controller to attach to", - "vscode_ibek_plugin_type": "type_object" - }, - "axis": { - "type": "integer", - "description": "which axis number this motor drives" - }, - "P": { - "type": "string", - "description": "PV prefix name for this motor" - }, - "M": { - "type": "string", - "description": "PV motor name for this motor" - }, - "DESC": { - "type": "string", - "description": "Description, displayed on EDM screen", - "default": "" - }, - "MRES": { - "type": "number", - "description": "Motor Step Size (EGU)", - "default": 0.0001 - }, - "VELO": { - "type": "number", - "description": "axis Velocity (EGU/s)", - "default": 1.0 - }, - "PREC": { - "type": "integer", - "description": "Display Precision", - "default": 3 - }, - "EGU": { - "type": "string", - "description": "Engineering Units", - "default": "mm" - }, - "TWV": { - "type": "number", - "description": "Tweak Step Size (EGU)", - "default": 1.0 - }, - "DTYP": { - "type": "string", - "description": "Datatype of record", - "default": "asynMotor" - }, - "DIR": { - "type": "integer", - "description": "User direction", - "default": 0 - }, - "VBAS": { - "type": "number", - "description": "Base Velocity (EGU/s)", - "default": 1.0 - }, - "VMAX": { - "type": "string", - "description": "Max Velocity (EGU/s)", - "default": "{{VELO}}" - }, - "ACCL": { - "type": "number", - "description": "Seconds to Velocity", - "default": 0.5 - }, - "BDST": { - "type": "number", - "description": "BL Distance (EGU)", - "default": 0.0 - }, - "BVEL": { - "type": "number", - "description": "BL Velocity(EGU/s)", - "default": 0.0 - }, - "BACC": { - "type": "number", - "description": "BL Seconds to Veloc", - "default": 0.0 - }, - "DHLM": { - "type": "number", - "description": "Dial High Limit", - "default": 10000.0 - }, - "DLLM": { - "type": "number", - "description": "Dial low limit", - "default": -10000.0 - }, - "HLM": { - "type": "number", - "description": "User High Limit", - "default": 0.0 - }, - "LLM": { - "type": "number", - "description": "User Low Limit", - "default": 0.0 - }, - "HLSV": { - "type": "string", - "description": "HW Lim, Violation Svr", - "default": "MAJOR" - }, - "INIT": { - "type": "string", - "description": "Startup commands", - "default": "" - }, - "SREV": { - "type": "integer", - "description": "Steps per Revolution", - "default": 1000 - }, - "RRES": { - "type": "number", - "description": "Readback Step Size (EGU", - "default": 0.0 - }, - "ERES": { - "type": "number", - "description": "Encoder Step Size (EGU)", - "default": 0.0 - }, - "JAR": { - "type": "number", - "description": "Jog Acceleration (EGU/s^2)", - "default": 0.0 - }, - "UEIP": { - "type": "integer", - "description": "Use Encoder If Present", - "default": 0 - }, - "URIP": { - "type": "integer", - "description": "Use RDBL If Present", - "default": 0 - }, - "RDBL": { - "type": "string", - "description": "Readback Location, set URIP =1 if you specify this", - "default": "0" - }, - "RLNK": { - "type": "string", - "description": "Readback output link", - "default": "" - }, - "RTRY": { - "type": "integer", - "description": "Max retry count", - "default": 0 - }, - "DLY": { - "type": "number", - "description": "Readback settle time (s)", - "default": 0.0 - }, - "OFF": { - "type": "number", - "description": "User Offset (EGU)", - "default": 0.0 - }, - "RDBD": { - "type": "number", - "description": "Retry Deadband (EGU)", - "default": 0.0 - }, - "FOFF": { - "type": "integer", - "description": "Freeze Offset, 0=variable, 1=frozen", - "default": 0 - }, - "ADEL": { - "type": "number", - "description": "Alarm monitor deadband (EGU)", - "default": 0.0 - }, - "NTM": { - "type": "integer", - "description": "New Target Monitor, only set to 0 for soft motors", - "default": 1 - }, - "FEHEIGH": { - "type": "number", - "description": "HIGH limit for following error", - "default": 0.0 - }, - "FEHIHI": { - "type": "number", - "description": "HIHI limit for following error", - "default": 0.0 - }, - "FEHHSV": { - "type": "string", - "description": "HIHI alarm severity for following error", - "default": "NO_ALARM" - }, - "FEHSV": { - "type": "string", - "description": "HIGH alarm severity for following error", - "default": "NO_ALARM" - }, - "SCALE": { - "type": "integer", - "default": 1 - }, - "HOMEVIS": { - "type": "integer", - "description": "If 1 then home is visible on the gui", - "default": 1 - }, - "HOMEVISSTR": { - "type": "string", - "default": "Use motor summary screen" - }, - "alh": { - "type": "string", - "description": "Set this to alh to add the motor to the alarm handler and send emails", - "default": "" - }, - "HOME": { - "type": "string", - "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", - "default": "{{P}}" - }, - "ALLOW_HOMED_SET": { - "type": "string", - "description": "Set to a blank to allow this axis to have its homed", - "default": "#" - }, - "type": { - "type": "string", - "const": "pmac.DlsCsPmacAsynMotor", - "default": "pmac.DlsCsPmacAsynMotor" - } - }, - "required": [ - "name", - "CsController", - "axis", - "P", - "M" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "Controller": { - "type": "string", - "description": "Geobrick on which to disable limits", - "vscode_ibek_plugin_type": "type_object" - }, - "Axis": { - "type": "integer", - "description": "Axis to have limits disabled" - }, - "type": { - "type": "string", - "const": "pmac.pmacDisableLimitsCheck", - "default": "pmac.pmacDisableLimitsCheck" - } - }, - "required": [ - "Controller", - "Axis" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "Controller": { - "type": "string", - "description": "the PMAC Controller", - "vscode_ibek_plugin_type": "type_object" - }, - "PLC": { - "type": "integer", - "description": "PLC number of the auto home PLC" - }, - "P": { - "type": "string", - "description": "Prefix for auto home PVs" - }, - "GRP1": { - "type": "string", - "description": "name of the 'ALL' group of auto home axes", - "default": "All" - }, - "GRP2": { - "type": "string", - "description": "name of the second group of auto home axes", - "default": "" - }, - "GRP3": { - "type": "string", - "description": "name of the third group of auto home axes", - "default": "" - }, - "GRP4": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP5": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP6": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP7": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP8": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP9": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.autohome", - "default": "pmac.autohome" - } - }, - "required": [ - "Controller", - "PLC", - "P" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_autohome" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name for this object", - "vscode_ibek_plugin_type": "type_id" - }, - "Controller": { - "type": "string", - "description": "the PMAC Controller", - "vscode_ibek_plugin_type": "type_object" - }, - "CS": { - "type": "integer", - "description": "Coordinate system number" - }, - "NAxes": { - "type": "integer", - "description": "number of CS axes", - "default": 9 - }, - "Program": { - "type": "integer", - "description": "PROG number for CS motion", - "default": 10 - }, - "type": { - "type": "string", - "const": "pmac.CS", - "default": "pmac.CS" - } - }, - "required": [ - "name", - "Controller", - "CS" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_CS" } ] }, - "description": "List of entities this IOC instantiates" - }, - "generic_ioc_image": { - "type": "string", - "description": "The generic IOC container image registry URL" + "title": "Entities", + "type": "array" } }, "required": [ "ioc_name", "description", - "entities", "generic_ioc_image" ], - "additionalProperties": false, - "$schema": "http://json-schema.org/draft-07/schema#" + "title": "NewIOC", + "type": "object" } \ No newline at end of file diff --git a/tests/samples/schemas/container.ibek.entities.schema.json b/tests/samples/schemas/container.ibek.entities.schema.json index e2065eea0..7cf19586d 100644 --- a/tests/samples/schemas/container.ibek.entities.schema.json +++ b/tests/samples/schemas/container.ibek.entities.schema.json @@ -1,1009 +1,1177 @@ { - "type": "object", + "$defs": { + "asyn_AsynIP": { + "additionalProperties": false, + "properties": { + "port": { + "default": null, + "description": "Serial port tty name / IP address optionally followed by protocol", + "title": "Port", + "type": "string" + }, + "name": { + "default": null, + "description": "Name for the Asyn Port", + "title": "Name", + "type": "string" + }, + "input_eos": { + "default": null, + "description": "Input end of string (terminator)", + "title": "Input Eos", + "type": "string" + }, + "output_eos": { + "default": null, + "description": "Output end of string (terminator)", + "title": "Output Eos", + "type": "string" + }, + "priority": { + "default": 100, + "description": "Priority", + "title": "Priority", + "type": "integer" + }, + "no_auto_connect": { + "default": null, + "description": "Set to stop auto connect", + "title": "No Auto Connect", + "type": "boolean" + }, + "no_process_eos": { + "default": null, + "description": "Set to avoid processing end of string", + "title": "No Process Eos", + "type": "boolean" + }, + "simulation": { + "default": null, + "description": "IP port to connect to if in simulation mode", + "title": "Simulation", + "type": "string" + }, + "type": { + "const": "asyn.AsynIP", + "default": "asyn.AsynIP", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "asyn_AsynIP", + "type": "object" + }, + "asyn_AsynSerial": { + "additionalProperties": false, + "properties": { + "port": { + "default": null, + "description": "The port name for this asyn object", + "title": "Port", + "type": "string" + }, + "input_eos": { + "default": null, + "description": "Input end of string (terminator)", + "title": "Input Eos", + "type": "string" + }, + "output_eos": { + "default": null, + "description": "Output end of string (terminator)", + "title": "Output Eos", + "type": "string" + }, + "priority": { + "default": 100, + "description": "Priority", + "title": "Priority", + "type": "integer" + }, + "no_auto_connect": { + "default": null, + "description": "Set to stop auto connect", + "title": "No Auto Connect", + "type": "boolean" + }, + "no_process_eos": { + "default": null, + "description": "Set to avoid processing end of string", + "title": "No Process Eos", + "type": "boolean" + }, + "simulation": { + "default": null, + "description": "IP port to connect to if in simulation mode", + "title": "Simulation", + "type": "string" + }, + "baud": { + "default": null, + "description": "Baud Rate", + "title": "Baud", + "type": "integer" + }, + "bits": { + "default": null, + "description": "Bits [8,7,6,5]", + "title": "Bits", + "type": "integer" + }, + "parity": { + "default": null, + "description": "Parity [null,even,odd]", + "title": "Parity", + "type": "string" + }, + "stop": { + "default": null, + "description": "Stop Bits [1,2]", + "title": "Stop", + "type": "integer" + }, + "crtscts": { + "default": null, + "description": "Set hardware flow control on", + "title": "Crtscts", + "type": "boolean" + }, + "type": { + "const": "asyn.AsynSerial", + "default": "asyn.AsynSerial", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "asyn_AsynSerial", + "type": "object" + }, + "pmac_CS": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name for this object", + "title": "Name", + "type": "string" + }, + "Controller": { + "default": null, + "description": "the PMAC Controller", + "title": "Controller", + "type": "string" + }, + "CS": { + "default": null, + "description": "Coordinate system number", + "title": "Cs", + "type": "integer" + }, + "NAxes": { + "default": 9, + "description": "number of CS axes", + "title": "Naxes", + "type": "integer" + }, + "Program": { + "default": 10, + "description": "PROG number for CS motion", + "title": "Program", + "type": "integer" + }, + "type": { + "const": "pmac.CS", + "default": "pmac.CS", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_CS", + "type": "object" + }, + "pmac_DlsCsPmacAsynMotor": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Object name and gui association name", + "title": "Name", + "type": "string" + }, + "CsController": { + "default": null, + "description": "Coordinate system controller to attach to", + "title": "Cscontroller", + "type": "string" + }, + "axis": { + "default": null, + "description": "which axis number this motor drives", + "title": "Axis", + "type": "integer" + }, + "P": { + "default": null, + "description": "PV prefix name for this motor", + "title": "P", + "type": "string" + }, + "M": { + "default": null, + "description": "PV motor name for this motor", + "title": "M", + "type": "string" + }, + "DESC": { + "default": "", + "description": "Description, displayed on EDM screen", + "title": "Desc", + "type": "string" + }, + "MRES": { + "default": 0.0001, + "description": "Motor Step Size (EGU)", + "title": "Mres", + "type": "number" + }, + "VELO": { + "default": 1.0, + "description": "axis Velocity (EGU/s)", + "title": "Velo", + "type": "number" + }, + "PREC": { + "default": 3, + "description": "Display Precision", + "title": "Prec", + "type": "integer" + }, + "EGU": { + "default": "mm", + "description": "Engineering Units", + "title": "Egu", + "type": "string" + }, + "TWV": { + "default": 1.0, + "description": "Tweak Step Size (EGU)", + "title": "Twv", + "type": "number" + }, + "DTYP": { + "default": "asynMotor", + "description": "Datatype of record", + "title": "Dtyp", + "type": "string" + }, + "DIR": { + "default": 0, + "description": "User direction", + "title": "Dir", + "type": "integer" + }, + "VBAS": { + "default": 1.0, + "description": "Base Velocity (EGU/s)", + "title": "Vbas", + "type": "number" + }, + "VMAX": { + "default": "{{VELO}}", + "description": "Max Velocity (EGU/s)", + "title": "Vmax", + "type": "string" + }, + "ACCL": { + "default": 0.5, + "description": "Seconds to Velocity", + "title": "Accl", + "type": "number" + }, + "BDST": { + "default": 0.0, + "description": "BL Distance (EGU)", + "title": "Bdst", + "type": "number" + }, + "BVEL": { + "default": 0.0, + "description": "BL Velocity(EGU/s)", + "title": "Bvel", + "type": "number" + }, + "BACC": { + "default": 0.0, + "description": "BL Seconds to Veloc", + "title": "Bacc", + "type": "number" + }, + "DHLM": { + "default": 10000.0, + "description": "Dial High Limit", + "title": "Dhlm", + "type": "number" + }, + "DLLM": { + "default": -10000.0, + "description": "Dial low limit", + "title": "Dllm", + "type": "number" + }, + "HLM": { + "default": 0.0, + "description": "User High Limit", + "title": "Hlm", + "type": "number" + }, + "LLM": { + "default": 0.0, + "description": "User Low Limit", + "title": "Llm", + "type": "number" + }, + "HLSV": { + "default": "MAJOR", + "description": "HW Lim, Violation Svr", + "title": "Hlsv", + "type": "string" + }, + "INIT": { + "default": "", + "description": "Startup commands", + "title": "Init", + "type": "string" + }, + "SREV": { + "default": 1000, + "description": "Steps per Revolution", + "title": "Srev", + "type": "integer" + }, + "RRES": { + "default": 0.0, + "description": "Readback Step Size (EGU", + "title": "Rres", + "type": "number" + }, + "ERES": { + "default": 0.0, + "description": "Encoder Step Size (EGU)", + "title": "Eres", + "type": "number" + }, + "JAR": { + "default": 0.0, + "description": "Jog Acceleration (EGU/s^2)", + "title": "Jar", + "type": "number" + }, + "UEIP": { + "default": 0, + "description": "Use Encoder If Present", + "title": "Ueip", + "type": "integer" + }, + "URIP": { + "default": 0, + "description": "Use RDBL If Present", + "title": "Urip", + "type": "integer" + }, + "RDBL": { + "default": "0", + "description": "Readback Location, set URIP =1 if you specify this", + "title": "Rdbl", + "type": "string" + }, + "RLNK": { + "default": "", + "description": "Readback output link", + "title": "Rlnk", + "type": "string" + }, + "RTRY": { + "default": 0, + "description": "Max retry count", + "title": "Rtry", + "type": "integer" + }, + "DLY": { + "default": 0.0, + "description": "Readback settle time (s)", + "title": "Dly", + "type": "number" + }, + "OFF": { + "default": 0.0, + "description": "User Offset (EGU)", + "title": "Off", + "type": "number" + }, + "RDBD": { + "default": 0.0, + "description": "Retry Deadband (EGU)", + "title": "Rdbd", + "type": "number" + }, + "FOFF": { + "default": 0, + "description": "Freeze Offset, 0=variable, 1=frozen", + "title": "Foff", + "type": "integer" + }, + "ADEL": { + "default": 0.0, + "description": "Alarm monitor deadband (EGU)", + "title": "Adel", + "type": "number" + }, + "NTM": { + "default": 1, + "description": "New Target Monitor, only set to 0 for soft motors", + "title": "Ntm", + "type": "integer" + }, + "FEHEIGH": { + "default": 0.0, + "description": "HIGH limit for following error", + "title": "Feheigh", + "type": "number" + }, + "FEHIHI": { + "default": 0.0, + "description": "HIHI limit for following error", + "title": "Fehihi", + "type": "number" + }, + "FEHHSV": { + "default": "NO_ALARM", + "description": "HIHI alarm severity for following error", + "title": "Fehhsv", + "type": "string" + }, + "FEHSV": { + "default": "NO_ALARM", + "description": "HIGH alarm severity for following error", + "title": "Fehsv", + "type": "string" + }, + "SCALE": { + "default": 1, + "description": "", + "title": "Scale", + "type": "integer" + }, + "HOMEVIS": { + "default": 1, + "description": "If 1 then home is visible on the gui", + "title": "Homevis", + "type": "integer" + }, + "HOMEVISSTR": { + "default": "Use motor summary screen", + "description": "", + "title": "Homevisstr", + "type": "string" + }, + "alh": { + "default": "", + "description": "Set this to alh to add the motor to the alarm handler and send emails", + "title": "Alh", + "type": "string" + }, + "HOME": { + "default": "{{P}}", + "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", + "title": "Home", + "type": "string" + }, + "ALLOW_HOMED_SET": { + "default": "#", + "description": "Set to a blank to allow this axis to have its homed", + "title": "Allow Homed Set", + "type": "string" + }, + "type": { + "const": "pmac.DlsCsPmacAsynMotor", + "default": "pmac.DlsCsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_DlsCsPmacAsynMotor", + "type": "object" + }, + "pmac_DlsPmacAsynMotor": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Object name and gui association name", + "title": "Name", + "type": "string" + }, + "Controller": { + "default": null, + "description": "PMAC Controller to attach to", + "title": "Controller", + "type": "string" + }, + "axis": { + "default": null, + "description": "which axis number this motor drives", + "title": "Axis", + "type": "integer" + }, + "P": { + "default": null, + "description": "PV prefix name for this motor", + "title": "P", + "type": "string" + }, + "M": { + "default": null, + "description": "PV motor name for this motor", + "title": "M", + "type": "string" + }, + "DESC": { + "default": "", + "description": "Description, displayed on EDM screen", + "title": "Desc", + "type": "string" + }, + "MRES": { + "default": 0.0001, + "description": "Motor Step Size (EGU)", + "title": "Mres", + "type": "number" + }, + "VELO": { + "default": 1.0, + "description": "axis Velocity (EGU/s)", + "title": "Velo", + "type": "number" + }, + "PREC": { + "default": 3, + "description": "Display Precision", + "title": "Prec", + "type": "integer" + }, + "EGU": { + "default": "mm", + "description": "Engineering Units", + "title": "Egu", + "type": "string" + }, + "TWV": { + "default": 1.0, + "description": "Tweak Step Size (EGU)", + "title": "Twv", + "type": "number" + }, + "DTYP": { + "default": "asynMotor", + "description": "Datatype of record", + "title": "Dtyp", + "type": "string" + }, + "DIR": { + "default": 0, + "description": "User direction", + "title": "Dir", + "type": "integer" + }, + "VBAS": { + "default": 1.0, + "description": "Base Velocity (EGU/s)", + "title": "Vbas", + "type": "number" + }, + "VMAX": { + "default": "{{VELO}}", + "description": "Max Velocity (EGU/s)", + "title": "Vmax", + "type": "string" + }, + "ACCL": { + "default": 0.5, + "description": "Seconds to Velocity", + "title": "Accl", + "type": "number" + }, + "BDST": { + "default": 0.0, + "description": "BL Distance (EGU)", + "title": "Bdst", + "type": "number" + }, + "BVEL": { + "default": 0.0, + "description": "BL Velocity(EGU/s)", + "title": "Bvel", + "type": "number" + }, + "BACC": { + "default": 0.0, + "description": "BL Seconds to Veloc", + "title": "Bacc", + "type": "number" + }, + "DHLM": { + "default": 10000.0, + "description": "Dial High Limit", + "title": "Dhlm", + "type": "number" + }, + "DLLM": { + "default": -10000.0, + "description": "Dial low limit", + "title": "Dllm", + "type": "number" + }, + "HLM": { + "default": 0.0, + "description": "User High Limit", + "title": "Hlm", + "type": "number" + }, + "LLM": { + "default": 0.0, + "description": "User Low Limit", + "title": "Llm", + "type": "number" + }, + "HLSV": { + "default": "MAJOR", + "description": "HW Lim, Violation Svr", + "title": "Hlsv", + "type": "string" + }, + "INIT": { + "default": "", + "description": "Startup commands", + "title": "Init", + "type": "string" + }, + "SREV": { + "default": 1000, + "description": "Steps per Revolution", + "title": "Srev", + "type": "integer" + }, + "RRES": { + "default": 0.0, + "description": "Readback Step Size (EGU", + "title": "Rres", + "type": "number" + }, + "ERES": { + "default": 0.0, + "description": "Encoder Step Size (EGU)", + "title": "Eres", + "type": "number" + }, + "JAR": { + "default": 0.0, + "description": "Jog Acceleration (EGU/s^2)", + "title": "Jar", + "type": "number" + }, + "UEIP": { + "default": 0, + "description": "Use Encoder If Present", + "title": "Ueip", + "type": "integer" + }, + "URIP": { + "default": 0, + "description": "Use RDBL If Present", + "title": "Urip", + "type": "integer" + }, + "RDBL": { + "default": "0", + "description": "Readback Location, set URIP =1 if you specify this", + "title": "Rdbl", + "type": "string" + }, + "RLNK": { + "default": "", + "description": "Readback output link", + "title": "Rlnk", + "type": "string" + }, + "RTRY": { + "default": 0, + "description": "Max retry count", + "title": "Rtry", + "type": "integer" + }, + "DLY": { + "default": 0.0, + "description": "Readback settle time (s)", + "title": "Dly", + "type": "number" + }, + "OFF": { + "default": 0.0, + "description": "User Offset (EGU)", + "title": "Off", + "type": "number" + }, + "RDBD": { + "default": 0.0, + "description": "Retry Deadband (EGU)", + "title": "Rdbd", + "type": "number" + }, + "FOFF": { + "default": 0, + "description": "Freeze Offset, 0=variable, 1=frozen", + "title": "Foff", + "type": "integer" + }, + "ADEL": { + "default": 0.0, + "description": "Alarm monitor deadband (EGU)", + "title": "Adel", + "type": "number" + }, + "NTM": { + "default": 1, + "description": "New Target Monitor, only set to 0 for soft motors", + "title": "Ntm", + "type": "integer" + }, + "FEHIGH": { + "default": 0.0, + "description": "HIGH limit for following error", + "title": "Fehigh", + "type": "number" + }, + "FEHIHI": { + "default": 0.0, + "description": "HIHI limit for following error", + "title": "Fehihi", + "type": "number" + }, + "FEHHSV": { + "default": "NO_ALARM", + "description": "HIHI alarm severity for following error", + "title": "Fehhsv", + "type": "string" + }, + "FEHSV": { + "default": "NO_ALARM", + "description": "HIGH alarm severity for following error", + "title": "Fehsv", + "type": "string" + }, + "SCALE": { + "default": 1, + "description": "", + "title": "Scale", + "type": "integer" + }, + "HOMEVIS": { + "default": 1, + "description": "If 1 then home is visible on the gui", + "title": "Homevis", + "type": "integer" + }, + "HOMEVISSTR": { + "default": "Use motor summary screen", + "description": "", + "title": "Homevisstr", + "type": "string" + }, + "alh": { + "default": "", + "description": "Set this to alh to add the motor to the alarm handler and send emails", + "title": "Alh", + "type": "string" + }, + "HOME": { + "default": "{{P}}", + "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", + "title": "Home", + "type": "string" + }, + "ALLOW_HOMED_SET": { + "default": "#", + "description": "Set to a blank to allow this axis to have its homed", + "title": "Allow Homed Set", + "type": "string" + }, + "RLINK": { + "default": "", + "description": "not sure what this is", + "title": "Rlink", + "type": "string" + }, + "type": { + "const": "pmac.DlsPmacAsynMotor", + "default": "pmac.DlsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_DlsPmacAsynMotor", + "type": "object" + }, + "pmac_Geobrick": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Name to use for the geobrick's asyn port", + "title": "Name", + "type": "string" + }, + "PORT": { + "default": null, + "description": "Asyn port name for PmacAsynIPPort to connect to", + "title": "Port", + "type": "string" + }, + "P": { + "default": null, + "description": "PV Prefix for all pmac db templates", + "title": "P", + "type": "string" + }, + "numAxes": { + "default": 8, + "description": "number of axes to initialize for the controller", + "title": "Numaxes", + "type": "integer" + }, + "idlePoll": { + "default": 500, + "description": "Idle Poll Period in ms", + "title": "Idlepoll", + "type": "integer" + }, + "movingPoll": { + "default": 100, + "description": "Moving Poll Period in ms", + "title": "Movingpoll", + "type": "integer" + }, + "TIMEOUT": { + "default": 4, + "description": "timeout in seconds for asyn", + "title": "Timeout", + "type": "integer" + }, + "FEEDRATE": { + "default": 100, + "description": "feedrate below which we go into error", + "title": "Feedrate", + "type": "integer" + }, + "CSG0": { + "default": "", + "description": "Name for Coordinate System Group 0", + "title": "Csg0", + "type": "string" + }, + "CSG1": { + "default": "", + "description": "Name for Coordinate System Group 1", + "title": "Csg1", + "type": "string" + }, + "CSG2": { + "default": "", + "description": "Name for Coordinate System Group 2", + "title": "Csg2", + "type": "string" + }, + "CSG3": { + "default": "", + "description": "Name for Coordinate System Group 3", + "title": "Csg3", + "type": "string" + }, + "CSG4": { + "default": "", + "description": "Name for Coordinate System Group 3", + "title": "Csg4", + "type": "string" + }, + "type": { + "const": "pmac.Geobrick", + "default": "pmac.Geobrick", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_Geobrick", + "type": "object" + }, + "pmac_PmacAsynIPPort": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name", + "title": "Name", + "type": "string" + }, + "IP": { + "default": null, + "description": "IP address of pmac", + "title": "Ip", + "type": "string" + }, + "PORT": { + "default": 1025, + "description": "TCP port for connection", + "title": "Port", + "type": "integer" + }, + "type": { + "const": "pmac.PmacAsynIPPort", + "default": "pmac.PmacAsynIPPort", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_PmacAsynIPPort", + "type": "object" + }, + "pmac_PmacAsynSSHPort": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name", + "title": "Name", + "type": "string" + }, + "IP": { + "default": null, + "description": "IP address of Power pmac", + "title": "Ip", + "type": "string" + }, + "USERNAME": { + "default": "root", + "description": "Username for login", + "title": "Username", + "type": "string" + }, + "PASSWORD": { + "default": "deltatau", + "description": "Password for login", + "title": "Password", + "type": "string" + }, + "PRIORITY": { + "default": 0, + "description": "Priority of the port", + "title": "Priority", + "type": "integer" + }, + "NOAUTOCONNECT": { + "default": 0, + "description": "Disables autoconnect if set to 1", + "title": "Noautoconnect", + "type": "integer" + }, + "NOEOS": { + "default": 0, + "description": "No EOS used if set to 1", + "title": "Noeos", + "type": "integer" + }, + "type": { + "const": "pmac.PmacAsynSSHPort", + "default": "pmac.PmacAsynSSHPort", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_PmacAsynSSHPort", + "type": "object" + }, + "pmac_autohome": { + "additionalProperties": false, + "properties": { + "Controller": { + "default": null, + "description": "the PMAC Controller", + "title": "Controller", + "type": "string" + }, + "PLC": { + "default": null, + "description": "PLC number of the auto home PLC", + "title": "Plc", + "type": "integer" + }, + "P": { + "default": null, + "description": "Prefix for auto home PVs", + "title": "P", + "type": "string" + }, + "GRP1": { + "default": "All", + "description": "name of the 'ALL' group of auto home axes", + "title": "Grp1", + "type": "string" + }, + "GRP2": { + "default": "", + "description": "name of the second group of auto home axes", + "title": "Grp2", + "type": "string" + }, + "GRP3": { + "default": "", + "description": "name of the third group of auto home axes", + "title": "Grp3", + "type": "string" + }, + "GRP4": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp4", + "type": "string" + }, + "GRP5": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp5", + "type": "string" + }, + "GRP6": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp6", + "type": "string" + }, + "GRP7": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp7", + "type": "string" + }, + "GRP8": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp8", + "type": "string" + }, + "GRP9": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp9", + "type": "string" + }, + "type": { + "const": "pmac.autohome", + "default": "pmac.autohome", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_autohome", + "type": "object" + }, + "pmac_pmacDisableLimitsCheck": { + "additionalProperties": false, + "properties": { + "Controller": { + "default": null, + "description": "Geobrick on which to disable limits", + "title": "Controller", + "type": "string" + }, + "Axis": { + "default": null, + "description": "Axis to have limits disabled", + "title": "Axis", + "type": "integer" + }, + "type": { + "const": "pmac.pmacDisableLimitsCheck", + "default": "pmac.pmacDisableLimitsCheck", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_pmacDisableLimitsCheck", + "type": "object" + } + }, + "additionalProperties": false, "properties": { "ioc_name": { - "type": "string", - "description": "Name of IOC instance" + "description": "Name of IOC instance", + "title": "Ioc Name", + "type": "string" }, "description": { - "type": "string", - "description": "Description of what the IOC does" + "description": "Description of what the IOC does", + "title": "Description", + "type": "string" + }, + "generic_ioc_image": { + "description": "The generic IOC container image registry URL", + "title": "Generic Ioc Image", + "type": "string" }, "entities": { - "type": "array", + "default": [], + "description": "List of entities this IOC instantiates", "items": { "anyOf": [ { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "port": { - "type": "string", - "description": "The port name for this asyn object" - }, - "input_eos": { - "type": "string", - "description": "Input end of string (terminator)" - }, - "output_eos": { - "type": "string", - "description": "Output end of string (terminator)" - }, - "priority": { - "type": "integer", - "description": "Priority", - "default": 100 - }, - "no_auto_connect": { - "type": "boolean", - "description": "Set to stop auto connect" - }, - "no_process_eos": { - "type": "boolean", - "description": "Set to avoid processing end of string" - }, - "simulation": { - "type": "string", - "description": "IP port to connect to if in simulation mode" - }, - "baud": { - "type": "integer", - "description": "Baud Rate" - }, - "bits": { - "type": "integer", - "description": "Bits [8,7,6,5]" - }, - "parity": { - "type": "string", - "description": "Parity [null,even,odd]" - }, - "stop": { - "type": "integer", - "description": "Stop Bits [1,2]" - }, - "crtscts": { - "type": "boolean", - "description": "Set hardware flow control on" - }, - "type": { - "type": "string", - "const": "asyn.AsynSerial", - "default": "asyn.AsynSerial" - } - }, - "required": [ - "port" - ], - "additionalProperties": false + "$ref": "#/$defs/asyn_AsynSerial" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "port": { - "type": "string", - "description": "Serial port tty name / IP address optionally followed by protocol" - }, - "name": { - "type": "string", - "description": "Name for the Asyn Port" - }, - "input_eos": { - "type": "string", - "description": "Input end of string (terminator)" - }, - "output_eos": { - "type": "string", - "description": "Output end of string (terminator)" - }, - "priority": { - "type": "integer", - "description": "Priority", - "default": 100 - }, - "no_auto_connect": { - "type": "boolean", - "description": "Set to stop auto connect" - }, - "no_process_eos": { - "type": "boolean", - "description": "Set to avoid processing end of string" - }, - "simulation": { - "type": "string", - "description": "IP port to connect to if in simulation mode" - }, - "type": { - "type": "string", - "const": "asyn.AsynIP", - "default": "asyn.AsynIP" - } - }, - "required": [ - "port", - "name" - ], - "additionalProperties": false + "$ref": "#/$defs/asyn_AsynIP" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name", - "vscode_ibek_plugin_type": "type_id" - }, - "IP": { - "type": "string", - "description": "IP address of Power pmac" - }, - "USERNAME": { - "type": "string", - "description": "Username for login", - "default": "root" - }, - "PASSWORD": { - "type": "string", - "description": "Password for login", - "default": "deltatau" - }, - "PRIORITY": { - "type": "integer", - "description": "Priority of the port", - "default": 0 - }, - "NOAUTOCONNECT": { - "type": "integer", - "description": "Disables autoconnect if set to 1", - "default": 0 - }, - "NOEOS": { - "type": "integer", - "description": "No EOS used if set to 1", - "default": 0 - }, - "type": { - "type": "string", - "const": "pmac.PmacAsynSSHPort", - "default": "pmac.PmacAsynSSHPort" - } - }, - "required": [ - "name", - "IP" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_PmacAsynSSHPort" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name", - "vscode_ibek_plugin_type": "type_id" - }, - "IP": { - "type": "string", - "description": "IP address of pmac" - }, - "PORT": { - "type": "integer", - "description": "TCP port for connection", - "default": 1025 - }, - "type": { - "type": "string", - "const": "pmac.PmacAsynIPPort", - "default": "pmac.PmacAsynIPPort" - } - }, - "required": [ - "name", - "IP" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_PmacAsynIPPort" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Name to use for the geobrick's asyn port", - "vscode_ibek_plugin_type": "type_id" - }, - "PORT": { - "type": "string", - "description": "Asyn port name for PmacAsynIPPort to connect to", - "vscode_ibek_plugin_type": "type_object" - }, - "P": { - "type": "string", - "description": "PV Prefix for all pmac db templates" - }, - "numAxes": { - "type": "integer", - "description": "number of axes to initialize for the controller", - "default": 8 - }, - "idlePoll": { - "type": "integer", - "description": "Idle Poll Period in ms", - "default": 500 - }, - "movingPoll": { - "type": "integer", - "description": "Moving Poll Period in ms", - "default": 100 - }, - "TIMEOUT": { - "type": "integer", - "description": "timeout in seconds for asyn", - "default": 4 - }, - "FEEDRATE": { - "type": "integer", - "description": "feedrate below which we go into error", - "default": 100 - }, - "CSG0": { - "type": "string", - "description": "Name for Coordinate System Group 0", - "default": "" - }, - "CSG1": { - "type": "string", - "description": "Name for Coordinate System Group 1", - "default": "" - }, - "CSG2": { - "type": "string", - "description": "Name for Coordinate System Group 2", - "default": "" - }, - "CSG3": { - "type": "string", - "description": "Name for Coordinate System Group 3", - "default": "" - }, - "CSG4": { - "type": "string", - "description": "Name for Coordinate System Group 3", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.Geobrick", - "default": "pmac.Geobrick" - } - }, - "required": [ - "name", - "PORT", - "P" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_Geobrick" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Object name and gui association name" - }, - "Controller": { - "type": "string", - "description": "PMAC Controller to attach to", - "vscode_ibek_plugin_type": "type_object" - }, - "axis": { - "type": "integer", - "description": "which axis number this motor drives" - }, - "P": { - "type": "string", - "description": "PV prefix name for this motor" - }, - "M": { - "type": "string", - "description": "PV motor name for this motor" - }, - "DESC": { - "type": "string", - "description": "Description, displayed on EDM screen", - "default": "" - }, - "MRES": { - "type": "number", - "description": "Motor Step Size (EGU)", - "default": 0.0001 - }, - "VELO": { - "type": "number", - "description": "axis Velocity (EGU/s)", - "default": 1.0 - }, - "PREC": { - "type": "integer", - "description": "Display Precision", - "default": 3 - }, - "EGU": { - "type": "string", - "description": "Engineering Units", - "default": "mm" - }, - "TWV": { - "type": "number", - "description": "Tweak Step Size (EGU)", - "default": 1.0 - }, - "DTYP": { - "type": "string", - "description": "Datatype of record", - "default": "asynMotor" - }, - "DIR": { - "type": "integer", - "description": "User direction", - "default": 0 - }, - "VBAS": { - "type": "number", - "description": "Base Velocity (EGU/s)", - "default": 1.0 - }, - "VMAX": { - "type": "string", - "description": "Max Velocity (EGU/s)", - "default": "{{VELO}}" - }, - "ACCL": { - "type": "number", - "description": "Seconds to Velocity", - "default": 0.5 - }, - "BDST": { - "type": "number", - "description": "BL Distance (EGU)", - "default": 0.0 - }, - "BVEL": { - "type": "number", - "description": "BL Velocity(EGU/s)", - "default": 0.0 - }, - "BACC": { - "type": "number", - "description": "BL Seconds to Veloc", - "default": 0.0 - }, - "DHLM": { - "type": "number", - "description": "Dial High Limit", - "default": 10000.0 - }, - "DLLM": { - "type": "number", - "description": "Dial low limit", - "default": -10000.0 - }, - "HLM": { - "type": "number", - "description": "User High Limit", - "default": 0.0 - }, - "LLM": { - "type": "number", - "description": "User Low Limit", - "default": 0.0 - }, - "HLSV": { - "type": "string", - "description": "HW Lim, Violation Svr", - "default": "MAJOR" - }, - "INIT": { - "type": "string", - "description": "Startup commands", - "default": "" - }, - "SREV": { - "type": "integer", - "description": "Steps per Revolution", - "default": 1000 - }, - "RRES": { - "type": "number", - "description": "Readback Step Size (EGU", - "default": 0.0 - }, - "ERES": { - "type": "number", - "description": "Encoder Step Size (EGU)", - "default": 0.0 - }, - "JAR": { - "type": "number", - "description": "Jog Acceleration (EGU/s^2)", - "default": 0.0 - }, - "UEIP": { - "type": "integer", - "description": "Use Encoder If Present", - "default": 0 - }, - "URIP": { - "type": "integer", - "description": "Use RDBL If Present", - "default": 0 - }, - "RDBL": { - "type": "string", - "description": "Readback Location, set URIP =1 if you specify this", - "default": "0" - }, - "RLNK": { - "type": "string", - "description": "Readback output link", - "default": "" - }, - "RTRY": { - "type": "integer", - "description": "Max retry count", - "default": 0 - }, - "DLY": { - "type": "number", - "description": "Readback settle time (s)", - "default": 0.0 - }, - "OFF": { - "type": "number", - "description": "User Offset (EGU)", - "default": 0.0 - }, - "RDBD": { - "type": "number", - "description": "Retry Deadband (EGU)", - "default": 0.0 - }, - "FOFF": { - "type": "integer", - "description": "Freeze Offset, 0=variable, 1=frozen", - "default": 0 - }, - "ADEL": { - "type": "number", - "description": "Alarm monitor deadband (EGU)", - "default": 0.0 - }, - "NTM": { - "type": "integer", - "description": "New Target Monitor, only set to 0 for soft motors", - "default": 1 - }, - "FEHIGH": { - "type": "number", - "description": "HIGH limit for following error", - "default": 0.0 - }, - "FEHIHI": { - "type": "number", - "description": "HIHI limit for following error", - "default": 0.0 - }, - "FEHHSV": { - "type": "string", - "description": "HIHI alarm severity for following error", - "default": "NO_ALARM" - }, - "FEHSV": { - "type": "string", - "description": "HIGH alarm severity for following error", - "default": "NO_ALARM" - }, - "SCALE": { - "type": "integer", - "default": 1 - }, - "HOMEVIS": { - "type": "integer", - "description": "If 1 then home is visible on the gui", - "default": 1 - }, - "HOMEVISSTR": { - "type": "string", - "default": "Use motor summary screen" - }, - "alh": { - "type": "string", - "description": "Set this to alh to add the motor to the alarm handler and send emails", - "default": "" - }, - "HOME": { - "type": "string", - "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", - "default": "{{P}}" - }, - "ALLOW_HOMED_SET": { - "type": "string", - "description": "Set to a blank to allow this axis to have its homed", - "default": "#" - }, - "RLINK": { - "type": "string", - "description": "not sure what this is", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.DlsPmacAsynMotor", - "default": "pmac.DlsPmacAsynMotor" - } - }, - "required": [ - "name", - "Controller", - "axis", - "P", - "M" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_DlsPmacAsynMotor" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Object name and gui association name" - }, - "CsController": { - "type": "string", - "description": "Coordinate system controller to attach to", - "vscode_ibek_plugin_type": "type_object" - }, - "axis": { - "type": "integer", - "description": "which axis number this motor drives" - }, - "P": { - "type": "string", - "description": "PV prefix name for this motor" - }, - "M": { - "type": "string", - "description": "PV motor name for this motor" - }, - "DESC": { - "type": "string", - "description": "Description, displayed on EDM screen", - "default": "" - }, - "MRES": { - "type": "number", - "description": "Motor Step Size (EGU)", - "default": 0.0001 - }, - "VELO": { - "type": "number", - "description": "axis Velocity (EGU/s)", - "default": 1.0 - }, - "PREC": { - "type": "integer", - "description": "Display Precision", - "default": 3 - }, - "EGU": { - "type": "string", - "description": "Engineering Units", - "default": "mm" - }, - "TWV": { - "type": "number", - "description": "Tweak Step Size (EGU)", - "default": 1.0 - }, - "DTYP": { - "type": "string", - "description": "Datatype of record", - "default": "asynMotor" - }, - "DIR": { - "type": "integer", - "description": "User direction", - "default": 0 - }, - "VBAS": { - "type": "number", - "description": "Base Velocity (EGU/s)", - "default": 1.0 - }, - "VMAX": { - "type": "string", - "description": "Max Velocity (EGU/s)", - "default": "{{VELO}}" - }, - "ACCL": { - "type": "number", - "description": "Seconds to Velocity", - "default": 0.5 - }, - "BDST": { - "type": "number", - "description": "BL Distance (EGU)", - "default": 0.0 - }, - "BVEL": { - "type": "number", - "description": "BL Velocity(EGU/s)", - "default": 0.0 - }, - "BACC": { - "type": "number", - "description": "BL Seconds to Veloc", - "default": 0.0 - }, - "DHLM": { - "type": "number", - "description": "Dial High Limit", - "default": 10000.0 - }, - "DLLM": { - "type": "number", - "description": "Dial low limit", - "default": -10000.0 - }, - "HLM": { - "type": "number", - "description": "User High Limit", - "default": 0.0 - }, - "LLM": { - "type": "number", - "description": "User Low Limit", - "default": 0.0 - }, - "HLSV": { - "type": "string", - "description": "HW Lim, Violation Svr", - "default": "MAJOR" - }, - "INIT": { - "type": "string", - "description": "Startup commands", - "default": "" - }, - "SREV": { - "type": "integer", - "description": "Steps per Revolution", - "default": 1000 - }, - "RRES": { - "type": "number", - "description": "Readback Step Size (EGU", - "default": 0.0 - }, - "ERES": { - "type": "number", - "description": "Encoder Step Size (EGU)", - "default": 0.0 - }, - "JAR": { - "type": "number", - "description": "Jog Acceleration (EGU/s^2)", - "default": 0.0 - }, - "UEIP": { - "type": "integer", - "description": "Use Encoder If Present", - "default": 0 - }, - "URIP": { - "type": "integer", - "description": "Use RDBL If Present", - "default": 0 - }, - "RDBL": { - "type": "string", - "description": "Readback Location, set URIP =1 if you specify this", - "default": "0" - }, - "RLNK": { - "type": "string", - "description": "Readback output link", - "default": "" - }, - "RTRY": { - "type": "integer", - "description": "Max retry count", - "default": 0 - }, - "DLY": { - "type": "number", - "description": "Readback settle time (s)", - "default": 0.0 - }, - "OFF": { - "type": "number", - "description": "User Offset (EGU)", - "default": 0.0 - }, - "RDBD": { - "type": "number", - "description": "Retry Deadband (EGU)", - "default": 0.0 - }, - "FOFF": { - "type": "integer", - "description": "Freeze Offset, 0=variable, 1=frozen", - "default": 0 - }, - "ADEL": { - "type": "number", - "description": "Alarm monitor deadband (EGU)", - "default": 0.0 - }, - "NTM": { - "type": "integer", - "description": "New Target Monitor, only set to 0 for soft motors", - "default": 1 - }, - "FEHEIGH": { - "type": "number", - "description": "HIGH limit for following error", - "default": 0.0 - }, - "FEHIHI": { - "type": "number", - "description": "HIHI limit for following error", - "default": 0.0 - }, - "FEHHSV": { - "type": "string", - "description": "HIHI alarm severity for following error", - "default": "NO_ALARM" - }, - "FEHSV": { - "type": "string", - "description": "HIGH alarm severity for following error", - "default": "NO_ALARM" - }, - "SCALE": { - "type": "integer", - "default": 1 - }, - "HOMEVIS": { - "type": "integer", - "description": "If 1 then home is visible on the gui", - "default": 1 - }, - "HOMEVISSTR": { - "type": "string", - "default": "Use motor summary screen" - }, - "alh": { - "type": "string", - "description": "Set this to alh to add the motor to the alarm handler and send emails", - "default": "" - }, - "HOME": { - "type": "string", - "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", - "default": "{{P}}" - }, - "ALLOW_HOMED_SET": { - "type": "string", - "description": "Set to a blank to allow this axis to have its homed", - "default": "#" - }, - "type": { - "type": "string", - "const": "pmac.DlsCsPmacAsynMotor", - "default": "pmac.DlsCsPmacAsynMotor" - } - }, - "required": [ - "name", - "CsController", - "axis", - "P", - "M" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "Controller": { - "type": "string", - "description": "Geobrick on which to disable limits", - "vscode_ibek_plugin_type": "type_object" - }, - "Axis": { - "type": "integer", - "description": "Axis to have limits disabled" - }, - "type": { - "type": "string", - "const": "pmac.pmacDisableLimitsCheck", - "default": "pmac.pmacDisableLimitsCheck" - } - }, - "required": [ - "Controller", - "Axis" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "Controller": { - "type": "string", - "description": "the PMAC Controller", - "vscode_ibek_plugin_type": "type_object" - }, - "PLC": { - "type": "integer", - "description": "PLC number of the auto home PLC" - }, - "P": { - "type": "string", - "description": "Prefix for auto home PVs" - }, - "GRP1": { - "type": "string", - "description": "name of the 'ALL' group of auto home axes", - "default": "All" - }, - "GRP2": { - "type": "string", - "description": "name of the second group of auto home axes", - "default": "" - }, - "GRP3": { - "type": "string", - "description": "name of the third group of auto home axes", - "default": "" - }, - "GRP4": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP5": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP6": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP7": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP8": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP9": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.autohome", - "default": "pmac.autohome" - } - }, - "required": [ - "Controller", - "PLC", - "P" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_autohome" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name for this object", - "vscode_ibek_plugin_type": "type_id" - }, - "Controller": { - "type": "string", - "description": "the PMAC Controller", - "vscode_ibek_plugin_type": "type_object" - }, - "CS": { - "type": "integer", - "description": "Coordinate system number" - }, - "NAxes": { - "type": "integer", - "description": "number of CS axes", - "default": 9 - }, - "Program": { - "type": "integer", - "description": "PROG number for CS motion", - "default": 10 - }, - "type": { - "type": "string", - "const": "pmac.CS", - "default": "pmac.CS" - } - }, - "required": [ - "name", - "Controller", - "CS" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_CS" } ] }, - "description": "List of entities this IOC instantiates" - }, - "generic_ioc_image": { - "type": "string", - "description": "The generic IOC container image registry URL" + "title": "Entities", + "type": "array" } }, "required": [ "ioc_name", "description", - "entities", "generic_ioc_image" ], - "additionalProperties": false, - "$schema": "http://json-schema.org/draft-07/schema#" + "title": "NewIOC", + "type": "object" } \ No newline at end of file diff --git a/tests/samples/schemas/epics.ibek.support.schema.json b/tests/samples/schemas/epics.ibek.support.schema.json index 0b0f332b5..cf10e6ba5 100644 --- a/tests/samples/schemas/epics.ibek.support.schema.json +++ b/tests/samples/schemas/epics.ibek.support.schema.json @@ -1,195 +1,211 @@ { - "type": "object", + "$defs": { + "epics_Dbpf": { + "additionalProperties": false, + "properties": { + "pv": { + "default": null, + "description": "Name of PV", + "title": "Pv", + "type": "string" + }, + "value": { + "default": null, + "description": "Value to set", + "title": "Value", + "type": "string" + }, + "type": { + "const": "epics.Dbpf", + "default": "epics.Dbpf", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_Dbpf", + "type": "object" + }, + "epics_EpicsCaMaxArrayBytes": { + "additionalProperties": false, + "properties": { + "max_bytes": { + "default": 6000000, + "description": "Max size in bytes for sending arrays over channel access", + "title": "Max Bytes", + "type": "integer" + }, + "type": { + "const": "epics.EpicsCaMaxArrayBytes", + "default": "epics.EpicsCaMaxArrayBytes", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_EpicsCaMaxArrayBytes", + "type": "object" + }, + "epics_EpicsEnvSet": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Name of environment variable", + "title": "Name", + "type": "string" + }, + "value": { + "default": null, + "description": "Value of environment variable", + "title": "Value", + "type": "string" + }, + "type": { + "const": "epics.EpicsEnvSet", + "default": "epics.EpicsEnvSet", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_EpicsEnvSet", + "type": "object" + }, + "epics_EpicsTsMinWest": { + "additionalProperties": false, + "properties": { + "minutes_west": { + "default": 0, + "description": "relative time zone minutes", + "title": "Minutes West", + "type": "integer" + }, + "type": { + "const": "epics.EpicsTsMinWest", + "default": "epics.EpicsTsMinWest", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_EpicsTsMinWest", + "type": "object" + }, + "epics_InterruptVectorVME": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "A name for an interrupt vector variable", + "title": "Name", + "type": "string" + }, + "count": { + "default": 1, + "description": "The number of interrupt vectors to reserve", + "title": "Count", + "type": "integer" + }, + "type": { + "const": "epics.InterruptVectorVME", + "default": "epics.InterruptVectorVME", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_InterruptVectorVME", + "type": "object" + }, + "epics_PostStartupCommand": { + "additionalProperties": false, + "properties": { + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" + }, + "type": { + "const": "epics.PostStartupCommand", + "default": "epics.PostStartupCommand", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_PostStartupCommand", + "type": "object" + }, + "epics_StartupCommand": { + "additionalProperties": false, + "properties": { + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" + }, + "type": { + "const": "epics.StartupCommand", + "default": "epics.StartupCommand", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "epics_StartupCommand", + "type": "object" + } + }, + "additionalProperties": false, "properties": { "ioc_name": { - "type": "string", - "description": "Name of IOC instance" + "description": "Name of IOC instance", + "title": "Ioc Name", + "type": "string" }, "description": { - "type": "string", - "description": "Description of what the IOC does" + "description": "Description of what the IOC does", + "title": "Description", + "type": "string" + }, + "generic_ioc_image": { + "description": "The generic IOC container image registry URL", + "title": "Generic Ioc Image", + "type": "string" }, "entities": { - "type": "array", + "default": [], + "description": "List of entities this IOC instantiates", "items": { "anyOf": [ { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "max_bytes": { - "type": "integer", - "description": "Max size in bytes for sending arrays over channel access", - "default": 6000000 - }, - "type": { - "type": "string", - "const": "epics.EpicsCaMaxArrayBytes", - "default": "epics.EpicsCaMaxArrayBytes" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_EpicsCaMaxArrayBytes" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "minutes_west": { - "type": "integer", - "description": "relative time zone minutes", - "default": 0 - }, - "type": { - "type": "string", - "const": "epics.EpicsTsMinWest", - "default": "epics.EpicsTsMinWest" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_EpicsTsMinWest" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "pv": { - "type": "string", - "description": "Name of PV" - }, - "value": { - "type": "string", - "description": "Value to set" - }, - "type": { - "type": "string", - "const": "epics.Dbpf", - "default": "epics.Dbpf" - } - }, - "required": [ - "pv", - "value" - ], - "additionalProperties": false + "$ref": "#/$defs/epics_Dbpf" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Name of environment variable" - }, - "value": { - "type": "string", - "description": "Value of environment variable" - }, - "type": { - "type": "string", - "const": "epics.EpicsEnvSet", - "default": "epics.EpicsEnvSet" - } - }, - "required": [ - "name", - "value" - ], - "additionalProperties": false + "$ref": "#/$defs/epics_EpicsEnvSet" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "command": { - "type": "string", - "description": "command string", - "default": "" - }, - "type": { - "type": "string", - "const": "epics.StartupCommand", - "default": "epics.StartupCommand" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_StartupCommand" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "command": { - "type": "string", - "description": "command string", - "default": "" - }, - "type": { - "type": "string", - "const": "epics.PostStartupCommand", - "default": "epics.PostStartupCommand" - } - }, - "additionalProperties": false + "$ref": "#/$defs/epics_PostStartupCommand" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "A name for an interrupt vector variable", - "vscode_ibek_plugin_type": "type_id" - }, - "count": { - "type": "integer", - "description": "The number of interrupt vectors to reserve", - "default": 1 - }, - "type": { - "type": "string", - "const": "epics.InterruptVectorVME", - "default": "epics.InterruptVectorVME" - } - }, - "required": [ - "name" - ], - "additionalProperties": false + "$ref": "#/$defs/epics_InterruptVectorVME" } ] }, - "description": "List of entities this IOC instantiates" - }, - "generic_ioc_image": { - "type": "string", - "description": "The generic IOC container image registry URL" + "title": "Entities", + "type": "array" } }, "required": [ "ioc_name", "description", - "entities", "generic_ioc_image" ], - "additionalProperties": false, - "$schema": "http://json-schema.org/draft-07/schema#" + "title": "NewIOC", + "type": "object" } \ No newline at end of file diff --git a/tests/samples/schemas/pmac.ibek.entities.schema.json b/tests/samples/schemas/pmac.ibek.entities.schema.json index a0f3d71c0..1a55d5f35 100644 --- a/tests/samples/schemas/pmac.ibek.entities.schema.json +++ b/tests/samples/schemas/pmac.ibek.entities.schema.json @@ -1,890 +1,1025 @@ { - "type": "object", + "$defs": { + "pmac_CS": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name for this object", + "title": "Name", + "type": "string" + }, + "Controller": { + "default": null, + "description": "the PMAC Controller", + "title": "Controller", + "type": "string" + }, + "CS": { + "default": null, + "description": "Coordinate system number", + "title": "Cs", + "type": "integer" + }, + "NAxes": { + "default": 9, + "description": "number of CS axes", + "title": "Naxes", + "type": "integer" + }, + "Program": { + "default": 10, + "description": "PROG number for CS motion", + "title": "Program", + "type": "integer" + }, + "type": { + "const": "pmac.CS", + "default": "pmac.CS", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_CS", + "type": "object" + }, + "pmac_DlsCsPmacAsynMotor": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Object name and gui association name", + "title": "Name", + "type": "string" + }, + "CsController": { + "default": null, + "description": "Coordinate system controller to attach to", + "title": "Cscontroller", + "type": "string" + }, + "axis": { + "default": null, + "description": "which axis number this motor drives", + "title": "Axis", + "type": "integer" + }, + "P": { + "default": null, + "description": "PV prefix name for this motor", + "title": "P", + "type": "string" + }, + "M": { + "default": null, + "description": "PV motor name for this motor", + "title": "M", + "type": "string" + }, + "DESC": { + "default": "", + "description": "Description, displayed on EDM screen", + "title": "Desc", + "type": "string" + }, + "MRES": { + "default": 0.0001, + "description": "Motor Step Size (EGU)", + "title": "Mres", + "type": "number" + }, + "VELO": { + "default": 1.0, + "description": "axis Velocity (EGU/s)", + "title": "Velo", + "type": "number" + }, + "PREC": { + "default": 3, + "description": "Display Precision", + "title": "Prec", + "type": "integer" + }, + "EGU": { + "default": "mm", + "description": "Engineering Units", + "title": "Egu", + "type": "string" + }, + "TWV": { + "default": 1.0, + "description": "Tweak Step Size (EGU)", + "title": "Twv", + "type": "number" + }, + "DTYP": { + "default": "asynMotor", + "description": "Datatype of record", + "title": "Dtyp", + "type": "string" + }, + "DIR": { + "default": 0, + "description": "User direction", + "title": "Dir", + "type": "integer" + }, + "VBAS": { + "default": 1.0, + "description": "Base Velocity (EGU/s)", + "title": "Vbas", + "type": "number" + }, + "VMAX": { + "default": "{{VELO}}", + "description": "Max Velocity (EGU/s)", + "title": "Vmax", + "type": "string" + }, + "ACCL": { + "default": 0.5, + "description": "Seconds to Velocity", + "title": "Accl", + "type": "number" + }, + "BDST": { + "default": 0.0, + "description": "BL Distance (EGU)", + "title": "Bdst", + "type": "number" + }, + "BVEL": { + "default": 0.0, + "description": "BL Velocity(EGU/s)", + "title": "Bvel", + "type": "number" + }, + "BACC": { + "default": 0.0, + "description": "BL Seconds to Veloc", + "title": "Bacc", + "type": "number" + }, + "DHLM": { + "default": 10000.0, + "description": "Dial High Limit", + "title": "Dhlm", + "type": "number" + }, + "DLLM": { + "default": -10000.0, + "description": "Dial low limit", + "title": "Dllm", + "type": "number" + }, + "HLM": { + "default": 0.0, + "description": "User High Limit", + "title": "Hlm", + "type": "number" + }, + "LLM": { + "default": 0.0, + "description": "User Low Limit", + "title": "Llm", + "type": "number" + }, + "HLSV": { + "default": "MAJOR", + "description": "HW Lim, Violation Svr", + "title": "Hlsv", + "type": "string" + }, + "INIT": { + "default": "", + "description": "Startup commands", + "title": "Init", + "type": "string" + }, + "SREV": { + "default": 1000, + "description": "Steps per Revolution", + "title": "Srev", + "type": "integer" + }, + "RRES": { + "default": 0.0, + "description": "Readback Step Size (EGU", + "title": "Rres", + "type": "number" + }, + "ERES": { + "default": 0.0, + "description": "Encoder Step Size (EGU)", + "title": "Eres", + "type": "number" + }, + "JAR": { + "default": 0.0, + "description": "Jog Acceleration (EGU/s^2)", + "title": "Jar", + "type": "number" + }, + "UEIP": { + "default": 0, + "description": "Use Encoder If Present", + "title": "Ueip", + "type": "integer" + }, + "URIP": { + "default": 0, + "description": "Use RDBL If Present", + "title": "Urip", + "type": "integer" + }, + "RDBL": { + "default": "0", + "description": "Readback Location, set URIP =1 if you specify this", + "title": "Rdbl", + "type": "string" + }, + "RLNK": { + "default": "", + "description": "Readback output link", + "title": "Rlnk", + "type": "string" + }, + "RTRY": { + "default": 0, + "description": "Max retry count", + "title": "Rtry", + "type": "integer" + }, + "DLY": { + "default": 0.0, + "description": "Readback settle time (s)", + "title": "Dly", + "type": "number" + }, + "OFF": { + "default": 0.0, + "description": "User Offset (EGU)", + "title": "Off", + "type": "number" + }, + "RDBD": { + "default": 0.0, + "description": "Retry Deadband (EGU)", + "title": "Rdbd", + "type": "number" + }, + "FOFF": { + "default": 0, + "description": "Freeze Offset, 0=variable, 1=frozen", + "title": "Foff", + "type": "integer" + }, + "ADEL": { + "default": 0.0, + "description": "Alarm monitor deadband (EGU)", + "title": "Adel", + "type": "number" + }, + "NTM": { + "default": 1, + "description": "New Target Monitor, only set to 0 for soft motors", + "title": "Ntm", + "type": "integer" + }, + "FEHEIGH": { + "default": 0.0, + "description": "HIGH limit for following error", + "title": "Feheigh", + "type": "number" + }, + "FEHIHI": { + "default": 0.0, + "description": "HIHI limit for following error", + "title": "Fehihi", + "type": "number" + }, + "FEHHSV": { + "default": "NO_ALARM", + "description": "HIHI alarm severity for following error", + "title": "Fehhsv", + "type": "string" + }, + "FEHSV": { + "default": "NO_ALARM", + "description": "HIGH alarm severity for following error", + "title": "Fehsv", + "type": "string" + }, + "SCALE": { + "default": 1, + "description": "", + "title": "Scale", + "type": "integer" + }, + "HOMEVIS": { + "default": 1, + "description": "If 1 then home is visible on the gui", + "title": "Homevis", + "type": "integer" + }, + "HOMEVISSTR": { + "default": "Use motor summary screen", + "description": "", + "title": "Homevisstr", + "type": "string" + }, + "alh": { + "default": "", + "description": "Set this to alh to add the motor to the alarm handler and send emails", + "title": "Alh", + "type": "string" + }, + "HOME": { + "default": "{{P}}", + "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", + "title": "Home", + "type": "string" + }, + "ALLOW_HOMED_SET": { + "default": "#", + "description": "Set to a blank to allow this axis to have its homed", + "title": "Allow Homed Set", + "type": "string" + }, + "type": { + "const": "pmac.DlsCsPmacAsynMotor", + "default": "pmac.DlsCsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_DlsCsPmacAsynMotor", + "type": "object" + }, + "pmac_DlsPmacAsynMotor": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Object name and gui association name", + "title": "Name", + "type": "string" + }, + "Controller": { + "default": null, + "description": "PMAC Controller to attach to", + "title": "Controller", + "type": "string" + }, + "axis": { + "default": null, + "description": "which axis number this motor drives", + "title": "Axis", + "type": "integer" + }, + "P": { + "default": null, + "description": "PV prefix name for this motor", + "title": "P", + "type": "string" + }, + "M": { + "default": null, + "description": "PV motor name for this motor", + "title": "M", + "type": "string" + }, + "DESC": { + "default": "", + "description": "Description, displayed on EDM screen", + "title": "Desc", + "type": "string" + }, + "MRES": { + "default": 0.0001, + "description": "Motor Step Size (EGU)", + "title": "Mres", + "type": "number" + }, + "VELO": { + "default": 1.0, + "description": "axis Velocity (EGU/s)", + "title": "Velo", + "type": "number" + }, + "PREC": { + "default": 3, + "description": "Display Precision", + "title": "Prec", + "type": "integer" + }, + "EGU": { + "default": "mm", + "description": "Engineering Units", + "title": "Egu", + "type": "string" + }, + "TWV": { + "default": 1.0, + "description": "Tweak Step Size (EGU)", + "title": "Twv", + "type": "number" + }, + "DTYP": { + "default": "asynMotor", + "description": "Datatype of record", + "title": "Dtyp", + "type": "string" + }, + "DIR": { + "default": 0, + "description": "User direction", + "title": "Dir", + "type": "integer" + }, + "VBAS": { + "default": 1.0, + "description": "Base Velocity (EGU/s)", + "title": "Vbas", + "type": "number" + }, + "VMAX": { + "default": "{{VELO}}", + "description": "Max Velocity (EGU/s)", + "title": "Vmax", + "type": "string" + }, + "ACCL": { + "default": 0.5, + "description": "Seconds to Velocity", + "title": "Accl", + "type": "number" + }, + "BDST": { + "default": 0.0, + "description": "BL Distance (EGU)", + "title": "Bdst", + "type": "number" + }, + "BVEL": { + "default": 0.0, + "description": "BL Velocity(EGU/s)", + "title": "Bvel", + "type": "number" + }, + "BACC": { + "default": 0.0, + "description": "BL Seconds to Veloc", + "title": "Bacc", + "type": "number" + }, + "DHLM": { + "default": 10000.0, + "description": "Dial High Limit", + "title": "Dhlm", + "type": "number" + }, + "DLLM": { + "default": -10000.0, + "description": "Dial low limit", + "title": "Dllm", + "type": "number" + }, + "HLM": { + "default": 0.0, + "description": "User High Limit", + "title": "Hlm", + "type": "number" + }, + "LLM": { + "default": 0.0, + "description": "User Low Limit", + "title": "Llm", + "type": "number" + }, + "HLSV": { + "default": "MAJOR", + "description": "HW Lim, Violation Svr", + "title": "Hlsv", + "type": "string" + }, + "INIT": { + "default": "", + "description": "Startup commands", + "title": "Init", + "type": "string" + }, + "SREV": { + "default": 1000, + "description": "Steps per Revolution", + "title": "Srev", + "type": "integer" + }, + "RRES": { + "default": 0.0, + "description": "Readback Step Size (EGU", + "title": "Rres", + "type": "number" + }, + "ERES": { + "default": 0.0, + "description": "Encoder Step Size (EGU)", + "title": "Eres", + "type": "number" + }, + "JAR": { + "default": 0.0, + "description": "Jog Acceleration (EGU/s^2)", + "title": "Jar", + "type": "number" + }, + "UEIP": { + "default": 0, + "description": "Use Encoder If Present", + "title": "Ueip", + "type": "integer" + }, + "URIP": { + "default": 0, + "description": "Use RDBL If Present", + "title": "Urip", + "type": "integer" + }, + "RDBL": { + "default": "0", + "description": "Readback Location, set URIP =1 if you specify this", + "title": "Rdbl", + "type": "string" + }, + "RLNK": { + "default": "", + "description": "Readback output link", + "title": "Rlnk", + "type": "string" + }, + "RTRY": { + "default": 0, + "description": "Max retry count", + "title": "Rtry", + "type": "integer" + }, + "DLY": { + "default": 0.0, + "description": "Readback settle time (s)", + "title": "Dly", + "type": "number" + }, + "OFF": { + "default": 0.0, + "description": "User Offset (EGU)", + "title": "Off", + "type": "number" + }, + "RDBD": { + "default": 0.0, + "description": "Retry Deadband (EGU)", + "title": "Rdbd", + "type": "number" + }, + "FOFF": { + "default": 0, + "description": "Freeze Offset, 0=variable, 1=frozen", + "title": "Foff", + "type": "integer" + }, + "ADEL": { + "default": 0.0, + "description": "Alarm monitor deadband (EGU)", + "title": "Adel", + "type": "number" + }, + "NTM": { + "default": 1, + "description": "New Target Monitor, only set to 0 for soft motors", + "title": "Ntm", + "type": "integer" + }, + "FEHIGH": { + "default": 0.0, + "description": "HIGH limit for following error", + "title": "Fehigh", + "type": "number" + }, + "FEHIHI": { + "default": 0.0, + "description": "HIHI limit for following error", + "title": "Fehihi", + "type": "number" + }, + "FEHHSV": { + "default": "NO_ALARM", + "description": "HIHI alarm severity for following error", + "title": "Fehhsv", + "type": "string" + }, + "FEHSV": { + "default": "NO_ALARM", + "description": "HIGH alarm severity for following error", + "title": "Fehsv", + "type": "string" + }, + "SCALE": { + "default": 1, + "description": "", + "title": "Scale", + "type": "integer" + }, + "HOMEVIS": { + "default": 1, + "description": "If 1 then home is visible on the gui", + "title": "Homevis", + "type": "integer" + }, + "HOMEVISSTR": { + "default": "Use motor summary screen", + "description": "", + "title": "Homevisstr", + "type": "string" + }, + "alh": { + "default": "", + "description": "Set this to alh to add the motor to the alarm handler and send emails", + "title": "Alh", + "type": "string" + }, + "HOME": { + "default": "{{P}}", + "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", + "title": "Home", + "type": "string" + }, + "ALLOW_HOMED_SET": { + "default": "#", + "description": "Set to a blank to allow this axis to have its homed", + "title": "Allow Homed Set", + "type": "string" + }, + "RLINK": { + "default": "", + "description": "not sure what this is", + "title": "Rlink", + "type": "string" + }, + "type": { + "const": "pmac.DlsPmacAsynMotor", + "default": "pmac.DlsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_DlsPmacAsynMotor", + "type": "object" + }, + "pmac_Geobrick": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Name to use for the geobrick's asyn port", + "title": "Name", + "type": "string" + }, + "PORT": { + "default": null, + "description": "Asyn port name for PmacAsynIPPort to connect to", + "title": "Port", + "type": "string" + }, + "P": { + "default": null, + "description": "PV Prefix for all pmac db templates", + "title": "P", + "type": "string" + }, + "numAxes": { + "default": 8, + "description": "number of axes to initialize for the controller", + "title": "Numaxes", + "type": "integer" + }, + "idlePoll": { + "default": 500, + "description": "Idle Poll Period in ms", + "title": "Idlepoll", + "type": "integer" + }, + "movingPoll": { + "default": 100, + "description": "Moving Poll Period in ms", + "title": "Movingpoll", + "type": "integer" + }, + "TIMEOUT": { + "default": 4, + "description": "timeout in seconds for asyn", + "title": "Timeout", + "type": "integer" + }, + "FEEDRATE": { + "default": 100, + "description": "feedrate below which we go into error", + "title": "Feedrate", + "type": "integer" + }, + "CSG0": { + "default": "", + "description": "Name for Coordinate System Group 0", + "title": "Csg0", + "type": "string" + }, + "CSG1": { + "default": "", + "description": "Name for Coordinate System Group 1", + "title": "Csg1", + "type": "string" + }, + "CSG2": { + "default": "", + "description": "Name for Coordinate System Group 2", + "title": "Csg2", + "type": "string" + }, + "CSG3": { + "default": "", + "description": "Name for Coordinate System Group 3", + "title": "Csg3", + "type": "string" + }, + "CSG4": { + "default": "", + "description": "Name for Coordinate System Group 3", + "title": "Csg4", + "type": "string" + }, + "type": { + "const": "pmac.Geobrick", + "default": "pmac.Geobrick", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_Geobrick", + "type": "object" + }, + "pmac_PmacAsynIPPort": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name", + "title": "Name", + "type": "string" + }, + "IP": { + "default": null, + "description": "IP address of pmac", + "title": "Ip", + "type": "string" + }, + "PORT": { + "default": 1025, + "description": "TCP port for connection", + "title": "Port", + "type": "integer" + }, + "type": { + "const": "pmac.PmacAsynIPPort", + "default": "pmac.PmacAsynIPPort", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_PmacAsynIPPort", + "type": "object" + }, + "pmac_PmacAsynSSHPort": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name", + "title": "Name", + "type": "string" + }, + "IP": { + "default": null, + "description": "IP address of Power pmac", + "title": "Ip", + "type": "string" + }, + "USERNAME": { + "default": "root", + "description": "Username for login", + "title": "Username", + "type": "string" + }, + "PASSWORD": { + "default": "deltatau", + "description": "Password for login", + "title": "Password", + "type": "string" + }, + "PRIORITY": { + "default": 0, + "description": "Priority of the port", + "title": "Priority", + "type": "integer" + }, + "NOAUTOCONNECT": { + "default": 0, + "description": "Disables autoconnect if set to 1", + "title": "Noautoconnect", + "type": "integer" + }, + "NOEOS": { + "default": 0, + "description": "No EOS used if set to 1", + "title": "Noeos", + "type": "integer" + }, + "type": { + "const": "pmac.PmacAsynSSHPort", + "default": "pmac.PmacAsynSSHPort", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_PmacAsynSSHPort", + "type": "object" + }, + "pmac_autohome": { + "additionalProperties": false, + "properties": { + "Controller": { + "default": null, + "description": "the PMAC Controller", + "title": "Controller", + "type": "string" + }, + "PLC": { + "default": null, + "description": "PLC number of the auto home PLC", + "title": "Plc", + "type": "integer" + }, + "P": { + "default": null, + "description": "Prefix for auto home PVs", + "title": "P", + "type": "string" + }, + "GRP1": { + "default": "All", + "description": "name of the 'ALL' group of auto home axes", + "title": "Grp1", + "type": "string" + }, + "GRP2": { + "default": "", + "description": "name of the second group of auto home axes", + "title": "Grp2", + "type": "string" + }, + "GRP3": { + "default": "", + "description": "name of the third group of auto home axes", + "title": "Grp3", + "type": "string" + }, + "GRP4": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp4", + "type": "string" + }, + "GRP5": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp5", + "type": "string" + }, + "GRP6": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp6", + "type": "string" + }, + "GRP7": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp7", + "type": "string" + }, + "GRP8": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp8", + "type": "string" + }, + "GRP9": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp9", + "type": "string" + }, + "type": { + "const": "pmac.autohome", + "default": "pmac.autohome", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_autohome", + "type": "object" + }, + "pmac_pmacDisableLimitsCheck": { + "additionalProperties": false, + "properties": { + "Controller": { + "default": null, + "description": "Geobrick on which to disable limits", + "title": "Controller", + "type": "string" + }, + "Axis": { + "default": null, + "description": "Axis to have limits disabled", + "title": "Axis", + "type": "integer" + }, + "type": { + "const": "pmac.pmacDisableLimitsCheck", + "default": "pmac.pmacDisableLimitsCheck", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_pmacDisableLimitsCheck", + "type": "object" + } + }, + "additionalProperties": false, "properties": { "ioc_name": { - "type": "string", - "description": "Name of IOC instance" + "description": "Name of IOC instance", + "title": "Ioc Name", + "type": "string" }, "description": { - "type": "string", - "description": "Description of what the IOC does" + "description": "Description of what the IOC does", + "title": "Description", + "type": "string" + }, + "generic_ioc_image": { + "description": "The generic IOC container image registry URL", + "title": "Generic Ioc Image", + "type": "string" }, "entities": { - "type": "array", + "default": [], + "description": "List of entities this IOC instantiates", "items": { "anyOf": [ { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name", - "vscode_ibek_plugin_type": "type_id" - }, - "IP": { - "type": "string", - "description": "IP address of Power pmac" - }, - "USERNAME": { - "type": "string", - "description": "Username for login", - "default": "root" - }, - "PASSWORD": { - "type": "string", - "description": "Password for login", - "default": "deltatau" - }, - "PRIORITY": { - "type": "integer", - "description": "Priority of the port", - "default": 0 - }, - "NOAUTOCONNECT": { - "type": "integer", - "description": "Disables autoconnect if set to 1", - "default": 0 - }, - "NOEOS": { - "type": "integer", - "description": "No EOS used if set to 1", - "default": 0 - }, - "type": { - "type": "string", - "const": "pmac.PmacAsynSSHPort", - "default": "pmac.PmacAsynSSHPort" - } - }, - "required": [ - "name", - "IP" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_PmacAsynSSHPort" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name", - "vscode_ibek_plugin_type": "type_id" - }, - "IP": { - "type": "string", - "description": "IP address of pmac" - }, - "PORT": { - "type": "integer", - "description": "TCP port for connection", - "default": 1025 - }, - "type": { - "type": "string", - "const": "pmac.PmacAsynIPPort", - "default": "pmac.PmacAsynIPPort" - } - }, - "required": [ - "name", - "IP" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_PmacAsynIPPort" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Name to use for the geobrick's asyn port", - "vscode_ibek_plugin_type": "type_id" - }, - "PORT": { - "type": "string", - "description": "Asyn port name for PmacAsynIPPort to connect to", - "vscode_ibek_plugin_type": "type_object" - }, - "P": { - "type": "string", - "description": "PV Prefix for all pmac db templates" - }, - "numAxes": { - "type": "integer", - "description": "number of axes to initialize for the controller", - "default": 8 - }, - "idlePoll": { - "type": "integer", - "description": "Idle Poll Period in ms", - "default": 500 - }, - "movingPoll": { - "type": "integer", - "description": "Moving Poll Period in ms", - "default": 100 - }, - "TIMEOUT": { - "type": "integer", - "description": "timeout in seconds for asyn", - "default": 4 - }, - "FEEDRATE": { - "type": "integer", - "description": "feedrate below which we go into error", - "default": 100 - }, - "CSG0": { - "type": "string", - "description": "Name for Coordinate System Group 0", - "default": "" - }, - "CSG1": { - "type": "string", - "description": "Name for Coordinate System Group 1", - "default": "" - }, - "CSG2": { - "type": "string", - "description": "Name for Coordinate System Group 2", - "default": "" - }, - "CSG3": { - "type": "string", - "description": "Name for Coordinate System Group 3", - "default": "" - }, - "CSG4": { - "type": "string", - "description": "Name for Coordinate System Group 3", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.Geobrick", - "default": "pmac.Geobrick" - } - }, - "required": [ - "name", - "PORT", - "P" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_Geobrick" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Object name and gui association name" - }, - "Controller": { - "type": "string", - "description": "PMAC Controller to attach to", - "vscode_ibek_plugin_type": "type_object" - }, - "axis": { - "type": "integer", - "description": "which axis number this motor drives" - }, - "P": { - "type": "string", - "description": "PV prefix name for this motor" - }, - "M": { - "type": "string", - "description": "PV motor name for this motor" - }, - "DESC": { - "type": "string", - "description": "Description, displayed on EDM screen", - "default": "" - }, - "MRES": { - "type": "number", - "description": "Motor Step Size (EGU)", - "default": 0.0001 - }, - "VELO": { - "type": "number", - "description": "axis Velocity (EGU/s)", - "default": 1.0 - }, - "PREC": { - "type": "integer", - "description": "Display Precision", - "default": 3 - }, - "EGU": { - "type": "string", - "description": "Engineering Units", - "default": "mm" - }, - "TWV": { - "type": "number", - "description": "Tweak Step Size (EGU)", - "default": 1.0 - }, - "DTYP": { - "type": "string", - "description": "Datatype of record", - "default": "asynMotor" - }, - "DIR": { - "type": "integer", - "description": "User direction", - "default": 0 - }, - "VBAS": { - "type": "number", - "description": "Base Velocity (EGU/s)", - "default": 1.0 - }, - "VMAX": { - "type": "string", - "description": "Max Velocity (EGU/s)", - "default": "{{VELO}}" - }, - "ACCL": { - "type": "number", - "description": "Seconds to Velocity", - "default": 0.5 - }, - "BDST": { - "type": "number", - "description": "BL Distance (EGU)", - "default": 0.0 - }, - "BVEL": { - "type": "number", - "description": "BL Velocity(EGU/s)", - "default": 0.0 - }, - "BACC": { - "type": "number", - "description": "BL Seconds to Veloc", - "default": 0.0 - }, - "DHLM": { - "type": "number", - "description": "Dial High Limit", - "default": 10000.0 - }, - "DLLM": { - "type": "number", - "description": "Dial low limit", - "default": -10000.0 - }, - "HLM": { - "type": "number", - "description": "User High Limit", - "default": 0.0 - }, - "LLM": { - "type": "number", - "description": "User Low Limit", - "default": 0.0 - }, - "HLSV": { - "type": "string", - "description": "HW Lim, Violation Svr", - "default": "MAJOR" - }, - "INIT": { - "type": "string", - "description": "Startup commands", - "default": "" - }, - "SREV": { - "type": "integer", - "description": "Steps per Revolution", - "default": 1000 - }, - "RRES": { - "type": "number", - "description": "Readback Step Size (EGU", - "default": 0.0 - }, - "ERES": { - "type": "number", - "description": "Encoder Step Size (EGU)", - "default": 0.0 - }, - "JAR": { - "type": "number", - "description": "Jog Acceleration (EGU/s^2)", - "default": 0.0 - }, - "UEIP": { - "type": "integer", - "description": "Use Encoder If Present", - "default": 0 - }, - "URIP": { - "type": "integer", - "description": "Use RDBL If Present", - "default": 0 - }, - "RDBL": { - "type": "string", - "description": "Readback Location, set URIP =1 if you specify this", - "default": "0" - }, - "RLNK": { - "type": "string", - "description": "Readback output link", - "default": "" - }, - "RTRY": { - "type": "integer", - "description": "Max retry count", - "default": 0 - }, - "DLY": { - "type": "number", - "description": "Readback settle time (s)", - "default": 0.0 - }, - "OFF": { - "type": "number", - "description": "User Offset (EGU)", - "default": 0.0 - }, - "RDBD": { - "type": "number", - "description": "Retry Deadband (EGU)", - "default": 0.0 - }, - "FOFF": { - "type": "integer", - "description": "Freeze Offset, 0=variable, 1=frozen", - "default": 0 - }, - "ADEL": { - "type": "number", - "description": "Alarm monitor deadband (EGU)", - "default": 0.0 - }, - "NTM": { - "type": "integer", - "description": "New Target Monitor, only set to 0 for soft motors", - "default": 1 - }, - "FEHIGH": { - "type": "number", - "description": "HIGH limit for following error", - "default": 0.0 - }, - "FEHIHI": { - "type": "number", - "description": "HIHI limit for following error", - "default": 0.0 - }, - "FEHHSV": { - "type": "string", - "description": "HIHI alarm severity for following error", - "default": "NO_ALARM" - }, - "FEHSV": { - "type": "string", - "description": "HIGH alarm severity for following error", - "default": "NO_ALARM" - }, - "SCALE": { - "type": "integer", - "default": 1 - }, - "HOMEVIS": { - "type": "integer", - "description": "If 1 then home is visible on the gui", - "default": 1 - }, - "HOMEVISSTR": { - "type": "string", - "default": "Use motor summary screen" - }, - "alh": { - "type": "string", - "description": "Set this to alh to add the motor to the alarm handler and send emails", - "default": "" - }, - "HOME": { - "type": "string", - "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", - "default": "{{P}}" - }, - "ALLOW_HOMED_SET": { - "type": "string", - "description": "Set to a blank to allow this axis to have its homed", - "default": "#" - }, - "RLINK": { - "type": "string", - "description": "not sure what this is", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.DlsPmacAsynMotor", - "default": "pmac.DlsPmacAsynMotor" - } - }, - "required": [ - "name", - "Controller", - "axis", - "P", - "M" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_DlsPmacAsynMotor" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Object name and gui association name" - }, - "CsController": { - "type": "string", - "description": "Coordinate system controller to attach to", - "vscode_ibek_plugin_type": "type_object" - }, - "axis": { - "type": "integer", - "description": "which axis number this motor drives" - }, - "P": { - "type": "string", - "description": "PV prefix name for this motor" - }, - "M": { - "type": "string", - "description": "PV motor name for this motor" - }, - "DESC": { - "type": "string", - "description": "Description, displayed on EDM screen", - "default": "" - }, - "MRES": { - "type": "number", - "description": "Motor Step Size (EGU)", - "default": 0.0001 - }, - "VELO": { - "type": "number", - "description": "axis Velocity (EGU/s)", - "default": 1.0 - }, - "PREC": { - "type": "integer", - "description": "Display Precision", - "default": 3 - }, - "EGU": { - "type": "string", - "description": "Engineering Units", - "default": "mm" - }, - "TWV": { - "type": "number", - "description": "Tweak Step Size (EGU)", - "default": 1.0 - }, - "DTYP": { - "type": "string", - "description": "Datatype of record", - "default": "asynMotor" - }, - "DIR": { - "type": "integer", - "description": "User direction", - "default": 0 - }, - "VBAS": { - "type": "number", - "description": "Base Velocity (EGU/s)", - "default": 1.0 - }, - "VMAX": { - "type": "string", - "description": "Max Velocity (EGU/s)", - "default": "{{VELO}}" - }, - "ACCL": { - "type": "number", - "description": "Seconds to Velocity", - "default": 0.5 - }, - "BDST": { - "type": "number", - "description": "BL Distance (EGU)", - "default": 0.0 - }, - "BVEL": { - "type": "number", - "description": "BL Velocity(EGU/s)", - "default": 0.0 - }, - "BACC": { - "type": "number", - "description": "BL Seconds to Veloc", - "default": 0.0 - }, - "DHLM": { - "type": "number", - "description": "Dial High Limit", - "default": 10000.0 - }, - "DLLM": { - "type": "number", - "description": "Dial low limit", - "default": -10000.0 - }, - "HLM": { - "type": "number", - "description": "User High Limit", - "default": 0.0 - }, - "LLM": { - "type": "number", - "description": "User Low Limit", - "default": 0.0 - }, - "HLSV": { - "type": "string", - "description": "HW Lim, Violation Svr", - "default": "MAJOR" - }, - "INIT": { - "type": "string", - "description": "Startup commands", - "default": "" - }, - "SREV": { - "type": "integer", - "description": "Steps per Revolution", - "default": 1000 - }, - "RRES": { - "type": "number", - "description": "Readback Step Size (EGU", - "default": 0.0 - }, - "ERES": { - "type": "number", - "description": "Encoder Step Size (EGU)", - "default": 0.0 - }, - "JAR": { - "type": "number", - "description": "Jog Acceleration (EGU/s^2)", - "default": 0.0 - }, - "UEIP": { - "type": "integer", - "description": "Use Encoder If Present", - "default": 0 - }, - "URIP": { - "type": "integer", - "description": "Use RDBL If Present", - "default": 0 - }, - "RDBL": { - "type": "string", - "description": "Readback Location, set URIP =1 if you specify this", - "default": "0" - }, - "RLNK": { - "type": "string", - "description": "Readback output link", - "default": "" - }, - "RTRY": { - "type": "integer", - "description": "Max retry count", - "default": 0 - }, - "DLY": { - "type": "number", - "description": "Readback settle time (s)", - "default": 0.0 - }, - "OFF": { - "type": "number", - "description": "User Offset (EGU)", - "default": 0.0 - }, - "RDBD": { - "type": "number", - "description": "Retry Deadband (EGU)", - "default": 0.0 - }, - "FOFF": { - "type": "integer", - "description": "Freeze Offset, 0=variable, 1=frozen", - "default": 0 - }, - "ADEL": { - "type": "number", - "description": "Alarm monitor deadband (EGU)", - "default": 0.0 - }, - "NTM": { - "type": "integer", - "description": "New Target Monitor, only set to 0 for soft motors", - "default": 1 - }, - "FEHEIGH": { - "type": "number", - "description": "HIGH limit for following error", - "default": 0.0 - }, - "FEHIHI": { - "type": "number", - "description": "HIHI limit for following error", - "default": 0.0 - }, - "FEHHSV": { - "type": "string", - "description": "HIHI alarm severity for following error", - "default": "NO_ALARM" - }, - "FEHSV": { - "type": "string", - "description": "HIGH alarm severity for following error", - "default": "NO_ALARM" - }, - "SCALE": { - "type": "integer", - "default": 1 - }, - "HOMEVIS": { - "type": "integer", - "description": "If 1 then home is visible on the gui", - "default": 1 - }, - "HOMEVISSTR": { - "type": "string", - "default": "Use motor summary screen" - }, - "alh": { - "type": "string", - "description": "Set this to alh to add the motor to the alarm handler and send emails", - "default": "" - }, - "HOME": { - "type": "string", - "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", - "default": "{{P}}" - }, - "ALLOW_HOMED_SET": { - "type": "string", - "description": "Set to a blank to allow this axis to have its homed", - "default": "#" - }, - "type": { - "type": "string", - "const": "pmac.DlsCsPmacAsynMotor", - "default": "pmac.DlsCsPmacAsynMotor" - } - }, - "required": [ - "name", - "CsController", - "axis", - "P", - "M" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "Controller": { - "type": "string", - "description": "Geobrick on which to disable limits", - "vscode_ibek_plugin_type": "type_object" - }, - "Axis": { - "type": "integer", - "description": "Axis to have limits disabled" - }, - "type": { - "type": "string", - "const": "pmac.pmacDisableLimitsCheck", - "default": "pmac.pmacDisableLimitsCheck" - } - }, - "required": [ - "Controller", - "Axis" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "Controller": { - "type": "string", - "description": "the PMAC Controller", - "vscode_ibek_plugin_type": "type_object" - }, - "PLC": { - "type": "integer", - "description": "PLC number of the auto home PLC" - }, - "P": { - "type": "string", - "description": "Prefix for auto home PVs" - }, - "GRP1": { - "type": "string", - "description": "name of the 'ALL' group of auto home axes", - "default": "All" - }, - "GRP2": { - "type": "string", - "description": "name of the second group of auto home axes", - "default": "" - }, - "GRP3": { - "type": "string", - "description": "name of the third group of auto home axes", - "default": "" - }, - "GRP4": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP5": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP6": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP7": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP8": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "GRP9": { - "type": "string", - "description": "name of the fourth group of auto home axes", - "default": "" - }, - "type": { - "type": "string", - "const": "pmac.autohome", - "default": "pmac.autohome" - } - }, - "required": [ - "Controller", - "PLC", - "P" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_autohome" }, { - "type": "object", - "properties": { - "entity_enabled": { - "type": "boolean", - "default": true - }, - "name": { - "type": "string", - "description": "Asyn port name for this object", - "vscode_ibek_plugin_type": "type_id" - }, - "Controller": { - "type": "string", - "description": "the PMAC Controller", - "vscode_ibek_plugin_type": "type_object" - }, - "CS": { - "type": "integer", - "description": "Coordinate system number" - }, - "NAxes": { - "type": "integer", - "description": "number of CS axes", - "default": 9 - }, - "Program": { - "type": "integer", - "description": "PROG number for CS motion", - "default": 10 - }, - "type": { - "type": "string", - "const": "pmac.CS", - "default": "pmac.CS" - } - }, - "required": [ - "name", - "Controller", - "CS" - ], - "additionalProperties": false + "$ref": "#/$defs/pmac_CS" } ] }, - "description": "List of entities this IOC instantiates" - }, - "generic_ioc_image": { - "type": "string", - "description": "The generic IOC container image registry URL" + "title": "Entities", + "type": "array" } }, "required": [ "ioc_name", "description", - "entities", "generic_ioc_image" ], - "additionalProperties": false, - "$schema": "http://json-schema.org/draft-07/schema#" + "title": "NewIOC", + "type": "object" } \ No newline at end of file diff --git a/tests/samples/schemas/pmac.ibek.support.schema.json b/tests/samples/schemas/pmac.ibek.support.schema.json new file mode 100644 index 000000000..e87110d41 --- /dev/null +++ b/tests/samples/schemas/pmac.ibek.support.schema.json @@ -0,0 +1,999 @@ +{ + "$defs": { + "Entity": { + "additionalProperties": false, + "description": "\n A baseclass for all generated Entity classes. Provides the\n deserialize entry point.\n ", + "properties": { + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + } + }, + "title": "Entity", + "type": "object" + }, + "pmac_CS": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name for this object", + "title": "Name", + "type": "string" + }, + "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], + "default": null, + "description": "the PMAC Controller" + }, + "CS": { + "default": null, + "description": "Coordinate system number", + "title": "Cs", + "type": "integer" + }, + "NAxes": { + "default": 9, + "description": "number of CS axes", + "title": "Naxes", + "type": "integer" + }, + "Program": { + "default": 10, + "description": "PROG number for CS motion", + "title": "Program", + "type": "integer" + }, + "type": { + "const": "pmac.CS", + "default": "pmac.CS", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_CS", + "type": "object" + }, + "pmac_DlsCsPmacAsynMotor": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Object name and gui association name", + "title": "Name", + "type": "string" + }, + "CsController": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], + "default": null, + "description": "Coordinate system controller to attach to" + }, + "axis": { + "default": null, + "description": "which axis number this motor drives", + "title": "Axis", + "type": "integer" + }, + "P": { + "default": null, + "description": "PV prefix name for this motor", + "title": "P", + "type": "string" + }, + "M": { + "default": null, + "description": "PV motor name for this motor", + "title": "M", + "type": "string" + }, + "DESC": { + "default": "", + "description": "Description, displayed on EDM screen", + "title": "Desc", + "type": "string" + }, + "MRES": { + "default": 0.0001, + "description": "Motor Step Size (EGU)", + "title": "Mres", + "type": "number" + }, + "VELO": { + "default": 1.0, + "description": "axis Velocity (EGU/s)", + "title": "Velo", + "type": "number" + }, + "PREC": { + "default": 3, + "description": "Display Precision", + "title": "Prec", + "type": "integer" + }, + "EGU": { + "default": "mm", + "description": "Engineering Units", + "title": "Egu", + "type": "string" + }, + "TWV": { + "default": 1.0, + "description": "Tweak Step Size (EGU)", + "title": "Twv", + "type": "number" + }, + "DTYP": { + "default": "asynMotor", + "description": "Datatype of record", + "title": "Dtyp", + "type": "string" + }, + "DIR": { + "default": 0, + "description": "User direction", + "title": "Dir", + "type": "integer" + }, + "VBAS": { + "default": 1.0, + "description": "Base Velocity (EGU/s)", + "title": "Vbas", + "type": "number" + }, + "VMAX": { + "default": "{{VELO}}", + "description": "Max Velocity (EGU/s)", + "title": "Vmax", + "type": "string" + }, + "ACCL": { + "default": 0.5, + "description": "Seconds to Velocity", + "title": "Accl", + "type": "number" + }, + "BDST": { + "default": 0.0, + "description": "BL Distance (EGU)", + "title": "Bdst", + "type": "number" + }, + "BVEL": { + "default": 0.0, + "description": "BL Velocity(EGU/s)", + "title": "Bvel", + "type": "number" + }, + "BACC": { + "default": 0.0, + "description": "BL Seconds to Veloc", + "title": "Bacc", + "type": "number" + }, + "DHLM": { + "default": 10000.0, + "description": "Dial High Limit", + "title": "Dhlm", + "type": "number" + }, + "DLLM": { + "default": -10000.0, + "description": "Dial low limit", + "title": "Dllm", + "type": "number" + }, + "HLM": { + "default": 0.0, + "description": "User High Limit", + "title": "Hlm", + "type": "number" + }, + "LLM": { + "default": 0.0, + "description": "User Low Limit", + "title": "Llm", + "type": "number" + }, + "HLSV": { + "default": "MAJOR", + "description": "HW Lim, Violation Svr", + "title": "Hlsv", + "type": "string" + }, + "INIT": { + "default": "", + "description": "Startup commands", + "title": "Init", + "type": "string" + }, + "SREV": { + "default": 1000, + "description": "Steps per Revolution", + "title": "Srev", + "type": "integer" + }, + "RRES": { + "default": 0.0, + "description": "Readback Step Size (EGU", + "title": "Rres", + "type": "number" + }, + "ERES": { + "default": 0.0, + "description": "Encoder Step Size (EGU)", + "title": "Eres", + "type": "number" + }, + "JAR": { + "default": 0.0, + "description": "Jog Acceleration (EGU/s^2)", + "title": "Jar", + "type": "number" + }, + "UEIP": { + "default": 0, + "description": "Use Encoder If Present", + "title": "Ueip", + "type": "integer" + }, + "URIP": { + "default": 0, + "description": "Use RDBL If Present", + "title": "Urip", + "type": "integer" + }, + "RDBL": { + "default": "0", + "description": "Readback Location, set URIP =1 if you specify this", + "title": "Rdbl", + "type": "string" + }, + "RLNK": { + "default": "", + "description": "Readback output link", + "title": "Rlnk", + "type": "string" + }, + "RTRY": { + "default": 0, + "description": "Max retry count", + "title": "Rtry", + "type": "integer" + }, + "DLY": { + "default": 0.0, + "description": "Readback settle time (s)", + "title": "Dly", + "type": "number" + }, + "OFF": { + "default": 0.0, + "description": "User Offset (EGU)", + "title": "Off", + "type": "number" + }, + "RDBD": { + "default": 0.0, + "description": "Retry Deadband (EGU)", + "title": "Rdbd", + "type": "number" + }, + "FOFF": { + "default": 0, + "description": "Freeze Offset, 0=variable, 1=frozen", + "title": "Foff", + "type": "integer" + }, + "ADEL": { + "default": 0.0, + "description": "Alarm monitor deadband (EGU)", + "title": "Adel", + "type": "number" + }, + "NTM": { + "default": 1, + "description": "New Target Monitor, only set to 0 for soft motors", + "title": "Ntm", + "type": "integer" + }, + "FEHEIGH": { + "default": 0.0, + "description": "HIGH limit for following error", + "title": "Feheigh", + "type": "number" + }, + "FEHIHI": { + "default": 0.0, + "description": "HIHI limit for following error", + "title": "Fehihi", + "type": "number" + }, + "FEHHSV": { + "default": "NO_ALARM", + "description": "HIHI alarm severity for following error", + "title": "Fehhsv", + "type": "string" + }, + "FEHSV": { + "default": "NO_ALARM", + "description": "HIGH alarm severity for following error", + "title": "Fehsv", + "type": "string" + }, + "SCALE": { + "default": 1, + "description": "", + "title": "Scale", + "type": "integer" + }, + "HOMEVIS": { + "default": 1, + "description": "If 1 then home is visible on the gui", + "title": "Homevis", + "type": "integer" + }, + "HOMEVISSTR": { + "default": "Use motor summary screen", + "description": "", + "title": "Homevisstr", + "type": "string" + }, + "alh": { + "default": "", + "description": "Set this to alh to add the motor to the alarm handler and send emails", + "title": "Alh", + "type": "string" + }, + "HOME": { + "default": "{{P}}", + "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", + "title": "Home", + "type": "string" + }, + "ALLOW_HOMED_SET": { + "default": "#", + "description": "Set to a blank to allow this axis to have its homed", + "title": "Allow Homed Set", + "type": "string" + }, + "type": { + "const": "pmac.DlsCsPmacAsynMotor", + "default": "pmac.DlsCsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_DlsCsPmacAsynMotor", + "type": "object" + }, + "pmac_DlsPmacAsynMotor": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Object name and gui association name", + "title": "Name", + "type": "string" + }, + "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], + "default": null, + "description": "PMAC Controller to attach to" + }, + "axis": { + "default": null, + "description": "which axis number this motor drives", + "title": "Axis", + "type": "integer" + }, + "P": { + "default": null, + "description": "PV prefix name for this motor", + "title": "P", + "type": "string" + }, + "M": { + "default": null, + "description": "PV motor name for this motor", + "title": "M", + "type": "string" + }, + "DESC": { + "default": "", + "description": "Description, displayed on EDM screen", + "title": "Desc", + "type": "string" + }, + "MRES": { + "default": 0.0001, + "description": "Motor Step Size (EGU)", + "title": "Mres", + "type": "number" + }, + "VELO": { + "default": 1.0, + "description": "axis Velocity (EGU/s)", + "title": "Velo", + "type": "number" + }, + "PREC": { + "default": 3, + "description": "Display Precision", + "title": "Prec", + "type": "integer" + }, + "EGU": { + "default": "mm", + "description": "Engineering Units", + "title": "Egu", + "type": "string" + }, + "TWV": { + "default": 1.0, + "description": "Tweak Step Size (EGU)", + "title": "Twv", + "type": "number" + }, + "DTYP": { + "default": "asynMotor", + "description": "Datatype of record", + "title": "Dtyp", + "type": "string" + }, + "DIR": { + "default": 0, + "description": "User direction", + "title": "Dir", + "type": "integer" + }, + "VBAS": { + "default": 1.0, + "description": "Base Velocity (EGU/s)", + "title": "Vbas", + "type": "number" + }, + "VMAX": { + "default": "{{VELO}}", + "description": "Max Velocity (EGU/s)", + "title": "Vmax", + "type": "string" + }, + "ACCL": { + "default": 0.5, + "description": "Seconds to Velocity", + "title": "Accl", + "type": "number" + }, + "BDST": { + "default": 0.0, + "description": "BL Distance (EGU)", + "title": "Bdst", + "type": "number" + }, + "BVEL": { + "default": 0.0, + "description": "BL Velocity(EGU/s)", + "title": "Bvel", + "type": "number" + }, + "BACC": { + "default": 0.0, + "description": "BL Seconds to Veloc", + "title": "Bacc", + "type": "number" + }, + "DHLM": { + "default": 10000.0, + "description": "Dial High Limit", + "title": "Dhlm", + "type": "number" + }, + "DLLM": { + "default": -10000.0, + "description": "Dial low limit", + "title": "Dllm", + "type": "number" + }, + "HLM": { + "default": 0.0, + "description": "User High Limit", + "title": "Hlm", + "type": "number" + }, + "LLM": { + "default": 0.0, + "description": "User Low Limit", + "title": "Llm", + "type": "number" + }, + "HLSV": { + "default": "MAJOR", + "description": "HW Lim, Violation Svr", + "title": "Hlsv", + "type": "string" + }, + "INIT": { + "default": "", + "description": "Startup commands", + "title": "Init", + "type": "string" + }, + "SREV": { + "default": 1000, + "description": "Steps per Revolution", + "title": "Srev", + "type": "integer" + }, + "RRES": { + "default": 0.0, + "description": "Readback Step Size (EGU", + "title": "Rres", + "type": "number" + }, + "ERES": { + "default": 0.0, + "description": "Encoder Step Size (EGU)", + "title": "Eres", + "type": "number" + }, + "JAR": { + "default": 0.0, + "description": "Jog Acceleration (EGU/s^2)", + "title": "Jar", + "type": "number" + }, + "UEIP": { + "default": 0, + "description": "Use Encoder If Present", + "title": "Ueip", + "type": "integer" + }, + "URIP": { + "default": 0, + "description": "Use RDBL If Present", + "title": "Urip", + "type": "integer" + }, + "RDBL": { + "default": "0", + "description": "Readback Location, set URIP =1 if you specify this", + "title": "Rdbl", + "type": "string" + }, + "RLNK": { + "default": "", + "description": "Readback output link", + "title": "Rlnk", + "type": "string" + }, + "RTRY": { + "default": 0, + "description": "Max retry count", + "title": "Rtry", + "type": "integer" + }, + "DLY": { + "default": 0.0, + "description": "Readback settle time (s)", + "title": "Dly", + "type": "number" + }, + "OFF": { + "default": 0.0, + "description": "User Offset (EGU)", + "title": "Off", + "type": "number" + }, + "RDBD": { + "default": 0.0, + "description": "Retry Deadband (EGU)", + "title": "Rdbd", + "type": "number" + }, + "FOFF": { + "default": 0, + "description": "Freeze Offset, 0=variable, 1=frozen", + "title": "Foff", + "type": "integer" + }, + "ADEL": { + "default": 0.0, + "description": "Alarm monitor deadband (EGU)", + "title": "Adel", + "type": "number" + }, + "NTM": { + "default": 1, + "description": "New Target Monitor, only set to 0 for soft motors", + "title": "Ntm", + "type": "integer" + }, + "FEHIGH": { + "default": 0.0, + "description": "HIGH limit for following error", + "title": "Fehigh", + "type": "number" + }, + "FEHIHI": { + "default": 0.0, + "description": "HIHI limit for following error", + "title": "Fehihi", + "type": "number" + }, + "FEHHSV": { + "default": "NO_ALARM", + "description": "HIHI alarm severity for following error", + "title": "Fehhsv", + "type": "string" + }, + "FEHSV": { + "default": "NO_ALARM", + "description": "HIGH alarm severity for following error", + "title": "Fehsv", + "type": "string" + }, + "SCALE": { + "default": 1, + "description": "", + "title": "Scale", + "type": "integer" + }, + "HOMEVIS": { + "default": 1, + "description": "If 1 then home is visible on the gui", + "title": "Homevis", + "type": "integer" + }, + "HOMEVISSTR": { + "default": "Use motor summary screen", + "description": "", + "title": "Homevisstr", + "type": "string" + }, + "alh": { + "default": "", + "description": "Set this to alh to add the motor to the alarm handler and send emails", + "title": "Alh", + "type": "string" + }, + "HOME": { + "default": "{{P}}", + "description": "Prefix for autohome instance. Defaults to $(P) If unspecified", + "title": "Home", + "type": "string" + }, + "ALLOW_HOMED_SET": { + "default": "#", + "description": "Set to a blank to allow this axis to have its homed", + "title": "Allow Homed Set", + "type": "string" + }, + "RLINK": { + "default": "", + "description": "not sure what this is", + "title": "Rlink", + "type": "string" + }, + "type": { + "const": "pmac.DlsPmacAsynMotor", + "default": "pmac.DlsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_DlsPmacAsynMotor", + "type": "object" + }, + "pmac_Geobrick": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Name to use for the geobrick's asyn port", + "title": "Name", + "type": "string" + }, + "PORT": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], + "default": null, + "description": "Asyn port name for PmacAsynIPPort to connect to" + }, + "P": { + "default": null, + "description": "PV Prefix for all pmac db templates", + "title": "P", + "type": "string" + }, + "numAxes": { + "default": 8, + "description": "number of axes to initialize for the controller", + "title": "Numaxes", + "type": "integer" + }, + "idlePoll": { + "default": 500, + "description": "Idle Poll Period in ms", + "title": "Idlepoll", + "type": "integer" + }, + "movingPoll": { + "default": 100, + "description": "Moving Poll Period in ms", + "title": "Movingpoll", + "type": "integer" + }, + "TIMEOUT": { + "default": 4, + "description": "timeout in seconds for asyn", + "title": "Timeout", + "type": "integer" + }, + "FEEDRATE": { + "default": 100, + "description": "feedrate below which we go into error", + "title": "Feedrate", + "type": "integer" + }, + "CSG0": { + "default": "", + "description": "Name for Coordinate System Group 0", + "title": "Csg0", + "type": "string" + }, + "CSG1": { + "default": "", + "description": "Name for Coordinate System Group 1", + "title": "Csg1", + "type": "string" + }, + "CSG2": { + "default": "", + "description": "Name for Coordinate System Group 2", + "title": "Csg2", + "type": "string" + }, + "CSG3": { + "default": "", + "description": "Name for Coordinate System Group 3", + "title": "Csg3", + "type": "string" + }, + "CSG4": { + "default": "", + "description": "Name for Coordinate System Group 3", + "title": "Csg4", + "type": "string" + }, + "type": { + "const": "pmac.Geobrick", + "default": "pmac.Geobrick", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_Geobrick", + "type": "object" + }, + "pmac_PmacAsynIPPort": { + "additionalProperties": false, + "properties": { + "name": { + "default": null, + "description": "Asyn port name", + "title": "Name", + "type": "string" + }, + "IP": { + "default": null, + "description": "IP address of pmac", + "title": "Ip", + "type": "string" + }, + "PORT": { + "default": 1025, + "description": "TCP port for connection", + "title": "Port", + "type": "integer" + }, + "type": { + "const": "pmac.PmacAsynIPPort", + "default": "pmac.PmacAsynIPPort", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_PmacAsynIPPort", + "type": "object" + }, + "pmac_autohome": { + "additionalProperties": false, + "properties": { + "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], + "default": null, + "description": "the PMAC Controller" + }, + "PLC": { + "default": null, + "description": "PLC number of the auto home PLC", + "title": "Plc", + "type": "integer" + }, + "P": { + "default": null, + "description": "Prefix for auto home PVs", + "title": "P", + "type": "string" + }, + "GRP1": { + "default": "All", + "description": "name of the 'ALL' group of auto home axes", + "title": "Grp1", + "type": "string" + }, + "GRP2": { + "default": "", + "description": "name of the second group of auto home axes", + "title": "Grp2", + "type": "string" + }, + "GRP3": { + "default": "", + "description": "name of the third group of auto home axes", + "title": "Grp3", + "type": "string" + }, + "GRP4": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp4", + "type": "string" + }, + "GRP5": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp5", + "type": "string" + }, + "GRP6": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp6", + "type": "string" + }, + "GRP7": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp7", + "type": "string" + }, + "GRP8": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp8", + "type": "string" + }, + "GRP9": { + "default": "", + "description": "name of the fourth group of auto home axes", + "title": "Grp9", + "type": "string" + }, + "type": { + "const": "pmac.autohome", + "default": "pmac.autohome", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_autohome", + "type": "object" + }, + "pmac_pmacDisableLimitsCheck": { + "additionalProperties": false, + "properties": { + "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], + "default": null, + "description": "Geobrick on which to disable limits" + }, + "Axis": { + "default": null, + "description": "Axis to have limits disabled", + "title": "Axis", + "type": "integer" + }, + "type": { + "const": "pmac.pmacDisableLimitsCheck", + "default": "pmac.pmacDisableLimitsCheck", + "description": "The type of this entity", + "title": "Type" + } + }, + "title": "pmac_pmacDisableLimitsCheck", + "type": "object" + } + }, + "additionalProperties": false, + "properties": { + "ioc_name": { + "description": "Name of IOC instance", + "title": "Ioc Name", + "type": "string" + }, + "description": { + "description": "Description of what the IOC does", + "title": "Description", + "type": "string" + }, + "generic_ioc_image": { + "description": "The generic IOC container image registry URL", + "title": "Generic Ioc Image", + "type": "string" + }, + "entities": { + "default": [], + "description": "List of entities this IOC instantiates", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/pmac_PmacAsynIPPort" + }, + { + "$ref": "#/$defs/pmac_Geobrick" + }, + { + "$ref": "#/$defs/pmac_DlsPmacAsynMotor" + }, + { + "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" + }, + { + "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" + }, + { + "$ref": "#/$defs/pmac_autohome" + }, + { + "$ref": "#/$defs/pmac_CS" + } + ] + }, + "title": "Entities", + "type": "array" + } + }, + "required": [ + "ioc_name", + "description", + "generic_ioc_image" + ], + "title": "NewIOC", + "type": "object" +} \ No newline at end of file diff --git a/tests/samples/values_test/st.cmd b/tests/samples/values_test/st.cmd index e10ca6bc0..870df2af5 100644 --- a/tests/samples/values_test/st.cmd +++ b/tests/samples/values_test/st.cmd @@ -1,21 +1,10 @@ # EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek cd "/repos/epics/ioc" - -epicsEnvSet Vec0 192 - dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase -# ipacAddHy8002 "slot, interrupt_level" -# Create a new Hy8002 carrier. -# The resulting carrier handle (card id) is saved in an env variable. -ipacAddHy8002 "4, 2" -epicsEnvSet IPAC4 0 -ipacAddHy8002 "5, 2" -epicsEnvSet IPAC5 1 - dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/yaml/ADCore.ibek.support.yaml b/tests/samples/yaml/ADCore.ibek.support.yaml new file mode 100644 index 000000000..08cd5624f --- /dev/null +++ b/tests/samples/yaml/ADCore.ibek.support.yaml @@ -0,0 +1,182 @@ +# yaml-language-server: $schema=../schemas/ibek.defs.schema.json + +module: ADCore + +defs: + - name: NDRoi + description: Defines a ROI Plugin for an AreaDetector instance + args: + - type: id + name: PORT + description: Port for this plugin + + - type: object + name: NDARRAY_PORT + description: Port Name for input NDArray plugin + + - type: str + name: P + description: The PV prefix + + - type: str + name: R + description: The PV suffix + + - type: int + name: TIMEOUT + description: Timeout for ASYN communications + default: 1 + + - type: int + name: ADDR + description: ASYN Address this plugin + default: 0 + + - type: int + name: NDARRAY_ADDR + description: ASYN Address for input NDArray plugin + default: 0 + + - type: bool + name: ENABLED + description: Enable/Disable this plugin at startup + default: true + + - type: str + name: SCANRATE + description: Epics record scan rate + default: I/O Intr + + - type: int + name: QUEUE + description: Number of NDArray buffers to be created for plugin callbacks + default: 2 + + - type: bool + name: BLOCK + description: blocking callbacks? + default: false + + - type: int + name: MAX_THREADS + description: Maximum number of threads to use + default: 1 + + script: + - type: function + name: NDROIConfigure + args: + AsynPortName: "{{ PORT }}" + QueueSize: "{{ QUEUE }}" + BlockingCallbacks: "{{ BLOCK | int }}" + NDArrayPort: "{{ NDARRAY_PORT }}" + NDArrayAddr: "{{ NDARRAY_ADDR }}" + MaxBuffers: 0 + MaxMemory: 0 + Priority: 0 + StackSize: 0 + MaxThreads: "{{ MAX_THREADS }}" + + databases: + - file: NDROI.template + args: + { + P, + R: "{{ R }}:{{ REPEAT }}", + PORT, + TIMEOUT, + ADDR, + NDARRAY_PORT, + NDARRAY_ADDR, + ENABLED: "{{ ENABLED | int }}", + SCANRATE, + } + + - name: NDStats + description: Defines a Stats Plugin for an AreaDetector instance + args: + - type: id + name: PORT + description: Port for this plugin + + - type: str + name: NDARRAY_PORT + description: Port Name for input NDArray plugin + + - type: str + name: P + description: The PV prefix + + - type: str + name: R + description: The PV suffix + + - type: int + name: TIMEOUT + description: Timeout for ASYN communications + default: 1 + + - type: int + name: ADDR + description: ASYN Address this plugin + default: 0 + + - type: int + name: NDARRAY_ADDR + description: ASYN Address for input NDArray plugin + default: 0 + + - type: bool + name: ENABLED + description: Enable/Disable this plugin at startup + default: true + + - type: str + name: SCANRATE + description: Epics record scan rate + default: I/O Intr + + - type: int + name: QUEUE + description: Number of NDArray buffers to be created for plugin callbacks + default: 2 + + - type: bool + name: BLOCK + description: blocking callbacks? + default: false + + - type: int + name: MAX_THREADS + description: Maximum number of threads to use + default: 1 + + script: + - type: function + name: NDStatsConfigure + args: + { + A, + B, + C: "{{ xxx }}", + D, + E: "{{ yyy }}", + G: "{{ yyy }}", + F: "{{ zzz }}", + } + + databases: + - file: NDStats.template + args: + { + P, + R, + PORT, + TIMEOUT, + ADDR, + NDARRAY_PORT, + NDARRAY_ADDR, + ENABLED: "{{ ENABLED | int }}", + SCANRATE, + } + define_args: | diff --git a/tests/samples/yaml/bl45p-mo-ioc-02.ibek.ioc.yaml b/tests/samples/yaml/bl45p-mo-ioc-02.ibek.ioc.yaml index 174e436f3..d3e4bf382 100644 --- a/tests/samples/yaml/bl45p-mo-ioc-02.ibek.ioc.yaml +++ b/tests/samples/yaml/bl45p-mo-ioc-02.ibek.ioc.yaml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=../schemas/all.ibek.support.schema.json +# yaml-language-server: $schema=../schemas/pmac.ibek.support.schema.json ioc_name: bl45p-mo-ioc-02 description: an example motion ioc for ibek testing generic_ioc_image: ghcr.io/epics-containers/ioc-pmac:main.run diff --git a/tests/test_cli.py b/tests/test_cli.py index 50dc5e47d..c96e25760 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -9,7 +9,7 @@ from ibek import __version__ from ibek.__main__ import cli -from ibek.ioc import clear_entity_classes, make_entity_classes +from ibek.ioc import clear_entity_model_ids, make_entity_models from ibek.support import Support runner = CliRunner() @@ -41,7 +41,7 @@ def test_builder_schema(tmp_path: Path, samples: Path): def test_pmac_schema(tmp_path: Path, samples: Path, ibek_defs: Path): """generate schema from the pmac support module definition yaml""" - clear_entity_classes() + clear_entity_model_ids() schema_path = tmp_path / "pmac.ibek.entities.schema.json" yaml_path = ibek_defs / "pmac" / "pmac.ibek.support.yaml" @@ -57,7 +57,7 @@ def test_pmac_schema(tmp_path: Path, samples: Path, ibek_defs: Path): def test_asyn_schema(tmp_path: Path, samples: Path, ibek_defs: Path): """generate schema from the asyn support module definition yaml""" - clear_entity_classes() + clear_entity_model_ids() schema_path = tmp_path / "asyn.ibek.entities.schema.json" yaml_path = ibek_defs / "asyn" / "asyn.ibek.support.yaml" @@ -72,7 +72,7 @@ def test_asyn_schema(tmp_path: Path, samples: Path, ibek_defs: Path): def test_container_schema(tmp_path: Path, samples: Path, ibek_defs: Path): - clear_entity_classes() + clear_entity_model_ids() """generate schema for a container with two support modules""" schema_combined = tmp_path / "container.ibek.entities.schema.json" @@ -93,7 +93,7 @@ def test_build_startup_output_path(tmp_path: Path, samples: Path, ibek_defs: Pat build an ioc startup script and ensure output directory gets generated if it doesn't pre-exist """ - clear_entity_classes() + clear_entity_model_ids() entity_file = samples / "yaml" / "bl45p-mo-ioc-02.ibek.ioc.yaml" definition_file = ibek_defs / "pmac" / "pmac.ibek.support.yaml" out_file = tmp_path / "new_dir" / "st.cmd" @@ -120,7 +120,7 @@ def test_build_startup_single(tmp_path: Path, samples: Path, ibek_defs: Path): build an ioc startup script from an IOC instance entity file and a single support module definition file """ - clear_entity_classes() + clear_entity_model_ids() entity_file = samples / "yaml" / "bl45p-mo-ioc-02.ibek.ioc.yaml" definition_file = ibek_defs / "pmac" / "pmac.ibek.support.yaml" out_file = tmp_path / "st.cmd" @@ -147,7 +147,7 @@ def test_build_startup_multiple(tmp_path: Path, samples: Path, ibek_defs: Path): build an ioc startup script from an IOC instance entity file and multiple support module definition files """ - clear_entity_classes() + clear_entity_model_ids() entity_file = samples / "yaml" / "bl45p-mo-ioc-03.ibek.ioc.yaml" definition_file1 = ibek_defs / "asyn" / "asyn.ibek.support.yaml" definition_file2 = ibek_defs / "pmac" / "pmac.ibek.support.yaml" @@ -179,7 +179,7 @@ def test_build_startup_env_vars_and_post_ioc_init( support module definition files which include environment variables and post iocInit() entries """ - clear_entity_classes() + clear_entity_model_ids() entity_file = samples / "yaml" / "bl45p-mo-ioc-04.ibek.ioc.yaml" definition_file1 = ibek_defs / "_global" / "epics.ibek.support.yaml" definition_file2 = ibek_defs / "pmac" / "pmac.ibek.support.yaml" @@ -209,15 +209,15 @@ def test_loading_module_twice(tmp_path: Path, samples: Path, ibek_defs: Path): allows us to call make_entity_classes more than once """ - clear_entity_classes() + clear_entity_model_ids() # When we deserialize the same yaml twice as we do in the full test suite # we may get clashes in the namespace of generated Entity classes. # This tests that we get a sensible error when we do definition_file = ibek_defs / "pmac" / "pmac.ibek.support.yaml" support = Support.deserialize(YAML(typ="safe").load(definition_file)) - make_entity_classes(support) + make_entity_models(support) with pytest.raises(AssertionError) as ctx: - make_entity_classes(support) + make_entity_models(support) assert str(ctx.value) == "Entity classes already created for pmac" @@ -226,7 +226,7 @@ def test_bad_counter(tmp_path: Path, samples: Path): Check you cannot redefine a counter with the same name and different params """ - clear_entity_classes() + clear_entity_model_ids() entity_file = samples / "yaml" / "bad_counter.ibek.ioc.yaml" definition_file1 = samples / "yaml" / "bad_counter.ibek.support.yaml" diff --git a/tests/test_conversions.py b/tests/test_conversions.py index a4f7dcc36..2924602b2 100644 --- a/tests/test_conversions.py +++ b/tests/test_conversions.py @@ -1,9 +1,9 @@ -from ibek.ioc import IOC, clear_entity_classes, id_to_entity, make_entity_classes +from ibek.ioc import IOC, clear_entity_model_ids, id_to_entity, make_entity_models from ibek.support import Definition, IdArg, ObjectArg, Support def test_conversion_classes(): - clear_entity_classes() + clear_entity_model_ids() support = Support( "mymodule", [ @@ -11,7 +11,7 @@ def test_conversion_classes(): Definition("device", "a device", [ObjectArg("port", "the port", "object")]), ], ) - namespace = make_entity_classes(support) + namespace = make_entity_models(support) assert {"device", "port"}.issubset(dir(namespace)) assert namespace.port.__definition__ == support.defs[0] assert namespace.device.__definition__ == support.defs[1] diff --git a/tests/test_ioc.py b/tests/test_ioc.py index 92bf41a55..c6925d2d8 100644 --- a/tests/test_ioc.py +++ b/tests/test_ioc.py @@ -2,7 +2,7 @@ from typer.testing import CliRunner -from ibek.ioc import clear_entity_classes +from ibek.ioc import clear_entity_model_ids from ibek.utils import UTILS from .test_cli import run_cli @@ -18,7 +18,7 @@ def test_example_ioc(tmp_path: Path, samples: Path, ibek_defs: Path): but instead of verifying the output, it runs the ioc in a container and \ verifies that it starts up correctly. """ - clear_entity_classes() + clear_entity_model_ids() UTILS.__reset__() tmp_path = Path("/tmp/ibek_test") @@ -60,7 +60,7 @@ def test_example_sr_rf_08(tmp_path: Path, samples: Path, ibek_defs: Path): - the once field (for Hy8401 comments) """ - clear_entity_classes() + clear_entity_model_ids() UTILS.__reset__() tmp_path = Path("/tmp/ibek_test2") @@ -106,7 +106,7 @@ def test_values_ioc(tmp_path: Path, samples: Path, ibek_defs: Path): TODO: make sure samples/values_test/st.cmd is updated when this is fixed. """ - clear_entity_classes() + clear_entity_model_ids() UTILS.__reset__() tmp_path = Path("/tmp/ibek_test2") diff --git a/tests/test_pydantic.py b/tests/test_pydantic.py new file mode 100644 index 000000000..984512331 --- /dev/null +++ b/tests/test_pydantic.py @@ -0,0 +1,80 @@ +""" +Test the pydantic models for the ibek + +ibek.defs.schema.json + test.ibek.support.yaml -> test.ibek.ioc.schema.json +test.ibek.ioc.schema.json + test.ibek.ioc.yaml -> startup script +""" +import json +from pathlib import Path + +from typer.testing import CliRunner + +from ibek.__main__ import cli + +runner = CliRunner() + + +def run_cli(*args): + result = runner.invoke(cli, [str(x) for x in args]) + if result.exception: + raise result.exception + assert result.exit_code == 0, result + + +def test_ioc_schema(tmp_path: Path, samples: Path): + """generate the global ibek schema""" + + # TODO: temporarily using a fixed path to try schema in vscode + tmp_path = Path("/tmp") / "pydantic_test" + tmp_path.mkdir(exist_ok=True) + + ibek_schema_path = tmp_path / "ibek.schema.json" + run_cli("ibek-schema", ibek_schema_path) + expected = json.loads((samples / "schemas" / "ibek.defs.schema.json").read_text()) + + actual = json.loads(ibek_schema_path.read_text()) + assert expected == actual + + pydantic_sample_path = samples / "pydantic" + ioc_schema_name = "test.ibek.ioc.schema.json" + ibek_schema_path = tmp_path / ioc_schema_name + support_yaml_path = pydantic_sample_path / "test.ibek.support.yaml" + + # generate schema from test.ibek.support.yaml + run_cli("ioc-schema", support_yaml_path, ibek_schema_path) + + expected = json.loads((pydantic_sample_path / ioc_schema_name).read_text()) + + actual = json.loads(ibek_schema_path.read_text()) + assert expected == actual + + +def test_ioc_build(tmp_path: Path, samples: Path): + """generate the global ibek schema""" + + # TODO: temporarily using a fixed path to try schema in vscode + tmp_path = Path("/tmp") / "pydantic_test" + tmp_path.mkdir(exist_ok=True) + + pydantic_sample_path = samples / "pydantic" + support_yaml_path = pydantic_sample_path / "test.ibek.support.yaml" + + # generate startup script and from test.ibek.ioc.yaml + ioc_yaml_path = pydantic_sample_path / "test.ibek.ioc.yaml" + out_file = tmp_path / "st.cmd" + out_db = tmp_path / "make_db.sh" + + run_cli( + "build-startup", + ioc_yaml_path, + support_yaml_path, + "--out", + out_file, + "--db-out", + out_db, + ) + + example_boot = (pydantic_sample_path / "st.cmd").read_text() + actual_boot = out_file.read_text() + + assert example_boot == actual_boot diff --git a/tests/test_temp.py b/tests/test_temp.py index c5950746f..ee3ad8b53 100644 --- a/tests/test_temp.py +++ b/tests/test_temp.py @@ -3,7 +3,7 @@ from typer.testing import CliRunner from ibek.__main__ import cli -from ibek.ioc import clear_entity_classes +from ibek.ioc import clear_entity_model_ids runner = CliRunner() @@ -28,7 +28,7 @@ def xxtest_build_startup_p45(tmp_path: Path, samples: Path): """ root = Path("/workspace/bl45p") - clear_entity_classes() + clear_entity_model_ids() entity_file = root / "bl45p-mo-ioc-99.yaml" definitions = Path.glob(root / "ibek", "*.ibek.support.yaml") out_file = root / "iocs/bl45p-mo-ioc-99/config/st.cmd" From c2cca5244b6e52ecc0853f9c6caa4dfec647ee1d Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Wed, 12 Jul 2023 13:51:51 +0000 Subject: [PATCH 05/30] add TODO comments on existing issues --- src/ibek/ioc.py | 31 +++++++----- .../pydantic/test.ibek.ioc.schema.json | 48 +++++++++++++++++++ tests/samples/pydantic/test.ibek.ioc.yaml | 26 ++++++---- tests/samples/pydantic/test.ibek.support.yaml | 35 +++++++++----- 4 files changed, 108 insertions(+), 32 deletions(-) diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index d142aec78..42afadad4 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -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 @@ -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) @@ -64,8 +70,8 @@ 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, @@ -73,7 +79,7 @@ def add_entity(name, typ, description, 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 @@ -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 @@ -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 diff --git a/tests/samples/pydantic/test.ibek.ioc.schema.json b/tests/samples/pydantic/test.ibek.ioc.schema.json index 350c4696c..e21ce789f 100644 --- a/tests/samples/pydantic/test.ibek.ioc.schema.json +++ b/tests/samples/pydantic/test.ibek.ioc.schema.json @@ -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", @@ -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", @@ -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, @@ -76,6 +121,9 @@ }, { "$ref": "#/$defs/pydantic_test_Consumer" + }, + { + "$ref": "#/$defs/pydantic_test_ConsumerTwo" } ] }, diff --git a/tests/samples/pydantic/test.ibek.ioc.yaml b/tests/samples/pydantic/test.ibek.ioc.yaml index 407f33fb5..e28dfba80 100644 --- a/tests/samples/pydantic/test.ibek.ioc.yaml +++ b/tests/samples/pydantic/test.ibek.ioc.yaml @@ -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 @@ -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 diff --git a/tests/samples/pydantic/test.ibek.support.yaml b/tests/samples/pydantic/test.ibek.support.yaml index 71abad450..2482faa15 100644 --- a/tests/samples/pydantic/test.ibek.support.yaml +++ b/tests/samples/pydantic/test.ibek.support.yaml @@ -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 From 8285b3cef717e6a8c9c4a9f454be5e92676a7033 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Thu, 13 Jul 2023 12:40:03 +0000 Subject: [PATCH 06/30] pydantiic test_ioc_build test working but test_ioc_schema is not --- src/ibek/globals.py | 2 +- src/ibek/ioc.py | 34 ++++++++++++++----- tests/samples/pydantic/test.ibek.ioc.yaml | 10 +++--- tests/samples/pydantic/test.ibek.support.yaml | 24 ++++++------- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/ibek/globals.py b/src/ibek/globals.py index be139d7c9..b45f869af 100644 --- a/src/ibek/globals.py +++ b/src/ibek/globals.py @@ -6,7 +6,7 @@ # pydantic model configuration model_config = ConfigDict( - # arbitrary_types_allowed=True, + arbitrary_types_allowed=True, extra="forbid", ) diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index 42afadad4..a016680f7 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -5,7 +5,7 @@ from __future__ import annotations import builtins -from typing import Any, Dict, Literal, Sequence, Tuple, Type, Union +from typing import Annotated, Any, Dict, Literal, Sequence, Tuple, Type, Union from jinja2 import Template from pydantic import Field, create_model, field_validator, model_validator @@ -21,19 +21,27 @@ id_to_entity: Dict[str, Entity] = {} +class TypeOfType(BaseSettings): + type_name: str = Field("str", description="Type of this entity ") + + def __str__(self) -> str: + return self.type_name + + class Entity(BaseSettings): """ A baseclass for all generated Entity classes. Provides the deserialize entry point. """ - # a link back to the Definition Object that generated this Definition - __definition__: Definition - + type: str = Field(description="The type of this entity") entity_enabled: bool = Field( description="enable or disable this entity instance", default=True ) + # a link back to the Definition Object that generated this Definition + __definition__: Definition + @model_validator(mode="before") # type: ignore def add_ibek_attributes(cls, entity: Dict): """Add attributes used by ibek""" @@ -88,8 +96,11 @@ def add_arg(name, typ, description, default): # add in each of the arguments as a Field in the Entity for arg in definition.args: full_arg_name = f"{full_name}.{arg.name}" + arg_type: Any - if isinstance(arg, ObjectArg): + if arg.name == "type": + arg_type = TypeOfType(type_name=arg.name) + elif isinstance(arg, ObjectArg): @field_validator(arg.name) def lookup_instance(cls, id): @@ -106,8 +117,7 @@ def lookup_instance(cls, id): @field_validator(arg.name) 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)}") + raise KeyError(f"id {id} already defined in {list(id_to_entity)}") id_to_entity[id] = "test_sub_object" return id @@ -158,9 +168,15 @@ def make_entity_models(support: Support): def make_ioc_model(entity_models: Sequence[Type[Entity]]) -> Type[IOC]: + EntityModels = Annotated[ + Union[tuple(entity_models)], # type: ignore + FieldInfo(discriminator="type"), + ] + class NewIOC(IOC): - entities: Sequence[Union[tuple(entity_models)]] = Field( # type: ignore - description="List of entities this IOC instantiates", default=() + entities: Sequence[EntityModels] = Field( # type: ignore + description="List of entities this IOC instantiates", + default=(), ) return NewIOC diff --git a/tests/samples/pydantic/test.ibek.ioc.yaml b/tests/samples/pydantic/test.ibek.ioc.yaml index e28dfba80..614a6e7e5 100644 --- a/tests/samples/pydantic/test.ibek.ioc.yaml +++ b/tests/samples/pydantic/test.ibek.ioc.yaml @@ -1,4 +1,6 @@ -# yaml-language-server: $schema=/scratch/hgv27681/work/ibek/tests/samples/pydantic/test.ibek.support.yaml +# yaml-language-server: $schema=/scratch/hgv27681/work/ibek/tests/samples/pydantic/test.ibek.ioc.schema.json +# restore the below to the top for investigating tests +# yaml-language-server: $schema=/tmp/pydantic_test/test.ibek.ioc.schema.json ioc_name: test-pydantic-ioc description: a basic example for testing ioc-template @@ -13,9 +15,9 @@ entities: name: AsynPort2 IP: 10.0.0.1 - # - type: pydantic_test.Consumer - # name: A Consumer - # PORT: AsynPort + - type: pydantic_test.Consumer + name: A Consumer + PORT: AsynPort - type: pydantic_test.Consumer name: Another Consumer of same port diff --git a/tests/samples/pydantic/test.ibek.support.yaml b/tests/samples/pydantic/test.ibek.support.yaml index 2482faa15..f3ca66651 100644 --- a/tests/samples/pydantic/test.ibek.support.yaml +++ b/tests/samples/pydantic/test.ibek.support.yaml @@ -27,7 +27,7 @@ defs: name: name description: Consumer name - - type: str + - type: object name: PORT description: a reference to an AnAsynPort @@ -39,17 +39,17 @@ defs: name: name description: Consumer name - - type: str + - type: object name: PORT description: a reference to an AnAsynPort - # 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 + 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 From 5b5b7a562a572442845d590f9c00a7386d532bdf Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Thu, 13 Jul 2023 14:46:29 +0000 Subject: [PATCH 07/30] great progress --- src/ibek/gen_scripts.py | 10 +- src/ibek/ioc.py | 51 +- src/ibek/render.py | 23 +- tests/samples/boot_scripts/st.cmd | 11 + tests/samples/boot_scripts/stbl45p-mo-ioc-03 | 11 + tests/samples/boot_scripts/stbl45p-mo-ioc-04 | 5 + tests/samples/boot_scripts/test.ioc.cmd | 5 + .../samples/boot_scripts/test.ioc.make_db.sh | 1 + tests/samples/example-srrfioc08/make_db.sh | 1 + tests/samples/example-srrfioc08/st.cmd | 5 + tests/samples/pydantic/generate_samples.sh | 3 + tests/samples/pydantic/make_db.sh | 1 + tests/samples/pydantic/st.cmd | 6 + .../pydantic/test.ibek.ioc.schema.json | 74 +- tests/samples/pydantic/test.ibek.ioc.yaml | 2 +- tests/samples/pydantic/test.ibek.support.yaml | 4 +- .../schemas/all.ibek.support.schema.json | 1150 +++++++++++------ .../schemas/asyn.ibek.entities.schema.json | 67 +- .../bl45p-mo-ioc-04.ibek.entities.schema.json | 468 ++++--- .../container.ibek.entities.schema.json | 343 +++-- .../schemas/epics.ibek.support.schema.json | 192 ++- .../schemas/pmac.ibek.entities.schema.json | 293 +++-- tests/samples/values_test/st.cmd | 11 + 23 files changed, 1808 insertions(+), 929 deletions(-) create mode 100644 tests/samples/pydantic/make_db.sh diff --git a/src/ibek/gen_scripts.py b/src/ibek/gen_scripts.py index 32ec93ee9..7fff7c5fc 100644 --- a/src/ibek/gen_scripts.py +++ b/src/ibek/gen_scripts.py @@ -52,13 +52,13 @@ def ioc_deserialize(ioc_instance_yaml: Path, definition_yaml: List[Path]) -> IOC """ ioc_model = ioc_create_model(definition_yaml) - ioc_instance = YAML(typ="safe").load(ioc_instance_yaml) + # extract the ioc instance yaml into a dict + ioc_instance_dict = YAML(typ="safe").load(ioc_instance_yaml) - clear_entity_model_ids() - ioc_model.model_validate(ioc_instance) + # Create an IOC instance from the instance dict and the model + ioc_instance = ioc_model(**ioc_instance_dict) - # Create an IOC instance from the entities file and the model - return ioc_model.model_construct(ioc_instance) + return ioc_instance def create_db_script(ioc_instance: IOC) -> str: diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index a016680f7..7f9db2b4c 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -5,15 +5,14 @@ from __future__ import annotations import builtins -from typing import Annotated, Any, Dict, Literal, Sequence, Tuple, Type, Union +from typing import Any, Dict, Literal, Sequence, Tuple, Type, Union from jinja2 import Template -from pydantic import Field, create_model, field_validator, model_validator +from pydantic import Field, RootModel, create_model, field_validator, model_validator from pydantic.fields import FieldInfo -from .globals import BaseSettings, model_config +from .globals import BaseSettings from .support import Definition, IdArg, ObjectArg, Support -from .utils import UTILS # A base class for applying settings to all serializable classes @@ -21,13 +20,6 @@ id_to_entity: Dict[str, Entity] = {} -class TypeOfType(BaseSettings): - type_name: str = Field("str", description="Type of this entity ") - - def __str__(self) -> str: - return self.type_name - - class Entity(BaseSettings): """ A baseclass for all generated Entity classes. Provides the @@ -79,15 +71,9 @@ def make_entity_model(definition: Definition, support: Support) -> Type[Entity]: """ def add_arg(name, typ, description, default): - arguments[name] = ( - typ, - FieldInfo( - description=description, - default=default, - ), - ) + args[name] = (typ, FieldInfo(description=description, default=default)) - arguments: Dict[str, Tuple[type, Any]] = {} + args: Dict[str, Tuple[type, Any]] = {} validators: Dict[str, Any] = {} # fully qualified name of the Entity class including support module @@ -98,9 +84,7 @@ def add_arg(name, typ, description, default): full_arg_name = f"{full_name}.{arg.name}" arg_type: Any - if arg.name == "type": - arg_type = TypeOfType(type_name=arg.name) - elif isinstance(arg, ObjectArg): + if isinstance(arg, ObjectArg): @field_validator(arg.name) def lookup_instance(cls, id): @@ -110,7 +94,7 @@ def lookup_instance(cls, id): raise KeyError(f"object id {id} not in {list(id_to_entity)}") validators[full_arg_name] = lookup_instance - arg_type = str + arg_type = Entity elif isinstance(arg, IdArg): @@ -118,7 +102,7 @@ def lookup_instance(cls, id): def save_instance(cls, id): if id in id_to_entity: raise KeyError(f"id {id} already defined in {list(id_to_entity)}") - id_to_entity[id] = "test_sub_object" + id_to_entity[id] = Entity return id validators[full_arg_name] = save_instance @@ -136,13 +120,13 @@ def save_instance(cls, id): entity_cls = create_model( full_name.replace(".", "_"), - **arguments, + **args, __validators__=validators, - __base__=Entity - # __config__=model_config, NOTE: either set config or inherit with __base__ + __base__=Entity, ) # type: ignore # add a link back to the Definition Object that generated this Entity Class + # TODO replace this mechanism as it does not work in pydantic entity_cls.__definition__ = definition return entity_cls @@ -168,15 +152,12 @@ def make_entity_models(support: Support): def make_ioc_model(entity_models: Sequence[Type[Entity]]) -> Type[IOC]: - EntityModels = Annotated[ - Union[tuple(entity_models)], # type: ignore - FieldInfo(discriminator="type"), - ] + class EntityModel(RootModel): + root: Union[tuple(entity_models)] = Field(discriminator="type") # type: ignore class NewIOC(IOC): - entities: Sequence[EntityModels] = Field( # type: ignore - description="List of entities this IOC instantiates", - default=(), + entities: Sequence[EntityModel] = Field( # type: ignore + description="List of entities this IOC instantiates" ) return NewIOC @@ -199,3 +180,5 @@ class IOC(BaseSettings): generic_ioc_image: str = Field( description="The generic IOC container image registry URL" ) + # this will be replaced in derived classes made by make_ioc_model + entities: Sequence[Entity] diff --git a/src/ibek/render.py b/src/ibek/render.py index 06acaaefe..5794a3960 100644 --- a/src/ibek/render.py +++ b/src/ibek/render.py @@ -8,6 +8,7 @@ from .ioc import IOC, Entity from .support import Comment, Function, Script, Text, When +from .utils import UTILS class Render: @@ -20,6 +21,13 @@ class Render: def __init__(self: "Render"): self.once_done: List[str] = [] + def render_with_utils(self, instance: Entity, template_text: str) -> str: + """ + Render a Jinja template with the global __utils__ object available + """ + jinja_template = Template(template_text) + return jinja_template.render(instance.__dict__, __utils__=UTILS) + def render_text( self, instance: Entity, text: str, when=When.every, suffix="" ) -> str: @@ -46,8 +54,7 @@ def render_text( raise NotImplementedError("When.last not yet implemented") # Render Jinja entries in the text - jinja_template = Template(text) - result = jinja_template.render(instance.__dict__) # type: ignore + result = self.render_with_utils(instance, text) if result == "": return "" @@ -146,8 +153,7 @@ def render_database(self, instance: Entity) -> Optional[str]: f'msi -I${{EPICS_DB_INCLUDE_PATH}} -M"{db_arg_string}" "{db_file}"\n' ) - jinja_template = Template(jinja_txt) - db_txt = jinja_template.render(instance.__dict__) # type: ignore + db_txt = self.render_with_utils(instance, jinja_txt) return db_txt + "\n" @@ -163,8 +169,8 @@ def render_environment_variables(self, instance: Entity) -> Optional[str]: env_var_txt = "" for variable in variables: # Substitute the name and value of the environment variable from args - env_template = Template(f"epicsEnvSet {variable.name} {variable.value}") - env_var_txt += env_template.render(instance.__dict__) + env_template = f"epicsEnvSet {variable.name} {variable.value}" + env_var_txt += self.render_with_utils(instance, env_template) return env_var_txt + "\n" def render_elements( @@ -174,7 +180,10 @@ def render_elements( Render elements of a given IOC instance based on calling the correct method """ elements = "" - for instance in ioc.entities: + for entity in ioc.entities: + # TODO can we eliminate the need for intermediate root + # see definition of EntityModel in ioc.py + instance = getattr(entity, "root") if instance.entity_enabled: element = method(instance) if element: diff --git a/tests/samples/boot_scripts/st.cmd b/tests/samples/boot_scripts/st.cmd index 870df2af5..601e5ecc5 100644 --- a/tests/samples/boot_scripts/st.cmd +++ b/tests/samples/boot_scripts/st.cmd @@ -1,10 +1,21 @@ # EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek cd "/repos/epics/ioc" + +epicsEnvSet Vec0 192 + dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase +# ipacAddHy8002 "slot, interrupt_level" +# Create a new Hy8002 carrier. +# The resulting carrier handle (card id) is saved in an env variable. +ipacAddHy8002 "4, 2" +epicsEnvSet IPAC4 +ipacAddHy8002 "5, 2" +epicsEnvSet IPAC5 + dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/boot_scripts/stbl45p-mo-ioc-03 b/tests/samples/boot_scripts/stbl45p-mo-ioc-03 index 870df2af5..601e5ecc5 100644 --- a/tests/samples/boot_scripts/stbl45p-mo-ioc-03 +++ b/tests/samples/boot_scripts/stbl45p-mo-ioc-03 @@ -1,10 +1,21 @@ # EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek cd "/repos/epics/ioc" + +epicsEnvSet Vec0 192 + dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase +# ipacAddHy8002 "slot, interrupt_level" +# Create a new Hy8002 carrier. +# The resulting carrier handle (card id) is saved in an env variable. +ipacAddHy8002 "4, 2" +epicsEnvSet IPAC4 +ipacAddHy8002 "5, 2" +epicsEnvSet IPAC5 + dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/boot_scripts/stbl45p-mo-ioc-04 b/tests/samples/boot_scripts/stbl45p-mo-ioc-04 index 870df2af5..888f1f0c4 100644 --- a/tests/samples/boot_scripts/stbl45p-mo-ioc-04 +++ b/tests/samples/boot_scripts/stbl45p-mo-ioc-04 @@ -8,3 +8,8 @@ ioc_registerRecordDeviceDriver pdbbase dbLoadRecords /tmp/ioc.db iocInit + + +# dbpf pv value +dbpf BL45P-MO-THIN-01:Y1.TWV 0.5 + diff --git a/tests/samples/boot_scripts/test.ioc.cmd b/tests/samples/boot_scripts/test.ioc.cmd index 870df2af5..d946f599f 100644 --- a/tests/samples/boot_scripts/test.ioc.cmd +++ b/tests/samples/boot_scripts/test.ioc.cmd @@ -1,9 +1,14 @@ # EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek cd "/repos/epics/ioc" + +epicsEnvSet EPICS_CA_MAX_ARRAY_BYTES 6000000 +epicsEnvSet EPICS_CA_SERVER_PORT 7064 + dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase +dbLoadRecords("config/ioc.db") dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/boot_scripts/test.ioc.make_db.sh b/tests/samples/boot_scripts/test.ioc.make_db.sh index a9bf588e2..fca3baaa7 100644 --- a/tests/samples/boot_scripts/test.ioc.make_db.sh +++ b/tests/samples/boot_scripts/test.ioc.make_db.sh @@ -1 +1,2 @@ #!/bin/bash +msi -I${EPICS_DB_INCLUDE_PATH} -M"IOC=test-ibek-ioc" "iocAdminSoft.db" diff --git a/tests/samples/example-srrfioc08/make_db.sh b/tests/samples/example-srrfioc08/make_db.sh index a9bf588e2..fca3baaa7 100644 --- a/tests/samples/example-srrfioc08/make_db.sh +++ b/tests/samples/example-srrfioc08/make_db.sh @@ -1 +1,2 @@ #!/bin/bash +msi -I${EPICS_DB_INCLUDE_PATH} -M"IOC=test-ibek-ioc" "iocAdminSoft.db" diff --git a/tests/samples/example-srrfioc08/st.cmd b/tests/samples/example-srrfioc08/st.cmd index 870df2af5..d946f599f 100644 --- a/tests/samples/example-srrfioc08/st.cmd +++ b/tests/samples/example-srrfioc08/st.cmd @@ -1,9 +1,14 @@ # EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek cd "/repos/epics/ioc" + +epicsEnvSet EPICS_CA_MAX_ARRAY_BYTES 6000000 +epicsEnvSet EPICS_CA_SERVER_PORT 7064 + dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase +dbLoadRecords("config/ioc.db") dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/pydantic/generate_samples.sh b/tests/samples/pydantic/generate_samples.sh index e0292056b..5f9cef76d 100755 --- a/tests/samples/pydantic/generate_samples.sh +++ b/tests/samples/pydantic/generate_samples.sh @@ -18,3 +18,6 @@ ibek ibek-schema ${PYDANTIC_DIR}/../schemas/ibek.defs.schema.json echo making the pydantic test definition schema ibek ioc-schema ${PYDANTIC_DIR}/test.ibek.support.yaml $PYDANTIC_DIR/test.ibek.ioc.schema.json + +echo making the pydantic test ioc startup script +ibek build-startup ${PYDANTIC_DIR}/test.ibek.ioc.yaml ${PYDANTIC_DIR}/test.ibek.support.yaml --out $PYDANTIC_DIR/st.cmd --db-out $PYDANTIC_DIR/make_db.sh diff --git a/tests/samples/pydantic/make_db.sh b/tests/samples/pydantic/make_db.sh new file mode 100644 index 000000000..a9bf588e2 --- /dev/null +++ b/tests/samples/pydantic/make_db.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/tests/samples/pydantic/st.cmd b/tests/samples/pydantic/st.cmd index 870df2af5..4a9af0c37 100644 --- a/tests/samples/pydantic/st.cmd +++ b/tests/samples/pydantic/st.cmd @@ -5,6 +5,12 @@ dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase +# exampleTestFunction AsynPortIP Name Value +# A function that uses the AsynPortIP and Name +# to do something useful +exampleTestFunction Yet Another Consumer of same port +exampleTestFunction Just One More Consumer of same port + dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/pydantic/test.ibek.ioc.schema.json b/tests/samples/pydantic/test.ibek.ioc.schema.json index e21ce789f..8d2356927 100644 --- a/tests/samples/pydantic/test.ibek.ioc.schema.json +++ b/tests/samples/pydantic/test.ibek.ioc.schema.json @@ -1,8 +1,36 @@ { "$defs": { + "EntityModel": { + "discriminator": { + "mapping": { + "pydantic_test.AnAsynPort": "#/$defs/pydantic_test_AnAsynPort", + "pydantic_test.Consumer": "#/$defs/pydantic_test_Consumer", + "pydantic_test.ConsumerTwo": "#/$defs/pydantic_test_ConsumerTwo" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/pydantic_test_AnAsynPort" + }, + { + "$ref": "#/$defs/pydantic_test_Consumer" + }, + { + "$ref": "#/$defs/pydantic_test_ConsumerTwo" + } + ], + "title": "EntityModel" + }, "pydantic_test_AnAsynPort": { "additionalProperties": false, "properties": { + "type": { + "const": "pydantic_test.AnAsynPort", + "default": "pydantic_test.AnAsynPort", + "description": "The type of this entity", + "title": "Type" + }, "entity_enabled": { "default": true, "description": "enable or disable this entity instance", @@ -20,12 +48,6 @@ "description": "IP address of port", "title": "Ip", "type": "string" - }, - "type": { - "const": "pydantic_test.AnAsynPort", - "default": "pydantic_test.AnAsynPort", - "description": "The type of this entity", - "title": "Type" } }, "title": "pydantic_test_AnAsynPort", @@ -34,6 +56,12 @@ "pydantic_test_Consumer": { "additionalProperties": false, "properties": { + "type": { + "const": "pydantic_test.Consumer", + "default": "pydantic_test.Consumer", + "description": "The type of this entity", + "title": "Type" + }, "entity_enabled": { "default": true, "description": "enable or disable this entity instance", @@ -51,12 +79,6 @@ "description": "a reference to an AnAsynPort", "title": "Port", "type": "string" - }, - "type": { - "const": "pydantic_test.Consumer", - "default": "pydantic_test.Consumer", - "description": "The type of this entity", - "title": "Type" } }, "title": "pydantic_test_Consumer", @@ -65,6 +87,12 @@ "pydantic_test_ConsumerTwo": { "additionalProperties": false, "properties": { + "type": { + "const": "pydantic_test.ConsumerTwo", + "default": "pydantic_test.ConsumerTwo", + "description": "The type of this entity", + "title": "Type" + }, "entity_enabled": { "default": true, "description": "enable or disable this entity instance", @@ -82,12 +110,6 @@ "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", @@ -112,20 +134,9 @@ "type": "string" }, "entities": { - "default": [], "description": "List of entities this IOC instantiates", "items": { - "anyOf": [ - { - "$ref": "#/$defs/pydantic_test_AnAsynPort" - }, - { - "$ref": "#/$defs/pydantic_test_Consumer" - }, - { - "$ref": "#/$defs/pydantic_test_ConsumerTwo" - } - ] + "$ref": "#/$defs/EntityModel" }, "title": "Entities", "type": "array" @@ -134,7 +145,8 @@ "required": [ "ioc_name", "description", - "generic_ioc_image" + "generic_ioc_image", + "entities" ], "title": "NewIOC", "type": "object" diff --git a/tests/samples/pydantic/test.ibek.ioc.yaml b/tests/samples/pydantic/test.ibek.ioc.yaml index 614a6e7e5..cc2fd4a15 100644 --- a/tests/samples/pydantic/test.ibek.ioc.yaml +++ b/tests/samples/pydantic/test.ibek.ioc.yaml @@ -17,7 +17,7 @@ entities: - type: pydantic_test.Consumer name: A Consumer - PORT: AsynPort + PORT: AsynPort2 - type: pydantic_test.Consumer name: Another Consumer of same port diff --git a/tests/samples/pydantic/test.ibek.support.yaml b/tests/samples/pydantic/test.ibek.support.yaml index f3ca66651..fd928ee76 100644 --- a/tests/samples/pydantic/test.ibek.support.yaml +++ b/tests/samples/pydantic/test.ibek.support.yaml @@ -51,5 +51,5 @@ defs: Name: "{{ name }}" Value: "{{ PORT.test_value }}" header: | - A function that uses the AsynPortIP and Name - to do something useful + # A function that uses the AsynPortIP and Name + # to do something useful diff --git a/tests/samples/schemas/all.ibek.support.schema.json b/tests/samples/schemas/all.ibek.support.schema.json index a6b16c00f..7d8968e54 100644 --- a/tests/samples/schemas/all.ibek.support.schema.json +++ b/tests/samples/schemas/all.ibek.support.schema.json @@ -3,6 +3,18 @@ "ADAravis_ADAravis": { "additionalProperties": false, "properties": { + "type": { + "const": "ADAravis.ADAravis", + "default": "ADAravis.ADAravis", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "PORT": { "default": null, "description": "Port Name for teh camera", @@ -50,12 +62,6 @@ "description": "TODO this need to look into the purpose of this in builder.py\ndetermine its function and see if we can do the equivalent in ibek\n", "title": "Pv Alias", "type": "string" - }, - "type": { - "const": "ADAravis.ADAravis", - "default": "ADAravis.ADAravis", - "description": "The type of this entity", - "title": "Type" } }, "title": "ADAravis_ADAravis", @@ -64,17 +70,26 @@ "ADAravis_Mako_G234B": { "additionalProperties": false, "properties": { - "camera": { - "default": null, - "description": "reference to ADAravis.ADAravis instance", - "title": "Camera", - "type": "string" - }, "type": { "const": "ADAravis.Mako_G234B", "default": "ADAravis.Mako_G234B", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "camera": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], + "default": null, + "description": "reference to ADAravis.ADAravis instance" } }, "title": "ADAravis_Mako_G234B", @@ -83,17 +98,26 @@ "ADAravis_MantaG235B": { "additionalProperties": false, "properties": { - "camera": { - "default": null, - "description": "reference to ADAravis.ADAravis instance", - "title": "Camera", - "type": "string" - }, "type": { "const": "ADAravis.MantaG235B", "default": "ADAravis.MantaG235B", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "camera": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], + "default": null, + "description": "reference to ADAravis.ADAravis instance" } }, "title": "ADAravis_MantaG235B", @@ -102,6 +126,18 @@ "ADCore_NDRoi": { "additionalProperties": false, "properties": { + "type": { + "const": "ADCore.NDRoi", + "default": "ADCore.NDRoi", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "PORT": { "default": null, "description": "Port for this plugin", @@ -109,10 +145,13 @@ "type": "string" }, "NDARRAY_PORT": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Port Name for input NDArray plugin", - "title": "Ndarray Port", - "type": "string" + "description": "Port Name for input NDArray plugin" }, "P": { "default": null, @@ -173,12 +212,6 @@ "description": "Maximum number of threads to use", "title": "Max Threads", "type": "integer" - }, - "type": { - "const": "ADCore.NDRoi", - "default": "ADCore.NDRoi", - "description": "The type of this entity", - "title": "Type" } }, "title": "ADCore_NDRoi", @@ -187,6 +220,18 @@ "ADCore_NDStats": { "additionalProperties": false, "properties": { + "type": { + "const": "ADCore.NDStats", + "default": "ADCore.NDStats", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "PORT": { "default": null, "description": "Port for this plugin", @@ -258,37 +303,220 @@ "description": "Maximum number of threads to use", "title": "Max Threads", "type": "integer" - }, + } + }, + "title": "ADCore_NDStats", + "type": "object" + }, + "Entity": { + "additionalProperties": false, + "description": "\n A baseclass for all generated Entity classes. Provides the\n deserialize entry point.\n ", + "properties": { "type": { - "const": "ADCore.NDStats", - "default": "ADCore.NDStats", "description": "The type of this entity", - "title": "Type" + "title": "Type", + "type": "string" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" } }, - "title": "ADCore_NDStats", + "required": [ + "type" + ], + "title": "Entity", "type": "object" }, + "EntityModel": { + "discriminator": { + "mapping": { + "ADAravis.ADAravis": "#/$defs/ADAravis_ADAravis", + "ADAravis.Mako_G234B": "#/$defs/ADAravis_Mako_G234B", + "ADAravis.MantaG235B": "#/$defs/ADAravis_MantaG235B", + "ADCore.NDRoi": "#/$defs/ADCore_NDRoi", + "ADCore.NDStats": "#/$defs/ADCore_NDStats", + "Hy8401ip.Hy8401Channel": "#/$defs/Hy8401ip_Hy8401Channel", + "Hy8401ip.Hy8401ip": "#/$defs/Hy8401ip_Hy8401ip", + "Hy8403ip.Hy8403Channel": "#/$defs/Hy8403ip_Hy8403Channel", + "Hy8403ip.Hy8403ip": "#/$defs/Hy8403ip_Hy8403ip", + "PT100.PT100": "#/$defs/PT100_PT100", + "TimingTemplates.DefaultEVR": "#/$defs/TimingTemplates_DefaultEVR", + "TimingTemplates.EvrAlive": "#/$defs/TimingTemplates_EvrAlive", + "TimingTemplates.GeneralTime": "#/$defs/TimingTemplates_GeneralTime", + "asyn.AsynIP": "#/$defs/asyn_AsynIP", + "asyn.AsynSerial": "#/$defs/asyn_AsynSerial", + "devIocStats.IocAdminSoft": "#/$defs/devIocStats_IocAdminSoft", + "epics.Dbpf": "#/$defs/epics_Dbpf", + "epics.EpicsCaMaxArrayBytes": "#/$defs/epics_EpicsCaMaxArrayBytes", + "epics.EpicsEnvSet": "#/$defs/epics_EpicsEnvSet", + "epics.EpicsTsMinWest": "#/$defs/epics_EpicsTsMinWest", + "epics.InterruptVectorVME": "#/$defs/epics_InterruptVectorVME", + "epics.PostStartupCommand": "#/$defs/epics_PostStartupCommand", + "epics.StartupCommand": "#/$defs/epics_StartupCommand", + "ipac.Hy8002": "#/$defs/ipac_Hy8002", + "mrfTiming.EventReceiverInit": "#/$defs/mrfTiming_EventReceiverInit", + "mrfTiming.EventReceiverPMC": "#/$defs/mrfTiming_EventReceiverPMC", + "pmac.CS": "#/$defs/pmac_CS", + "pmac.DlsCsPmacAsynMotor": "#/$defs/pmac_DlsCsPmacAsynMotor", + "pmac.DlsPmacAsynMotor": "#/$defs/pmac_DlsPmacAsynMotor", + "pmac.Geobrick": "#/$defs/pmac_Geobrick", + "pmac.PmacAsynIPPort": "#/$defs/pmac_PmacAsynIPPort", + "pmac.PmacAsynSSHPort": "#/$defs/pmac_PmacAsynSSHPort", + "pmac.autohome": "#/$defs/pmac_autohome", + "pmac.pmacDisableLimitsCheck": "#/$defs/pmac_pmacDisableLimitsCheck", + "psc.PscIpModule": "#/$defs/psc_PscIpModule", + "psc.PscTemplate": "#/$defs/psc_PscTemplate", + "psc.pscHy8401Channel-BS": "#/$defs/psc_pscHy8401Channel-BS" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/ADAravis_ADAravis" + }, + { + "$ref": "#/$defs/ADAravis_MantaG235B" + }, + { + "$ref": "#/$defs/ADAravis_Mako_G234B" + }, + { + "$ref": "#/$defs/ADCore_NDRoi" + }, + { + "$ref": "#/$defs/ADCore_NDStats" + }, + { + "$ref": "#/$defs/Hy8401ip_Hy8401ip" + }, + { + "$ref": "#/$defs/Hy8401ip_Hy8401Channel" + }, + { + "$ref": "#/$defs/Hy8403ip_Hy8403ip" + }, + { + "$ref": "#/$defs/Hy8403ip_Hy8403Channel" + }, + { + "$ref": "#/$defs/PT100_PT100" + }, + { + "$ref": "#/$defs/TimingTemplates_DefaultEVR" + }, + { + "$ref": "#/$defs/TimingTemplates_EvrAlive" + }, + { + "$ref": "#/$defs/TimingTemplates_GeneralTime" + }, + { + "$ref": "#/$defs/devIocStats_IocAdminSoft" + }, + { + "$ref": "#/$defs/epics_EpicsCaMaxArrayBytes" + }, + { + "$ref": "#/$defs/epics_EpicsTsMinWest" + }, + { + "$ref": "#/$defs/epics_Dbpf" + }, + { + "$ref": "#/$defs/epics_EpicsEnvSet" + }, + { + "$ref": "#/$defs/epics_StartupCommand" + }, + { + "$ref": "#/$defs/epics_PostStartupCommand" + }, + { + "$ref": "#/$defs/epics_InterruptVectorVME" + }, + { + "$ref": "#/$defs/asyn_AsynSerial" + }, + { + "$ref": "#/$defs/asyn_AsynIP" + }, + { + "$ref": "#/$defs/ipac_Hy8002" + }, + { + "$ref": "#/$defs/mrfTiming_EventReceiverInit" + }, + { + "$ref": "#/$defs/mrfTiming_EventReceiverPMC" + }, + { + "$ref": "#/$defs/pmac_PmacAsynSSHPort" + }, + { + "$ref": "#/$defs/pmac_PmacAsynIPPort" + }, + { + "$ref": "#/$defs/pmac_Geobrick" + }, + { + "$ref": "#/$defs/pmac_DlsPmacAsynMotor" + }, + { + "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" + }, + { + "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" + }, + { + "$ref": "#/$defs/pmac_autohome" + }, + { + "$ref": "#/$defs/pmac_CS" + }, + { + "$ref": "#/$defs/psc_PscIpModule" + }, + { + "$ref": "#/$defs/psc_PscTemplate" + }, + { + "$ref": "#/$defs/psc_pscHy8401Channel-BS" + } + ], + "title": "EntityModel" + }, "Hy8401ip_Hy8401Channel": { "additionalProperties": false, "properties": { + "type": { + "const": "Hy8401ip.Hy8401Channel", + "default": "Hy8401ip.Hy8401Channel", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "card": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "8401 card identifier", - "title": "Card", - "type": "string" + "description": "8401 card identifier" }, "signal": { "default": null, "description": "8401 signal number (0-7)", "title": "Signal", "type": "integer" - }, - "type": { - "const": "Hy8401ip.Hy8401Channel", - "default": "Hy8401ip.Hy8401Channel", - "description": "The type of this entity", - "title": "Type" } }, "title": "Hy8401ip_Hy8401Channel", @@ -297,6 +525,18 @@ "Hy8401ip_Hy8401ip": { "additionalProperties": false, "properties": { + "type": { + "const": "Hy8401ip.Hy8401ip", + "default": "Hy8401ip.Hy8401ip", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Name to refer to when making a channel", @@ -304,10 +544,13 @@ "type": "string" }, "carrier": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Carrier Board Identifier", - "title": "Carrier", - "type": "string" + "description": "Carrier Board Identifier" }, "ip_site_number": { "default": null, @@ -316,10 +559,13 @@ "type": "integer" }, "vector": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Interrupt Vector", - "title": "Vector", - "type": "string" + "description": "Interrupt Vector" }, "int_enable": { "default": false, @@ -356,12 +602,6 @@ "description": "Card Identifier", "title": "Card Id", "type": "string" - }, - "type": { - "const": "Hy8401ip.Hy8401ip", - "default": "Hy8401ip.Hy8401ip", - "description": "The type of this entity", - "title": "Type" } }, "title": "Hy8401ip_Hy8401ip", @@ -370,6 +610,18 @@ "Hy8403ip_Hy8403Channel": { "additionalProperties": false, "properties": { + "type": { + "const": "Hy8403ip.Hy8403Channel", + "default": "Hy8403ip.Hy8403Channel", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "device": { "default": null, "description": "Device Name, PV Suffix", @@ -377,16 +629,13 @@ "type": "string" }, "card": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "8403 card identifier", - "title": "Card", - "type": "string" - }, - "type": { - "const": "Hy8403ip.Hy8403Channel", - "default": "Hy8403ip.Hy8403Channel", - "description": "The type of this entity", - "title": "Type" + "description": "8403 card identifier" } }, "title": "Hy8403ip_Hy8403Channel", @@ -395,6 +644,18 @@ "Hy8403ip_Hy8403ip": { "additionalProperties": false, "properties": { + "type": { + "const": "Hy8403ip.Hy8403ip", + "default": "Hy8403ip.Hy8403ip", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Name to refer to when making a channel", @@ -402,10 +663,13 @@ "type": "string" }, "carrier": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Carrier Board Identifier", - "title": "Carrier", - "type": "string" + "description": "Carrier Board Identifier" }, "ip_site_number": { "default": null, @@ -414,10 +678,13 @@ "type": "integer" }, "vector": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Interrupt Vector", - "title": "Vector", - "type": "string" + "description": "Interrupt Vector" }, "aitype": { "default": null, @@ -460,12 +727,6 @@ "description": "Card Identifier", "title": "Card Id", "type": "string" - }, - "type": { - "const": "Hy8403ip.Hy8403ip", - "default": "Hy8403ip.Hy8403ip", - "description": "The type of this entity", - "title": "Type" } }, "title": "Hy8403ip_Hy8403ip", @@ -474,6 +735,18 @@ "PT100_PT100": { "additionalProperties": false, "properties": { + "type": { + "const": "PT100.PT100", + "default": "PT100.PT100", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "PT": { "default": null, "description": "Process Variable prefix", @@ -545,12 +818,6 @@ "description": "low operating range", "title": "Lopr", "type": "number" - }, - "type": { - "const": "PT100.PT100", - "default": "PT100.PT100", - "description": "The type of this entity", - "title": "Type" } }, "title": "PT100_PT100", @@ -559,6 +826,18 @@ "TimingTemplates_DefaultEVR": { "additionalProperties": false, "properties": { + "type": { + "const": "TimingTemplates.DefaultEVR", + "default": "TimingTemplates.DefaultEVR", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "device": { "default": null, "description": "The device PV prefix", @@ -566,22 +845,19 @@ "type": "string" }, "event_receiver": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "reference to EventReceiverPMC entry", - "title": "Event Receiver", - "type": "string" + "description": "reference to EventReceiverPMC entry" }, "er": { "default": "SET-ER", "description": "Event Receiver record suffix", "title": "Er", "type": "string" - }, - "type": { - "const": "TimingTemplates.DefaultEVR", - "default": "TimingTemplates.DefaultEVR", - "description": "The type of this entity", - "title": "Type" } }, "title": "TimingTemplates_DefaultEVR", @@ -590,17 +866,26 @@ "TimingTemplates_EvrAlive": { "additionalProperties": false, "properties": { - "default_evr": { - "default": null, - "description": "reference to DefaultEVR entry", - "title": "Default Evr", - "type": "string" - }, "type": { "const": "TimingTemplates.EvrAlive", "default": "TimingTemplates.EvrAlive", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "default_evr": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], + "default": null, + "description": "reference to DefaultEVR entry" } }, "title": "TimingTemplates_EvrAlive", @@ -609,6 +894,18 @@ "TimingTemplates_GeneralTime": { "additionalProperties": false, "properties": { + "type": { + "const": "TimingTemplates.GeneralTime", + "default": "TimingTemplates.GeneralTime", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "device": { "default": null, "description": "device name", @@ -626,12 +923,6 @@ "description": "scan rate", "title": "Scan", "type": "string" - }, - "type": { - "const": "TimingTemplates.GeneralTime", - "default": "TimingTemplates.GeneralTime", - "description": "The type of this entity", - "title": "Type" } }, "title": "TimingTemplates_GeneralTime", @@ -640,6 +931,18 @@ "asyn_AsynIP": { "additionalProperties": false, "properties": { + "type": { + "const": "asyn.AsynIP", + "default": "asyn.AsynIP", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "port": { "default": null, "description": "Serial port tty name / IP address optionally followed by protocol", @@ -687,12 +990,6 @@ "description": "IP port to connect to if in simulation mode", "title": "Simulation", "type": "string" - }, - "type": { - "const": "asyn.AsynIP", - "default": "asyn.AsynIP", - "description": "The type of this entity", - "title": "Type" } }, "title": "asyn_AsynIP", @@ -701,6 +998,18 @@ "asyn_AsynSerial": { "additionalProperties": false, "properties": { + "type": { + "const": "asyn.AsynSerial", + "default": "asyn.AsynSerial", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "port": { "default": null, "description": "The port name for this asyn object", @@ -772,12 +1081,6 @@ "description": "Set hardware flow control on", "title": "Crtscts", "type": "boolean" - }, - "type": { - "const": "asyn.AsynSerial", - "default": "asyn.AsynSerial", - "description": "The type of this entity", - "title": "Type" } }, "title": "asyn_AsynSerial", @@ -786,17 +1089,23 @@ "devIocStats_IocAdminSoft": { "additionalProperties": false, "properties": { - "ioc": { - "default": null, - "description": "Device Prefix for this IOC", - "title": "Ioc", - "type": "string" - }, "type": { "const": "devIocStats.IocAdminSoft", "default": "devIocStats.IocAdminSoft", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "ioc": { + "default": null, + "description": "Device Prefix for this IOC", + "title": "Ioc", + "type": "string" } }, "title": "devIocStats_IocAdminSoft", @@ -805,6 +1114,18 @@ "epics_Dbpf": { "additionalProperties": false, "properties": { + "type": { + "const": "epics.Dbpf", + "default": "epics.Dbpf", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "pv": { "default": null, "description": "Name of PV", @@ -816,12 +1137,6 @@ "description": "Value to set", "title": "Value", "type": "string" - }, - "type": { - "const": "epics.Dbpf", - "default": "epics.Dbpf", - "description": "The type of this entity", - "title": "Type" } }, "title": "epics_Dbpf", @@ -830,17 +1145,23 @@ "epics_EpicsCaMaxArrayBytes": { "additionalProperties": false, "properties": { - "max_bytes": { - "default": 6000000, - "description": "Max size in bytes for sending arrays over channel access", - "title": "Max Bytes", - "type": "integer" - }, "type": { "const": "epics.EpicsCaMaxArrayBytes", "default": "epics.EpicsCaMaxArrayBytes", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "max_bytes": { + "default": 6000000, + "description": "Max size in bytes for sending arrays over channel access", + "title": "Max Bytes", + "type": "integer" } }, "title": "epics_EpicsCaMaxArrayBytes", @@ -849,6 +1170,18 @@ "epics_EpicsEnvSet": { "additionalProperties": false, "properties": { + "type": { + "const": "epics.EpicsEnvSet", + "default": "epics.EpicsEnvSet", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Name of environment variable", @@ -860,12 +1193,6 @@ "description": "Value of environment variable", "title": "Value", "type": "string" - }, - "type": { - "const": "epics.EpicsEnvSet", - "default": "epics.EpicsEnvSet", - "description": "The type of this entity", - "title": "Type" } }, "title": "epics_EpicsEnvSet", @@ -874,17 +1201,23 @@ "epics_EpicsTsMinWest": { "additionalProperties": false, "properties": { - "minutes_west": { - "default": 0, - "description": "relative time zone minutes", - "title": "Minutes West", - "type": "integer" - }, "type": { "const": "epics.EpicsTsMinWest", "default": "epics.EpicsTsMinWest", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "minutes_west": { + "default": 0, + "description": "relative time zone minutes", + "title": "Minutes West", + "type": "integer" } }, "title": "epics_EpicsTsMinWest", @@ -893,6 +1226,18 @@ "epics_InterruptVectorVME": { "additionalProperties": false, "properties": { + "type": { + "const": "epics.InterruptVectorVME", + "default": "epics.InterruptVectorVME", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "A name for an interrupt vector variable", @@ -900,16 +1245,10 @@ "type": "string" }, "count": { - "default": 1, - "description": "The number of interrupt vectors to reserve", - "title": "Count", - "type": "integer" - }, - "type": { - "const": "epics.InterruptVectorVME", - "default": "epics.InterruptVectorVME", - "description": "The type of this entity", - "title": "Type" + "default": 1, + "description": "The number of interrupt vectors to reserve", + "title": "Count", + "type": "integer" } }, "title": "epics_InterruptVectorVME", @@ -918,17 +1257,23 @@ "epics_PostStartupCommand": { "additionalProperties": false, "properties": { - "command": { - "default": "", - "description": "command string", - "title": "Command", - "type": "string" - }, "type": { "const": "epics.PostStartupCommand", "default": "epics.PostStartupCommand", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" } }, "title": "epics_PostStartupCommand", @@ -937,17 +1282,23 @@ "epics_StartupCommand": { "additionalProperties": false, "properties": { - "command": { - "default": "", - "description": "command string", - "title": "Command", - "type": "string" - }, "type": { "const": "epics.StartupCommand", "default": "epics.StartupCommand", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" } }, "title": "epics_StartupCommand", @@ -956,6 +1307,18 @@ "ipac_Hy8002": { "additionalProperties": false, "properties": { + "type": { + "const": "ipac.Hy8002", + "default": "ipac.Hy8002", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "IPAC identifier (suggested: IPAC)", @@ -973,12 +1336,6 @@ "description": "Interrupt level", "title": "Int Level", "type": "integer" - }, - "type": { - "const": "ipac.Hy8002", - "default": "ipac.Hy8002", - "description": "The type of this entity", - "title": "Type" } }, "title": "ipac_Hy8002", @@ -987,17 +1344,23 @@ "mrfTiming_EventReceiverInit": { "additionalProperties": false, "properties": { - "priority": { - "default": 10, - "description": "Time provider priority", - "title": "Priority", - "type": "integer" - }, "type": { "const": "mrfTiming.EventReceiverInit", "default": "mrfTiming.EventReceiverInit", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "priority": { + "default": 10, + "description": "Time provider priority", + "title": "Priority", + "type": "integer" } }, "title": "mrfTiming_EventReceiverInit", @@ -1006,6 +1369,18 @@ "mrfTiming_EventReceiverPMC": { "additionalProperties": false, "properties": { + "type": { + "const": "mrfTiming.EventReceiverPMC", + "default": "mrfTiming.EventReceiverPMC", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "A name to reference this EVR", @@ -1023,12 +1398,6 @@ "description": "PMC slot number", "title": "Card Index", "type": "integer" - }, - "type": { - "const": "mrfTiming.EventReceiverPMC", - "default": "mrfTiming.EventReceiverPMC", - "description": "The type of this entity", - "title": "Type" } }, "title": "mrfTiming_EventReceiverPMC", @@ -1037,6 +1406,18 @@ "pmac_CS": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.CS", + "default": "pmac.CS", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name for this object", @@ -1044,10 +1425,13 @@ "type": "string" }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "the PMAC Controller", - "title": "Controller", - "type": "string" + "description": "the PMAC Controller" }, "CS": { "default": null, @@ -1066,12 +1450,6 @@ "description": "PROG number for CS motion", "title": "Program", "type": "integer" - }, - "type": { - "const": "pmac.CS", - "default": "pmac.CS", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_CS", @@ -1080,6 +1458,18 @@ "pmac_DlsCsPmacAsynMotor": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.DlsCsPmacAsynMotor", + "default": "pmac.DlsCsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Object name and gui association name", @@ -1087,10 +1477,13 @@ "type": "string" }, "CsController": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Coordinate system controller to attach to", - "title": "Cscontroller", - "type": "string" + "description": "Coordinate system controller to attach to" }, "axis": { "default": null, @@ -1379,12 +1772,6 @@ "description": "Set to a blank to allow this axis to have its homed", "title": "Allow Homed Set", "type": "string" - }, - "type": { - "const": "pmac.DlsCsPmacAsynMotor", - "default": "pmac.DlsCsPmacAsynMotor", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_DlsCsPmacAsynMotor", @@ -1393,6 +1780,18 @@ "pmac_DlsPmacAsynMotor": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.DlsPmacAsynMotor", + "default": "pmac.DlsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Object name and gui association name", @@ -1400,10 +1799,13 @@ "type": "string" }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "PMAC Controller to attach to", - "title": "Controller", - "type": "string" + "description": "PMAC Controller to attach to" }, "axis": { "default": null, @@ -1698,12 +2100,6 @@ "description": "not sure what this is", "title": "Rlink", "type": "string" - }, - "type": { - "const": "pmac.DlsPmacAsynMotor", - "default": "pmac.DlsPmacAsynMotor", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_DlsPmacAsynMotor", @@ -1712,6 +2108,18 @@ "pmac_Geobrick": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.Geobrick", + "default": "pmac.Geobrick", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Name to use for the geobrick's asyn port", @@ -1719,10 +2127,13 @@ "type": "string" }, "PORT": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Asyn port name for PmacAsynIPPort to connect to", - "title": "Port", - "type": "string" + "description": "Asyn port name for PmacAsynIPPort to connect to" }, "P": { "default": null, @@ -1789,12 +2200,6 @@ "description": "Name for Coordinate System Group 3", "title": "Csg4", "type": "string" - }, - "type": { - "const": "pmac.Geobrick", - "default": "pmac.Geobrick", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_Geobrick", @@ -1803,6 +2208,18 @@ "pmac_PmacAsynIPPort": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.PmacAsynIPPort", + "default": "pmac.PmacAsynIPPort", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name", @@ -1820,12 +2237,6 @@ "description": "TCP port for connection", "title": "Port", "type": "integer" - }, - "type": { - "const": "pmac.PmacAsynIPPort", - "default": "pmac.PmacAsynIPPort", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_PmacAsynIPPort", @@ -1834,6 +2245,18 @@ "pmac_PmacAsynSSHPort": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.PmacAsynSSHPort", + "default": "pmac.PmacAsynSSHPort", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name", @@ -1875,12 +2298,6 @@ "description": "No EOS used if set to 1", "title": "Noeos", "type": "integer" - }, - "type": { - "const": "pmac.PmacAsynSSHPort", - "default": "pmac.PmacAsynSSHPort", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_PmacAsynSSHPort", @@ -1889,11 +2306,26 @@ "pmac_autohome": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.autohome", + "default": "pmac.autohome", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "the PMAC Controller", - "title": "Controller", - "type": "string" + "description": "the PMAC Controller" }, "PLC": { "default": null, @@ -1960,12 +2392,6 @@ "description": "name of the fourth group of auto home axes", "title": "Grp9", "type": "string" - }, - "type": { - "const": "pmac.autohome", - "default": "pmac.autohome", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_autohome", @@ -1974,23 +2400,32 @@ "pmac_pmacDisableLimitsCheck": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.pmacDisableLimitsCheck", + "default": "pmac.pmacDisableLimitsCheck", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Geobrick on which to disable limits", - "title": "Controller", - "type": "string" + "description": "Geobrick on which to disable limits" }, "Axis": { "default": null, "description": "Axis to have limits disabled", "title": "Axis", "type": "integer" - }, - "type": { - "const": "pmac.pmacDisableLimitsCheck", - "default": "pmac.pmacDisableLimitsCheck", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_pmacDisableLimitsCheck", @@ -1999,6 +2434,18 @@ "psc_PscIpModule": { "additionalProperties": false, "properties": { + "type": { + "const": "psc.PscIpModule", + "default": "psc.PscIpModule", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "A name this IP module", @@ -2006,10 +2453,13 @@ "type": "string" }, "carrier": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "IPAC carrier name", - "title": "Carrier", - "type": "string" + "description": "IPAC carrier name" }, "ip_site_number": { "default": null, @@ -2018,22 +2468,19 @@ "type": "integer" }, "interrupt_vector": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Interrupt Vector reserved with epics.InterruptVectorVME, count=3", - "title": "Interrupt Vector", - "type": "string" + "description": "Interrupt Vector reserved with epics.InterruptVectorVME, count=3" }, "link": { "default": 0, "description": "Link number on this IP module (0 or 1)", "title": "Link", "type": "integer" - }, - "type": { - "const": "psc.PscIpModule", - "default": "psc.PscIpModule", - "description": "The type of this entity", - "title": "Type" } }, "title": "psc_PscIpModule", @@ -2042,6 +2489,18 @@ "psc_PscTemplate": { "additionalProperties": false, "properties": { + "type": { + "const": "psc.PscTemplate", + "default": "psc.PscTemplate", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "device": { "default": null, "description": "Device Name, PV Suffix", @@ -2049,10 +2508,13 @@ "type": "string" }, "ip_module": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "PscIpModule object", - "title": "Ip Module", - "type": "string" + "description": "PscIpModule object" }, "link": { "default": null, @@ -2155,12 +2617,6 @@ "description": "UNKNOWN", "title": "Icharge Adel", "type": "number" - }, - "type": { - "const": "psc.PscTemplate", - "default": "psc.PscTemplate", - "description": "The type of this entity", - "title": "Type" } }, "title": "psc_PscTemplate", @@ -2169,17 +2625,35 @@ "psc_pscHy8401Channel-BS": { "additionalProperties": false, "properties": { + "type": { + "const": "psc.pscHy8401Channel-BS", + "default": "psc.pscHy8401Channel-BS", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "card": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "8401 card identifier", - "title": "Card", - "type": "string" + "description": "8401 card identifier" }, "psc_template": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "The PSC template instance", - "title": "Psc Template", - "type": "string" + "description": "The PSC template instance" }, "channel": { "default": null, @@ -2210,12 +2684,6 @@ "description": "Archive deadband for calibrated current", "title": "Adel", "type": "number" - }, - "type": { - "const": "psc.pscHy8401Channel-BS", - "default": "psc.pscHy8401Channel-BS", - "description": "The type of this entity", - "title": "Type" } }, "title": "psc_pscHy8401Channel-BS", @@ -2240,122 +2708,9 @@ "type": "string" }, "entities": { - "default": [], "description": "List of entities this IOC instantiates", "items": { - "anyOf": [ - { - "$ref": "#/$defs/ADAravis_ADAravis" - }, - { - "$ref": "#/$defs/ADAravis_MantaG235B" - }, - { - "$ref": "#/$defs/ADAravis_Mako_G234B" - }, - { - "$ref": "#/$defs/ADCore_NDRoi" - }, - { - "$ref": "#/$defs/ADCore_NDStats" - }, - { - "$ref": "#/$defs/Hy8401ip_Hy8401ip" - }, - { - "$ref": "#/$defs/Hy8401ip_Hy8401Channel" - }, - { - "$ref": "#/$defs/Hy8403ip_Hy8403ip" - }, - { - "$ref": "#/$defs/Hy8403ip_Hy8403Channel" - }, - { - "$ref": "#/$defs/PT100_PT100" - }, - { - "$ref": "#/$defs/TimingTemplates_DefaultEVR" - }, - { - "$ref": "#/$defs/TimingTemplates_EvrAlive" - }, - { - "$ref": "#/$defs/TimingTemplates_GeneralTime" - }, - { - "$ref": "#/$defs/devIocStats_IocAdminSoft" - }, - { - "$ref": "#/$defs/epics_EpicsCaMaxArrayBytes" - }, - { - "$ref": "#/$defs/epics_EpicsTsMinWest" - }, - { - "$ref": "#/$defs/epics_Dbpf" - }, - { - "$ref": "#/$defs/epics_EpicsEnvSet" - }, - { - "$ref": "#/$defs/epics_StartupCommand" - }, - { - "$ref": "#/$defs/epics_PostStartupCommand" - }, - { - "$ref": "#/$defs/epics_InterruptVectorVME" - }, - { - "$ref": "#/$defs/asyn_AsynSerial" - }, - { - "$ref": "#/$defs/asyn_AsynIP" - }, - { - "$ref": "#/$defs/ipac_Hy8002" - }, - { - "$ref": "#/$defs/mrfTiming_EventReceiverInit" - }, - { - "$ref": "#/$defs/mrfTiming_EventReceiverPMC" - }, - { - "$ref": "#/$defs/pmac_PmacAsynSSHPort" - }, - { - "$ref": "#/$defs/pmac_PmacAsynIPPort" - }, - { - "$ref": "#/$defs/pmac_Geobrick" - }, - { - "$ref": "#/$defs/pmac_DlsPmacAsynMotor" - }, - { - "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" - }, - { - "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" - }, - { - "$ref": "#/$defs/pmac_autohome" - }, - { - "$ref": "#/$defs/pmac_CS" - }, - { - "$ref": "#/$defs/psc_PscIpModule" - }, - { - "$ref": "#/$defs/psc_PscTemplate" - }, - { - "$ref": "#/$defs/psc_pscHy8401Channel-BS" - } - ] + "$ref": "#/$defs/EntityModel" }, "title": "Entities", "type": "array" @@ -2364,7 +2719,8 @@ "required": [ "ioc_name", "description", - "generic_ioc_image" + "generic_ioc_image", + "entities" ], "title": "NewIOC", "type": "object" diff --git a/tests/samples/schemas/asyn.ibek.entities.schema.json b/tests/samples/schemas/asyn.ibek.entities.schema.json index c9c077781..98f11a285 100644 --- a/tests/samples/schemas/asyn.ibek.entities.schema.json +++ b/tests/samples/schemas/asyn.ibek.entities.schema.json @@ -1,8 +1,38 @@ { "$defs": { + "EntityModel": { + "discriminator": { + "mapping": { + "asyn.AsynIP": "#/$defs/asyn_AsynIP", + "asyn.AsynSerial": "#/$defs/asyn_AsynSerial" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/asyn_AsynSerial" + }, + { + "$ref": "#/$defs/asyn_AsynIP" + } + ], + "title": "EntityModel" + }, "asyn_AsynIP": { "additionalProperties": false, "properties": { + "type": { + "const": "asyn.AsynIP", + "default": "asyn.AsynIP", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "port": { "default": null, "description": "Serial port tty name / IP address optionally followed by protocol", @@ -50,12 +80,6 @@ "description": "IP port to connect to if in simulation mode", "title": "Simulation", "type": "string" - }, - "type": { - "const": "asyn.AsynIP", - "default": "asyn.AsynIP", - "description": "The type of this entity", - "title": "Type" } }, "title": "asyn_AsynIP", @@ -64,6 +88,18 @@ "asyn_AsynSerial": { "additionalProperties": false, "properties": { + "type": { + "const": "asyn.AsynSerial", + "default": "asyn.AsynSerial", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "port": { "default": null, "description": "The port name for this asyn object", @@ -135,12 +171,6 @@ "description": "Set hardware flow control on", "title": "Crtscts", "type": "boolean" - }, - "type": { - "const": "asyn.AsynSerial", - "default": "asyn.AsynSerial", - "description": "The type of this entity", - "title": "Type" } }, "title": "asyn_AsynSerial", @@ -165,17 +195,9 @@ "type": "string" }, "entities": { - "default": [], "description": "List of entities this IOC instantiates", "items": { - "anyOf": [ - { - "$ref": "#/$defs/asyn_AsynSerial" - }, - { - "$ref": "#/$defs/asyn_AsynIP" - } - ] + "$ref": "#/$defs/EntityModel" }, "title": "Entities", "type": "array" @@ -184,7 +206,8 @@ "required": [ "ioc_name", "description", - "generic_ioc_image" + "generic_ioc_image", + "entities" ], "title": "NewIOC", "type": "object" diff --git a/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json b/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json index 3427a8ea2..88cfe8705 100644 --- a/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json +++ b/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json @@ -1,8 +1,112 @@ { "$defs": { + "Entity": { + "additionalProperties": false, + "description": "\n A baseclass for all generated Entity classes. Provides the\n deserialize entry point.\n ", + "properties": { + "type": { + "description": "The type of this entity", + "title": "Type", + "type": "string" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + } + }, + "required": [ + "type" + ], + "title": "Entity", + "type": "object" + }, + "EntityModel": { + "discriminator": { + "mapping": { + "epics.Dbpf": "#/$defs/epics_Dbpf", + "epics.EpicsCaMaxArrayBytes": "#/$defs/epics_EpicsCaMaxArrayBytes", + "epics.EpicsEnvSet": "#/$defs/epics_EpicsEnvSet", + "epics.EpicsTsMinWest": "#/$defs/epics_EpicsTsMinWest", + "epics.InterruptVectorVME": "#/$defs/epics_InterruptVectorVME", + "epics.PostStartupCommand": "#/$defs/epics_PostStartupCommand", + "epics.StartupCommand": "#/$defs/epics_StartupCommand", + "pmac.CS": "#/$defs/pmac_CS", + "pmac.DlsCsPmacAsynMotor": "#/$defs/pmac_DlsCsPmacAsynMotor", + "pmac.DlsPmacAsynMotor": "#/$defs/pmac_DlsPmacAsynMotor", + "pmac.Geobrick": "#/$defs/pmac_Geobrick", + "pmac.PmacAsynIPPort": "#/$defs/pmac_PmacAsynIPPort", + "pmac.PmacAsynSSHPort": "#/$defs/pmac_PmacAsynSSHPort", + "pmac.autohome": "#/$defs/pmac_autohome", + "pmac.pmacDisableLimitsCheck": "#/$defs/pmac_pmacDisableLimitsCheck" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/epics_EpicsCaMaxArrayBytes" + }, + { + "$ref": "#/$defs/epics_EpicsTsMinWest" + }, + { + "$ref": "#/$defs/epics_Dbpf" + }, + { + "$ref": "#/$defs/epics_EpicsEnvSet" + }, + { + "$ref": "#/$defs/epics_StartupCommand" + }, + { + "$ref": "#/$defs/epics_PostStartupCommand" + }, + { + "$ref": "#/$defs/epics_InterruptVectorVME" + }, + { + "$ref": "#/$defs/pmac_PmacAsynSSHPort" + }, + { + "$ref": "#/$defs/pmac_PmacAsynIPPort" + }, + { + "$ref": "#/$defs/pmac_Geobrick" + }, + { + "$ref": "#/$defs/pmac_DlsPmacAsynMotor" + }, + { + "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" + }, + { + "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" + }, + { + "$ref": "#/$defs/pmac_autohome" + }, + { + "$ref": "#/$defs/pmac_CS" + } + ], + "title": "EntityModel" + }, "epics_Dbpf": { "additionalProperties": false, "properties": { + "type": { + "const": "epics.Dbpf", + "default": "epics.Dbpf", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "pv": { "default": null, "description": "Name of PV", @@ -14,12 +118,6 @@ "description": "Value to set", "title": "Value", "type": "string" - }, - "type": { - "const": "epics.Dbpf", - "default": "epics.Dbpf", - "description": "The type of this entity", - "title": "Type" } }, "title": "epics_Dbpf", @@ -28,17 +126,23 @@ "epics_EpicsCaMaxArrayBytes": { "additionalProperties": false, "properties": { - "max_bytes": { - "default": 6000000, - "description": "Max size in bytes for sending arrays over channel access", - "title": "Max Bytes", - "type": "integer" - }, "type": { "const": "epics.EpicsCaMaxArrayBytes", "default": "epics.EpicsCaMaxArrayBytes", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "max_bytes": { + "default": 6000000, + "description": "Max size in bytes for sending arrays over channel access", + "title": "Max Bytes", + "type": "integer" } }, "title": "epics_EpicsCaMaxArrayBytes", @@ -47,6 +151,18 @@ "epics_EpicsEnvSet": { "additionalProperties": false, "properties": { + "type": { + "const": "epics.EpicsEnvSet", + "default": "epics.EpicsEnvSet", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Name of environment variable", @@ -58,12 +174,6 @@ "description": "Value of environment variable", "title": "Value", "type": "string" - }, - "type": { - "const": "epics.EpicsEnvSet", - "default": "epics.EpicsEnvSet", - "description": "The type of this entity", - "title": "Type" } }, "title": "epics_EpicsEnvSet", @@ -72,17 +182,23 @@ "epics_EpicsTsMinWest": { "additionalProperties": false, "properties": { - "minutes_west": { - "default": 0, - "description": "relative time zone minutes", - "title": "Minutes West", - "type": "integer" - }, "type": { "const": "epics.EpicsTsMinWest", "default": "epics.EpicsTsMinWest", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "minutes_west": { + "default": 0, + "description": "relative time zone minutes", + "title": "Minutes West", + "type": "integer" } }, "title": "epics_EpicsTsMinWest", @@ -91,6 +207,18 @@ "epics_InterruptVectorVME": { "additionalProperties": false, "properties": { + "type": { + "const": "epics.InterruptVectorVME", + "default": "epics.InterruptVectorVME", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "A name for an interrupt vector variable", @@ -102,12 +230,6 @@ "description": "The number of interrupt vectors to reserve", "title": "Count", "type": "integer" - }, - "type": { - "const": "epics.InterruptVectorVME", - "default": "epics.InterruptVectorVME", - "description": "The type of this entity", - "title": "Type" } }, "title": "epics_InterruptVectorVME", @@ -116,17 +238,23 @@ "epics_PostStartupCommand": { "additionalProperties": false, "properties": { - "command": { - "default": "", - "description": "command string", - "title": "Command", - "type": "string" - }, "type": { "const": "epics.PostStartupCommand", "default": "epics.PostStartupCommand", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" } }, "title": "epics_PostStartupCommand", @@ -135,17 +263,23 @@ "epics_StartupCommand": { "additionalProperties": false, "properties": { - "command": { - "default": "", - "description": "command string", - "title": "Command", - "type": "string" - }, "type": { "const": "epics.StartupCommand", "default": "epics.StartupCommand", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" } }, "title": "epics_StartupCommand", @@ -154,6 +288,18 @@ "pmac_CS": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.CS", + "default": "pmac.CS", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name for this object", @@ -161,10 +307,13 @@ "type": "string" }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "the PMAC Controller", - "title": "Controller", - "type": "string" + "description": "the PMAC Controller" }, "CS": { "default": null, @@ -183,12 +332,6 @@ "description": "PROG number for CS motion", "title": "Program", "type": "integer" - }, - "type": { - "const": "pmac.CS", - "default": "pmac.CS", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_CS", @@ -197,6 +340,18 @@ "pmac_DlsCsPmacAsynMotor": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.DlsCsPmacAsynMotor", + "default": "pmac.DlsCsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Object name and gui association name", @@ -204,10 +359,13 @@ "type": "string" }, "CsController": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Coordinate system controller to attach to", - "title": "Cscontroller", - "type": "string" + "description": "Coordinate system controller to attach to" }, "axis": { "default": null, @@ -496,12 +654,6 @@ "description": "Set to a blank to allow this axis to have its homed", "title": "Allow Homed Set", "type": "string" - }, - "type": { - "const": "pmac.DlsCsPmacAsynMotor", - "default": "pmac.DlsCsPmacAsynMotor", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_DlsCsPmacAsynMotor", @@ -510,6 +662,18 @@ "pmac_DlsPmacAsynMotor": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.DlsPmacAsynMotor", + "default": "pmac.DlsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Object name and gui association name", @@ -517,10 +681,13 @@ "type": "string" }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "PMAC Controller to attach to", - "title": "Controller", - "type": "string" + "description": "PMAC Controller to attach to" }, "axis": { "default": null, @@ -815,12 +982,6 @@ "description": "not sure what this is", "title": "Rlink", "type": "string" - }, - "type": { - "const": "pmac.DlsPmacAsynMotor", - "default": "pmac.DlsPmacAsynMotor", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_DlsPmacAsynMotor", @@ -829,6 +990,18 @@ "pmac_Geobrick": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.Geobrick", + "default": "pmac.Geobrick", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Name to use for the geobrick's asyn port", @@ -836,10 +1009,13 @@ "type": "string" }, "PORT": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Asyn port name for PmacAsynIPPort to connect to", - "title": "Port", - "type": "string" + "description": "Asyn port name for PmacAsynIPPort to connect to" }, "P": { "default": null, @@ -906,12 +1082,6 @@ "description": "Name for Coordinate System Group 3", "title": "Csg4", "type": "string" - }, - "type": { - "const": "pmac.Geobrick", - "default": "pmac.Geobrick", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_Geobrick", @@ -920,6 +1090,18 @@ "pmac_PmacAsynIPPort": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.PmacAsynIPPort", + "default": "pmac.PmacAsynIPPort", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name", @@ -937,12 +1119,6 @@ "description": "TCP port for connection", "title": "Port", "type": "integer" - }, - "type": { - "const": "pmac.PmacAsynIPPort", - "default": "pmac.PmacAsynIPPort", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_PmacAsynIPPort", @@ -951,6 +1127,18 @@ "pmac_PmacAsynSSHPort": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.PmacAsynSSHPort", + "default": "pmac.PmacAsynSSHPort", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name", @@ -992,12 +1180,6 @@ "description": "No EOS used if set to 1", "title": "Noeos", "type": "integer" - }, - "type": { - "const": "pmac.PmacAsynSSHPort", - "default": "pmac.PmacAsynSSHPort", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_PmacAsynSSHPort", @@ -1006,11 +1188,26 @@ "pmac_autohome": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.autohome", + "default": "pmac.autohome", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "the PMAC Controller", - "title": "Controller", - "type": "string" + "description": "the PMAC Controller" }, "PLC": { "default": null, @@ -1077,12 +1274,6 @@ "description": "name of the fourth group of auto home axes", "title": "Grp9", "type": "string" - }, - "type": { - "const": "pmac.autohome", - "default": "pmac.autohome", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_autohome", @@ -1091,23 +1282,32 @@ "pmac_pmacDisableLimitsCheck": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.pmacDisableLimitsCheck", + "default": "pmac.pmacDisableLimitsCheck", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Geobrick on which to disable limits", - "title": "Controller", - "type": "string" + "description": "Geobrick on which to disable limits" }, "Axis": { "default": null, "description": "Axis to have limits disabled", "title": "Axis", "type": "integer" - }, - "type": { - "const": "pmac.pmacDisableLimitsCheck", - "default": "pmac.pmacDisableLimitsCheck", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_pmacDisableLimitsCheck", @@ -1132,56 +1332,9 @@ "type": "string" }, "entities": { - "default": [], "description": "List of entities this IOC instantiates", "items": { - "anyOf": [ - { - "$ref": "#/$defs/epics_EpicsCaMaxArrayBytes" - }, - { - "$ref": "#/$defs/epics_EpicsTsMinWest" - }, - { - "$ref": "#/$defs/epics_Dbpf" - }, - { - "$ref": "#/$defs/epics_EpicsEnvSet" - }, - { - "$ref": "#/$defs/epics_StartupCommand" - }, - { - "$ref": "#/$defs/epics_PostStartupCommand" - }, - { - "$ref": "#/$defs/epics_InterruptVectorVME" - }, - { - "$ref": "#/$defs/pmac_PmacAsynSSHPort" - }, - { - "$ref": "#/$defs/pmac_PmacAsynIPPort" - }, - { - "$ref": "#/$defs/pmac_Geobrick" - }, - { - "$ref": "#/$defs/pmac_DlsPmacAsynMotor" - }, - { - "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" - }, - { - "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" - }, - { - "$ref": "#/$defs/pmac_autohome" - }, - { - "$ref": "#/$defs/pmac_CS" - } - ] + "$ref": "#/$defs/EntityModel" }, "title": "Entities", "type": "array" @@ -1190,7 +1343,8 @@ "required": [ "ioc_name", "description", - "generic_ioc_image" + "generic_ioc_image", + "entities" ], "title": "NewIOC", "type": "object" diff --git a/tests/samples/schemas/container.ibek.entities.schema.json b/tests/samples/schemas/container.ibek.entities.schema.json index 7cf19586d..69469849f 100644 --- a/tests/samples/schemas/container.ibek.entities.schema.json +++ b/tests/samples/schemas/container.ibek.entities.schema.json @@ -1,8 +1,92 @@ { "$defs": { + "Entity": { + "additionalProperties": false, + "description": "\n A baseclass for all generated Entity classes. Provides the\n deserialize entry point.\n ", + "properties": { + "type": { + "description": "The type of this entity", + "title": "Type", + "type": "string" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + } + }, + "required": [ + "type" + ], + "title": "Entity", + "type": "object" + }, + "EntityModel": { + "discriminator": { + "mapping": { + "asyn.AsynIP": "#/$defs/asyn_AsynIP", + "asyn.AsynSerial": "#/$defs/asyn_AsynSerial", + "pmac.CS": "#/$defs/pmac_CS", + "pmac.DlsCsPmacAsynMotor": "#/$defs/pmac_DlsCsPmacAsynMotor", + "pmac.DlsPmacAsynMotor": "#/$defs/pmac_DlsPmacAsynMotor", + "pmac.Geobrick": "#/$defs/pmac_Geobrick", + "pmac.PmacAsynIPPort": "#/$defs/pmac_PmacAsynIPPort", + "pmac.PmacAsynSSHPort": "#/$defs/pmac_PmacAsynSSHPort", + "pmac.autohome": "#/$defs/pmac_autohome", + "pmac.pmacDisableLimitsCheck": "#/$defs/pmac_pmacDisableLimitsCheck" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/asyn_AsynSerial" + }, + { + "$ref": "#/$defs/asyn_AsynIP" + }, + { + "$ref": "#/$defs/pmac_PmacAsynSSHPort" + }, + { + "$ref": "#/$defs/pmac_PmacAsynIPPort" + }, + { + "$ref": "#/$defs/pmac_Geobrick" + }, + { + "$ref": "#/$defs/pmac_DlsPmacAsynMotor" + }, + { + "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" + }, + { + "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" + }, + { + "$ref": "#/$defs/pmac_autohome" + }, + { + "$ref": "#/$defs/pmac_CS" + } + ], + "title": "EntityModel" + }, "asyn_AsynIP": { "additionalProperties": false, "properties": { + "type": { + "const": "asyn.AsynIP", + "default": "asyn.AsynIP", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "port": { "default": null, "description": "Serial port tty name / IP address optionally followed by protocol", @@ -50,12 +134,6 @@ "description": "IP port to connect to if in simulation mode", "title": "Simulation", "type": "string" - }, - "type": { - "const": "asyn.AsynIP", - "default": "asyn.AsynIP", - "description": "The type of this entity", - "title": "Type" } }, "title": "asyn_AsynIP", @@ -64,6 +142,18 @@ "asyn_AsynSerial": { "additionalProperties": false, "properties": { + "type": { + "const": "asyn.AsynSerial", + "default": "asyn.AsynSerial", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "port": { "default": null, "description": "The port name for this asyn object", @@ -135,12 +225,6 @@ "description": "Set hardware flow control on", "title": "Crtscts", "type": "boolean" - }, - "type": { - "const": "asyn.AsynSerial", - "default": "asyn.AsynSerial", - "description": "The type of this entity", - "title": "Type" } }, "title": "asyn_AsynSerial", @@ -149,6 +233,18 @@ "pmac_CS": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.CS", + "default": "pmac.CS", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name for this object", @@ -156,10 +252,13 @@ "type": "string" }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "the PMAC Controller", - "title": "Controller", - "type": "string" + "description": "the PMAC Controller" }, "CS": { "default": null, @@ -178,12 +277,6 @@ "description": "PROG number for CS motion", "title": "Program", "type": "integer" - }, - "type": { - "const": "pmac.CS", - "default": "pmac.CS", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_CS", @@ -192,6 +285,18 @@ "pmac_DlsCsPmacAsynMotor": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.DlsCsPmacAsynMotor", + "default": "pmac.DlsCsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Object name and gui association name", @@ -199,10 +304,13 @@ "type": "string" }, "CsController": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Coordinate system controller to attach to", - "title": "Cscontroller", - "type": "string" + "description": "Coordinate system controller to attach to" }, "axis": { "default": null, @@ -491,12 +599,6 @@ "description": "Set to a blank to allow this axis to have its homed", "title": "Allow Homed Set", "type": "string" - }, - "type": { - "const": "pmac.DlsCsPmacAsynMotor", - "default": "pmac.DlsCsPmacAsynMotor", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_DlsCsPmacAsynMotor", @@ -505,6 +607,18 @@ "pmac_DlsPmacAsynMotor": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.DlsPmacAsynMotor", + "default": "pmac.DlsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Object name and gui association name", @@ -512,10 +626,13 @@ "type": "string" }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "PMAC Controller to attach to", - "title": "Controller", - "type": "string" + "description": "PMAC Controller to attach to" }, "axis": { "default": null, @@ -810,12 +927,6 @@ "description": "not sure what this is", "title": "Rlink", "type": "string" - }, - "type": { - "const": "pmac.DlsPmacAsynMotor", - "default": "pmac.DlsPmacAsynMotor", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_DlsPmacAsynMotor", @@ -824,6 +935,18 @@ "pmac_Geobrick": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.Geobrick", + "default": "pmac.Geobrick", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Name to use for the geobrick's asyn port", @@ -831,10 +954,13 @@ "type": "string" }, "PORT": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Asyn port name for PmacAsynIPPort to connect to", - "title": "Port", - "type": "string" + "description": "Asyn port name for PmacAsynIPPort to connect to" }, "P": { "default": null, @@ -901,12 +1027,6 @@ "description": "Name for Coordinate System Group 3", "title": "Csg4", "type": "string" - }, - "type": { - "const": "pmac.Geobrick", - "default": "pmac.Geobrick", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_Geobrick", @@ -915,6 +1035,18 @@ "pmac_PmacAsynIPPort": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.PmacAsynIPPort", + "default": "pmac.PmacAsynIPPort", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name", @@ -932,12 +1064,6 @@ "description": "TCP port for connection", "title": "Port", "type": "integer" - }, - "type": { - "const": "pmac.PmacAsynIPPort", - "default": "pmac.PmacAsynIPPort", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_PmacAsynIPPort", @@ -946,6 +1072,18 @@ "pmac_PmacAsynSSHPort": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.PmacAsynSSHPort", + "default": "pmac.PmacAsynSSHPort", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name", @@ -987,12 +1125,6 @@ "description": "No EOS used if set to 1", "title": "Noeos", "type": "integer" - }, - "type": { - "const": "pmac.PmacAsynSSHPort", - "default": "pmac.PmacAsynSSHPort", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_PmacAsynSSHPort", @@ -1001,11 +1133,26 @@ "pmac_autohome": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.autohome", + "default": "pmac.autohome", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "the PMAC Controller", - "title": "Controller", - "type": "string" + "description": "the PMAC Controller" }, "PLC": { "default": null, @@ -1072,12 +1219,6 @@ "description": "name of the fourth group of auto home axes", "title": "Grp9", "type": "string" - }, - "type": { - "const": "pmac.autohome", - "default": "pmac.autohome", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_autohome", @@ -1086,23 +1227,32 @@ "pmac_pmacDisableLimitsCheck": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.pmacDisableLimitsCheck", + "default": "pmac.pmacDisableLimitsCheck", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Geobrick on which to disable limits", - "title": "Controller", - "type": "string" + "description": "Geobrick on which to disable limits" }, "Axis": { "default": null, "description": "Axis to have limits disabled", "title": "Axis", "type": "integer" - }, - "type": { - "const": "pmac.pmacDisableLimitsCheck", - "default": "pmac.pmacDisableLimitsCheck", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_pmacDisableLimitsCheck", @@ -1127,41 +1277,9 @@ "type": "string" }, "entities": { - "default": [], "description": "List of entities this IOC instantiates", "items": { - "anyOf": [ - { - "$ref": "#/$defs/asyn_AsynSerial" - }, - { - "$ref": "#/$defs/asyn_AsynIP" - }, - { - "$ref": "#/$defs/pmac_PmacAsynSSHPort" - }, - { - "$ref": "#/$defs/pmac_PmacAsynIPPort" - }, - { - "$ref": "#/$defs/pmac_Geobrick" - }, - { - "$ref": "#/$defs/pmac_DlsPmacAsynMotor" - }, - { - "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" - }, - { - "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" - }, - { - "$ref": "#/$defs/pmac_autohome" - }, - { - "$ref": "#/$defs/pmac_CS" - } - ] + "$ref": "#/$defs/EntityModel" }, "title": "Entities", "type": "array" @@ -1170,7 +1288,8 @@ "required": [ "ioc_name", "description", - "generic_ioc_image" + "generic_ioc_image", + "entities" ], "title": "NewIOC", "type": "object" diff --git a/tests/samples/schemas/epics.ibek.support.schema.json b/tests/samples/schemas/epics.ibek.support.schema.json index cf10e6ba5..7e99f5ba5 100644 --- a/tests/samples/schemas/epics.ibek.support.schema.json +++ b/tests/samples/schemas/epics.ibek.support.schema.json @@ -1,8 +1,58 @@ { "$defs": { + "EntityModel": { + "discriminator": { + "mapping": { + "epics.Dbpf": "#/$defs/epics_Dbpf", + "epics.EpicsCaMaxArrayBytes": "#/$defs/epics_EpicsCaMaxArrayBytes", + "epics.EpicsEnvSet": "#/$defs/epics_EpicsEnvSet", + "epics.EpicsTsMinWest": "#/$defs/epics_EpicsTsMinWest", + "epics.InterruptVectorVME": "#/$defs/epics_InterruptVectorVME", + "epics.PostStartupCommand": "#/$defs/epics_PostStartupCommand", + "epics.StartupCommand": "#/$defs/epics_StartupCommand" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/epics_EpicsCaMaxArrayBytes" + }, + { + "$ref": "#/$defs/epics_EpicsTsMinWest" + }, + { + "$ref": "#/$defs/epics_Dbpf" + }, + { + "$ref": "#/$defs/epics_EpicsEnvSet" + }, + { + "$ref": "#/$defs/epics_StartupCommand" + }, + { + "$ref": "#/$defs/epics_PostStartupCommand" + }, + { + "$ref": "#/$defs/epics_InterruptVectorVME" + } + ], + "title": "EntityModel" + }, "epics_Dbpf": { "additionalProperties": false, "properties": { + "type": { + "const": "epics.Dbpf", + "default": "epics.Dbpf", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "pv": { "default": null, "description": "Name of PV", @@ -14,12 +64,6 @@ "description": "Value to set", "title": "Value", "type": "string" - }, - "type": { - "const": "epics.Dbpf", - "default": "epics.Dbpf", - "description": "The type of this entity", - "title": "Type" } }, "title": "epics_Dbpf", @@ -28,17 +72,23 @@ "epics_EpicsCaMaxArrayBytes": { "additionalProperties": false, "properties": { - "max_bytes": { - "default": 6000000, - "description": "Max size in bytes for sending arrays over channel access", - "title": "Max Bytes", - "type": "integer" - }, "type": { "const": "epics.EpicsCaMaxArrayBytes", "default": "epics.EpicsCaMaxArrayBytes", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "max_bytes": { + "default": 6000000, + "description": "Max size in bytes for sending arrays over channel access", + "title": "Max Bytes", + "type": "integer" } }, "title": "epics_EpicsCaMaxArrayBytes", @@ -47,6 +97,18 @@ "epics_EpicsEnvSet": { "additionalProperties": false, "properties": { + "type": { + "const": "epics.EpicsEnvSet", + "default": "epics.EpicsEnvSet", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Name of environment variable", @@ -58,12 +120,6 @@ "description": "Value of environment variable", "title": "Value", "type": "string" - }, - "type": { - "const": "epics.EpicsEnvSet", - "default": "epics.EpicsEnvSet", - "description": "The type of this entity", - "title": "Type" } }, "title": "epics_EpicsEnvSet", @@ -72,17 +128,23 @@ "epics_EpicsTsMinWest": { "additionalProperties": false, "properties": { - "minutes_west": { - "default": 0, - "description": "relative time zone minutes", - "title": "Minutes West", - "type": "integer" - }, "type": { "const": "epics.EpicsTsMinWest", "default": "epics.EpicsTsMinWest", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "minutes_west": { + "default": 0, + "description": "relative time zone minutes", + "title": "Minutes West", + "type": "integer" } }, "title": "epics_EpicsTsMinWest", @@ -91,6 +153,18 @@ "epics_InterruptVectorVME": { "additionalProperties": false, "properties": { + "type": { + "const": "epics.InterruptVectorVME", + "default": "epics.InterruptVectorVME", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "A name for an interrupt vector variable", @@ -102,12 +176,6 @@ "description": "The number of interrupt vectors to reserve", "title": "Count", "type": "integer" - }, - "type": { - "const": "epics.InterruptVectorVME", - "default": "epics.InterruptVectorVME", - "description": "The type of this entity", - "title": "Type" } }, "title": "epics_InterruptVectorVME", @@ -116,17 +184,23 @@ "epics_PostStartupCommand": { "additionalProperties": false, "properties": { - "command": { - "default": "", - "description": "command string", - "title": "Command", - "type": "string" - }, "type": { "const": "epics.PostStartupCommand", "default": "epics.PostStartupCommand", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" } }, "title": "epics_PostStartupCommand", @@ -135,17 +209,23 @@ "epics_StartupCommand": { "additionalProperties": false, "properties": { - "command": { - "default": "", - "description": "command string", - "title": "Command", - "type": "string" - }, "type": { "const": "epics.StartupCommand", "default": "epics.StartupCommand", "description": "The type of this entity", "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "command": { + "default": "", + "description": "command string", + "title": "Command", + "type": "string" } }, "title": "epics_StartupCommand", @@ -170,32 +250,9 @@ "type": "string" }, "entities": { - "default": [], "description": "List of entities this IOC instantiates", "items": { - "anyOf": [ - { - "$ref": "#/$defs/epics_EpicsCaMaxArrayBytes" - }, - { - "$ref": "#/$defs/epics_EpicsTsMinWest" - }, - { - "$ref": "#/$defs/epics_Dbpf" - }, - { - "$ref": "#/$defs/epics_EpicsEnvSet" - }, - { - "$ref": "#/$defs/epics_StartupCommand" - }, - { - "$ref": "#/$defs/epics_PostStartupCommand" - }, - { - "$ref": "#/$defs/epics_InterruptVectorVME" - } - ] + "$ref": "#/$defs/EntityModel" }, "title": "Entities", "type": "array" @@ -204,7 +261,8 @@ "required": [ "ioc_name", "description", - "generic_ioc_image" + "generic_ioc_image", + "entities" ], "title": "NewIOC", "type": "object" diff --git a/tests/samples/schemas/pmac.ibek.entities.schema.json b/tests/samples/schemas/pmac.ibek.entities.schema.json index 1a55d5f35..290392d86 100644 --- a/tests/samples/schemas/pmac.ibek.entities.schema.json +++ b/tests/samples/schemas/pmac.ibek.entities.schema.json @@ -1,8 +1,84 @@ { "$defs": { + "Entity": { + "additionalProperties": false, + "description": "\n A baseclass for all generated Entity classes. Provides the\n deserialize entry point.\n ", + "properties": { + "type": { + "description": "The type of this entity", + "title": "Type", + "type": "string" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + } + }, + "required": [ + "type" + ], + "title": "Entity", + "type": "object" + }, + "EntityModel": { + "discriminator": { + "mapping": { + "pmac.CS": "#/$defs/pmac_CS", + "pmac.DlsCsPmacAsynMotor": "#/$defs/pmac_DlsCsPmacAsynMotor", + "pmac.DlsPmacAsynMotor": "#/$defs/pmac_DlsPmacAsynMotor", + "pmac.Geobrick": "#/$defs/pmac_Geobrick", + "pmac.PmacAsynIPPort": "#/$defs/pmac_PmacAsynIPPort", + "pmac.PmacAsynSSHPort": "#/$defs/pmac_PmacAsynSSHPort", + "pmac.autohome": "#/$defs/pmac_autohome", + "pmac.pmacDisableLimitsCheck": "#/$defs/pmac_pmacDisableLimitsCheck" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/pmac_PmacAsynSSHPort" + }, + { + "$ref": "#/$defs/pmac_PmacAsynIPPort" + }, + { + "$ref": "#/$defs/pmac_Geobrick" + }, + { + "$ref": "#/$defs/pmac_DlsPmacAsynMotor" + }, + { + "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" + }, + { + "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" + }, + { + "$ref": "#/$defs/pmac_autohome" + }, + { + "$ref": "#/$defs/pmac_CS" + } + ], + "title": "EntityModel" + }, "pmac_CS": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.CS", + "default": "pmac.CS", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name for this object", @@ -10,10 +86,13 @@ "type": "string" }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "the PMAC Controller", - "title": "Controller", - "type": "string" + "description": "the PMAC Controller" }, "CS": { "default": null, @@ -32,12 +111,6 @@ "description": "PROG number for CS motion", "title": "Program", "type": "integer" - }, - "type": { - "const": "pmac.CS", - "default": "pmac.CS", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_CS", @@ -46,6 +119,18 @@ "pmac_DlsCsPmacAsynMotor": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.DlsCsPmacAsynMotor", + "default": "pmac.DlsCsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Object name and gui association name", @@ -53,10 +138,13 @@ "type": "string" }, "CsController": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Coordinate system controller to attach to", - "title": "Cscontroller", - "type": "string" + "description": "Coordinate system controller to attach to" }, "axis": { "default": null, @@ -345,12 +433,6 @@ "description": "Set to a blank to allow this axis to have its homed", "title": "Allow Homed Set", "type": "string" - }, - "type": { - "const": "pmac.DlsCsPmacAsynMotor", - "default": "pmac.DlsCsPmacAsynMotor", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_DlsCsPmacAsynMotor", @@ -359,6 +441,18 @@ "pmac_DlsPmacAsynMotor": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.DlsPmacAsynMotor", + "default": "pmac.DlsPmacAsynMotor", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Object name and gui association name", @@ -366,10 +460,13 @@ "type": "string" }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "PMAC Controller to attach to", - "title": "Controller", - "type": "string" + "description": "PMAC Controller to attach to" }, "axis": { "default": null, @@ -664,12 +761,6 @@ "description": "not sure what this is", "title": "Rlink", "type": "string" - }, - "type": { - "const": "pmac.DlsPmacAsynMotor", - "default": "pmac.DlsPmacAsynMotor", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_DlsPmacAsynMotor", @@ -678,6 +769,18 @@ "pmac_Geobrick": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.Geobrick", + "default": "pmac.Geobrick", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Name to use for the geobrick's asyn port", @@ -685,10 +788,13 @@ "type": "string" }, "PORT": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Asyn port name for PmacAsynIPPort to connect to", - "title": "Port", - "type": "string" + "description": "Asyn port name for PmacAsynIPPort to connect to" }, "P": { "default": null, @@ -755,12 +861,6 @@ "description": "Name for Coordinate System Group 3", "title": "Csg4", "type": "string" - }, - "type": { - "const": "pmac.Geobrick", - "default": "pmac.Geobrick", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_Geobrick", @@ -769,6 +869,18 @@ "pmac_PmacAsynIPPort": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.PmacAsynIPPort", + "default": "pmac.PmacAsynIPPort", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name", @@ -786,12 +898,6 @@ "description": "TCP port for connection", "title": "Port", "type": "integer" - }, - "type": { - "const": "pmac.PmacAsynIPPort", - "default": "pmac.PmacAsynIPPort", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_PmacAsynIPPort", @@ -800,6 +906,18 @@ "pmac_PmacAsynSSHPort": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.PmacAsynSSHPort", + "default": "pmac.PmacAsynSSHPort", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "name": { "default": null, "description": "Asyn port name", @@ -841,12 +959,6 @@ "description": "No EOS used if set to 1", "title": "Noeos", "type": "integer" - }, - "type": { - "const": "pmac.PmacAsynSSHPort", - "default": "pmac.PmacAsynSSHPort", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_PmacAsynSSHPort", @@ -855,11 +967,26 @@ "pmac_autohome": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.autohome", + "default": "pmac.autohome", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "the PMAC Controller", - "title": "Controller", - "type": "string" + "description": "the PMAC Controller" }, "PLC": { "default": null, @@ -926,12 +1053,6 @@ "description": "name of the fourth group of auto home axes", "title": "Grp9", "type": "string" - }, - "type": { - "const": "pmac.autohome", - "default": "pmac.autohome", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_autohome", @@ -940,23 +1061,32 @@ "pmac_pmacDisableLimitsCheck": { "additionalProperties": false, "properties": { + "type": { + "const": "pmac.pmacDisableLimitsCheck", + "default": "pmac.pmacDisableLimitsCheck", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, "Controller": { + "allOf": [ + { + "$ref": "#/$defs/Entity" + } + ], "default": null, - "description": "Geobrick on which to disable limits", - "title": "Controller", - "type": "string" + "description": "Geobrick on which to disable limits" }, "Axis": { "default": null, "description": "Axis to have limits disabled", "title": "Axis", "type": "integer" - }, - "type": { - "const": "pmac.pmacDisableLimitsCheck", - "default": "pmac.pmacDisableLimitsCheck", - "description": "The type of this entity", - "title": "Type" } }, "title": "pmac_pmacDisableLimitsCheck", @@ -981,35 +1111,9 @@ "type": "string" }, "entities": { - "default": [], "description": "List of entities this IOC instantiates", "items": { - "anyOf": [ - { - "$ref": "#/$defs/pmac_PmacAsynSSHPort" - }, - { - "$ref": "#/$defs/pmac_PmacAsynIPPort" - }, - { - "$ref": "#/$defs/pmac_Geobrick" - }, - { - "$ref": "#/$defs/pmac_DlsPmacAsynMotor" - }, - { - "$ref": "#/$defs/pmac_DlsCsPmacAsynMotor" - }, - { - "$ref": "#/$defs/pmac_pmacDisableLimitsCheck" - }, - { - "$ref": "#/$defs/pmac_autohome" - }, - { - "$ref": "#/$defs/pmac_CS" - } - ] + "$ref": "#/$defs/EntityModel" }, "title": "Entities", "type": "array" @@ -1018,7 +1122,8 @@ "required": [ "ioc_name", "description", - "generic_ioc_image" + "generic_ioc_image", + "entities" ], "title": "NewIOC", "type": "object" diff --git a/tests/samples/values_test/st.cmd b/tests/samples/values_test/st.cmd index 870df2af5..601e5ecc5 100644 --- a/tests/samples/values_test/st.cmd +++ b/tests/samples/values_test/st.cmd @@ -1,10 +1,21 @@ # EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek cd "/repos/epics/ioc" + +epicsEnvSet Vec0 192 + dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase +# ipacAddHy8002 "slot, interrupt_level" +# Create a new Hy8002 carrier. +# The resulting carrier handle (card id) is saved in an env variable. +ipacAddHy8002 "4, 2" +epicsEnvSet IPAC4 +ipacAddHy8002 "5, 2" +epicsEnvSet IPAC5 + dbLoadRecords /tmp/ioc.db iocInit From 1edcea8624eb80bb0f5dae95c22437fde1528f7d Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 07:46:58 +0000 Subject: [PATCH 08/30] values expansion working --- src/ibek/ioc.py | 38 +++++++------------ tests/samples/pydantic/st.cmd | 11 ++++-- .../pydantic/test.ibek.ioc.schema.json | 6 +++ tests/samples/pydantic/test.ibek.ioc.yaml | 10 ++--- tests/samples/pydantic/test.ibek.support.yaml | 19 ++++++---- 5 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index 7f9db2b4c..b1128a0f2 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -31,32 +31,16 @@ class Entity(BaseSettings): description="enable or disable this entity instance", default=True ) - # a link back to the Definition Object that generated this Definition - __definition__: Definition - - @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 - # 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) + @model_validator(mode="after") # type: ignore + def add_ibek_attributes(cls, entity: Entity): + """Add additional attributes used by ibek""" # Jinja expansion of any string args/values in the Entity's attributes - for arg, value in entity.items(): + entity_dict = entity.model_dump() + for arg, value in entity_dict.items(): if isinstance(value, str): jinja_template = Template(value) - entity[arg] = jinja_template.render(entity) + setattr(entity, arg, jinja_template.render(entity_dict)) return entity @@ -94,7 +78,7 @@ def lookup_instance(cls, id): raise KeyError(f"object id {id} not in {list(id_to_entity)}") validators[full_arg_name] = lookup_instance - arg_type = Entity + arg_type = str elif isinstance(arg, IdArg): @@ -102,7 +86,7 @@ def lookup_instance(cls, id): def save_instance(cls, id): if id in id_to_entity: raise KeyError(f"id {id} already defined in {list(id_to_entity)}") - id_to_entity[id] = Entity + id_to_entity[id] = "hello" return id validators[full_arg_name] = save_instance @@ -115,6 +99,11 @@ def save_instance(cls, id): default = getattr(arg, "default", None) add_arg(arg.name, arg_type, arg.description, default) + # add in the calculated values as a Field in the Entity (as Jinja templates) + for value in definition.values: + add_arg(value.name, str, value.description, value.value) + + # add the type literal which discriminates between the different Entity classes typ = Literal[full_name] # type: ignore add_arg("type", typ, "The type of this entity", full_name) @@ -126,7 +115,6 @@ def save_instance(cls, id): ) # type: ignore # add a link back to the Definition Object that generated this Entity Class - # TODO replace this mechanism as it does not work in pydantic entity_cls.__definition__ = definition return entity_cls diff --git a/tests/samples/pydantic/st.cmd b/tests/samples/pydantic/st.cmd index 4a9af0c37..8751a1fa8 100644 --- a/tests/samples/pydantic/st.cmd +++ b/tests/samples/pydantic/st.cmd @@ -5,11 +5,14 @@ dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase +# testValues TestValue +testValues test_value:AsynPort.10.0.0.1 +testValues test_value:AsynPort2.10.0.0.2 + # exampleTestFunction AsynPortIP Name Value -# A function that uses the AsynPortIP and Name -# to do something useful -exampleTestFunction Yet Another Consumer of same port -exampleTestFunction Just One More Consumer of same port +# (A function that uses the AsynPortIP and its own Name) +exampleTestFunction IP: name:'Consumer of another port' Value: +exampleTestFunction IP: name:'Another Consumer of the 2nd port' Value: dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/pydantic/test.ibek.ioc.schema.json b/tests/samples/pydantic/test.ibek.ioc.schema.json index 8d2356927..4af25d330 100644 --- a/tests/samples/pydantic/test.ibek.ioc.schema.json +++ b/tests/samples/pydantic/test.ibek.ioc.schema.json @@ -48,6 +48,12 @@ "description": "IP address of port", "title": "Ip", "type": "string" + }, + "test_value": { + "default": "{{ name }}.{{ IP }}", + "description": "test jinja render of arg values", + "title": "Test Value", + "type": "string" } }, "title": "pydantic_test_AnAsynPort", diff --git a/tests/samples/pydantic/test.ibek.ioc.yaml b/tests/samples/pydantic/test.ibek.ioc.yaml index cc2fd4a15..37ebbdc7e 100644 --- a/tests/samples/pydantic/test.ibek.ioc.yaml +++ b/tests/samples/pydantic/test.ibek.ioc.yaml @@ -13,20 +13,20 @@ entities: - type: pydantic_test.AnAsynPort name: AsynPort2 - IP: 10.0.0.1 + IP: 10.0.0.2 - type: pydantic_test.Consumer name: A Consumer - PORT: AsynPort2 + PORT: AsynPort1 - type: pydantic_test.Consumer name: Another Consumer of same port - PORT: AsynPort2 + PORT: AsynPort1 - type: pydantic_test.ConsumerTwo - name: Yet Another Consumer of same port + name: Consumer of another port PORT: AsynPort2 - type: pydantic_test.ConsumerTwo - name: Just One More Consumer of same port + name: Another Consumer of the 2nd port PORT: AsynPort2 diff --git a/tests/samples/pydantic/test.ibek.support.yaml b/tests/samples/pydantic/test.ibek.support.yaml index fd928ee76..d13ea8db0 100644 --- a/tests/samples/pydantic/test.ibek.support.yaml +++ b/tests/samples/pydantic/test.ibek.support.yaml @@ -19,6 +19,12 @@ defs: value: "{{ name }}.{{ IP }}" description: test jinja render of arg values + pre_init: + - type: function + name: testValues + args: + TestValue: test_value:{{ test_value }} + - name: Consumer description: | A class that uses AnAsynPort @@ -27,7 +33,7 @@ defs: name: name description: Consumer name - - type: object + - type: str name: PORT description: a reference to an AnAsynPort @@ -39,7 +45,7 @@ defs: name: name description: Consumer name - - type: object + - type: str name: PORT description: a reference to an AnAsynPort @@ -47,9 +53,8 @@ defs: - type: function name: exampleTestFunction args: - AsynPortIP: "{{ PORT.IP }}" - Name: "{{ name }}" - Value: "{{ PORT.test_value }}" + AsynPortIP: IP:{{ PORT.IP }} + Name: name:'{{ name }}' + Value: Value:{{ PORT.test_value }} header: | - # A function that uses the AsynPortIP and Name - # to do something useful + # (A function that uses the AsynPortIP and its own Name) From c66c237ebf4b0ae13e828391fbd73fee24f7bfb4 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 09:27:00 +0000 Subject: [PATCH 09/30] id lookup working! --- src/ibek/globals.py | 13 ++--- src/ibek/ioc.py | 58 +++++++++---------- tests/samples/pydantic/st.cmd | 7 +-- .../pydantic/test.ibek.ioc.schema.json | 6 +- tests/samples/pydantic/test.ibek.ioc.yaml | 2 +- tests/samples/pydantic/test.ibek.support.yaml | 8 +-- 6 files changed, 42 insertions(+), 52 deletions(-) diff --git a/src/ibek/globals.py b/src/ibek/globals.py index b45f869af..43dc7a2d4 100644 --- a/src/ibek/globals.py +++ b/src/ibek/globals.py @@ -4,14 +4,11 @@ from pydantic import BaseModel, ConfigDict -# pydantic model configuration -model_config = ConfigDict( - arbitrary_types_allowed=True, - extra="forbid", -) - class BaseSettings(BaseModel): - """A Base class for setting Pydantic model configuration""" + """A Base class for setting consistent Pydantic model configuration""" - model_config = model_config + model_config = ConfigDict( + arbitrary_types_allowed=True, + extra="forbid", + ) diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index b1128a0f2..72cb88882 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -14,9 +14,6 @@ from .globals import BaseSettings from .support import Definition, IdArg, ObjectArg, Support -# A base class for applying settings to all serializable classes - - id_to_entity: Dict[str, Entity] = {} @@ -26,19 +23,27 @@ class Entity(BaseSettings): deserialize entry point. """ + # All entities have these two fields, others are added by make_entity_model type: str = Field(description="The type of this entity") entity_enabled: bool = Field( description="enable or disable this entity instance", default=True ) + __definition__: Definition @model_validator(mode="after") # type: ignore def add_ibek_attributes(cls, entity: Entity): - """Add additional attributes used by ibek""" + """Whole Entity model validation""" + + # find any id fields in this Entity + ids = set(a.name for a in entity.__definition__.args if isinstance(a, IdArg)) - # Jinja expansion of any string args/values in the Entity's attributes entity_dict = entity.model_dump() for arg, value in entity_dict.items(): - if isinstance(value, str): + if arg in ids: + # add this entity to the global id index + id_to_entity[value] = entity + elif isinstance(value, str): + # Jinja expansion of any of the Entity's string args/values jinja_template = Template(value) setattr(entity, arg, jinja_template.render(entity_dict)) return entity @@ -46,16 +51,14 @@ def add_ibek_attributes(cls, entity: Entity): def make_entity_model(definition: Definition, support: Support) -> Type[Entity]: """ - We can get a set of Definitions by deserializing an ibek - support module definition YAML file. - - This function then creates an Entity derived class from each Definition. - - See :ref:`entities` + Create an Entity Model from a Definition instance and a Support instance. """ def add_arg(name, typ, description, default): - args[name] = (typ, FieldInfo(description=description, default=default)) + args[name] = ( + typ, + FieldInfo(description=description, default=default), + ) args: Dict[str, Tuple[type, Any]] = {} validators: Dict[str, Any] = {} @@ -78,18 +81,9 @@ def lookup_instance(cls, id): raise KeyError(f"object id {id} not in {list(id_to_entity)}") validators[full_arg_name] = lookup_instance - arg_type = str + arg_type = object elif isinstance(arg, IdArg): - - @field_validator(arg.name) - def save_instance(cls, id): - if id in id_to_entity: - raise KeyError(f"id {id} already defined in {list(id_to_entity)}") - id_to_entity[id] = "hello" - return id - - validators[full_arg_name] = save_instance arg_type = str else: @@ -99,7 +93,7 @@ def save_instance(cls, id): default = getattr(arg, "default", None) add_arg(arg.name, arg_type, arg.description, default) - # add in the calculated values as a Field in the Entity (as Jinja templates) + # add in the calculated values Jinja Templates as Fields in the Entity for value in definition.values: add_arg(value.name, str, value.description, value.value) @@ -114,18 +108,17 @@ def save_instance(cls, id): __base__=Entity, ) # type: ignore - # add a link back to the Definition Object that generated this Entity Class + # add a link back to the Definition Instance that generated this Entity Class entity_cls.__definition__ = definition return entity_cls def make_entity_models(support: Support): - """Create `Entity` subclasses for all `Definition` objects in the given - `Support` instance. - - Then create a Pydantic model of an IOC class with its entities field - set to a Union of all the Entity subclasses created.""" + """ + Create `Entity` subclasses for all `Definition` instances in the given + `Support` instance. Returns a list of the Entity subclasses Models. + """ entity_models = [] entity_names = [] @@ -140,6 +133,11 @@ def make_entity_models(support: Support): def make_ioc_model(entity_models: Sequence[Type[Entity]]) -> Type[IOC]: + """ + Create an IOC derived model, by setting its entities attribute to + be of type 'list of Entity derived classes'. + """ + class EntityModel(RootModel): root: Union[tuple(entity_models)] = Field(discriminator="type") # type: ignore diff --git a/tests/samples/pydantic/st.cmd b/tests/samples/pydantic/st.cmd index 8751a1fa8..a7073af25 100644 --- a/tests/samples/pydantic/st.cmd +++ b/tests/samples/pydantic/st.cmd @@ -6,13 +6,12 @@ ioc_registerRecordDeviceDriver pdbbase # testValues TestValue -testValues test_value:AsynPort.10.0.0.1 +testValues test_value:AsynPort1.10.0.0.1 testValues test_value:AsynPort2.10.0.0.2 # exampleTestFunction AsynPortIP Name Value -# (A function that uses the AsynPortIP and its own Name) -exampleTestFunction IP: name:'Consumer of another port' Value: -exampleTestFunction IP: name:'Another Consumer of the 2nd port' Value: +exampleTestFunction IP:10.0.0.2 name:'Consumer of another port' Value:AsynPort2.10.0.0.2pydantic_test.AnAsynPort +exampleTestFunction IP:10.0.0.2 name:'Another Consumer of the 2nd port' Value:AsynPort2.10.0.0.2pydantic_test.AnAsynPort dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/pydantic/test.ibek.ioc.schema.json b/tests/samples/pydantic/test.ibek.ioc.schema.json index 4af25d330..ae768e509 100644 --- a/tests/samples/pydantic/test.ibek.ioc.schema.json +++ b/tests/samples/pydantic/test.ibek.ioc.schema.json @@ -83,8 +83,7 @@ "PORT": { "default": null, "description": "a reference to an AnAsynPort", - "title": "Port", - "type": "string" + "title": "Port" } }, "title": "pydantic_test_Consumer", @@ -114,8 +113,7 @@ "PORT": { "default": null, "description": "a reference to an AnAsynPort", - "title": "Port", - "type": "string" + "title": "Port" } }, "title": "pydantic_test_ConsumerTwo", diff --git a/tests/samples/pydantic/test.ibek.ioc.yaml b/tests/samples/pydantic/test.ibek.ioc.yaml index 37ebbdc7e..de4db9fea 100644 --- a/tests/samples/pydantic/test.ibek.ioc.yaml +++ b/tests/samples/pydantic/test.ibek.ioc.yaml @@ -8,7 +8,7 @@ generic_ioc_image: ghcr.io/epics-containers/ioc-template:23.3.2 entities: - type: pydantic_test.AnAsynPort - name: AsynPort + name: AsynPort1 IP: 10.0.0.1 - type: pydantic_test.AnAsynPort diff --git a/tests/samples/pydantic/test.ibek.support.yaml b/tests/samples/pydantic/test.ibek.support.yaml index d13ea8db0..bc96203a9 100644 --- a/tests/samples/pydantic/test.ibek.support.yaml +++ b/tests/samples/pydantic/test.ibek.support.yaml @@ -33,7 +33,7 @@ defs: name: name description: Consumer name - - type: str + - type: object name: PORT description: a reference to an AnAsynPort @@ -45,7 +45,7 @@ defs: name: name description: Consumer name - - type: str + - type: object name: PORT description: a reference to an AnAsynPort @@ -55,6 +55,4 @@ defs: args: AsynPortIP: IP:{{ PORT.IP }} Name: name:'{{ name }}' - Value: Value:{{ PORT.test_value }} - header: | - # (A function that uses the AsynPortIP and its own Name) + Value: Value:{{ PORT.test_value }}{{ PORT.type}} From 0ba40e00a750b45874103e6f5f6970be6d479a3d Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 09:45:21 +0000 Subject: [PATCH 10/30] utils in values render fixed --- src/ibek/globals.py | 13 ++ src/ibek/ioc.py | 6 +- src/ibek/render.py | 17 +- tests/samples/boot_scripts/st.cmd | 16 +- tests/samples/boot_scripts/stbl45p-mo-ioc-03 | 21 +- tests/samples/example-srrfioc08/make_db.sh | 1 - tests/samples/example-srrfioc08/st.cmd | 23 +- tests/samples/pydantic/st.cmd | 4 +- tests/samples/pydantic/test.ibek.support.yaml | 2 +- .../schemas/all.ibek.support.schema.json | 204 +++++------------- .../bl45p-mo-ioc-04.ibek.entities.schema.json | 70 ++---- .../container.ibek.entities.schema.json | 70 ++---- .../schemas/pmac.ibek.entities.schema.json | 70 ++---- tests/samples/values_test/st.cmd | 4 +- 14 files changed, 147 insertions(+), 374 deletions(-) diff --git a/src/ibek/globals.py b/src/ibek/globals.py index 43dc7a2d4..30c64d6ec 100644 --- a/src/ibek/globals.py +++ b/src/ibek/globals.py @@ -2,8 +2,13 @@ A few global definitions """ +from typing import Dict + +from jinja2 import Template from pydantic import BaseModel, ConfigDict +from .utils import UTILS + class BaseSettings(BaseModel): """A Base class for setting consistent Pydantic model configuration""" @@ -12,3 +17,11 @@ class BaseSettings(BaseModel): arbitrary_types_allowed=True, extra="forbid", ) + + +def render_with_utils(context: Dict, template_text: str) -> str: + """ + Render a Jinja template with the global __utils__ object available + """ + jinja_template = Template(template_text) + return jinja_template.render(context, __utils__=UTILS) diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index 72cb88882..7d7fb9004 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -7,11 +7,10 @@ import builtins from typing import Any, Dict, Literal, Sequence, Tuple, Type, Union -from jinja2 import Template from pydantic import Field, RootModel, create_model, field_validator, model_validator from pydantic.fields import FieldInfo -from .globals import BaseSettings +from .globals import BaseSettings, render_with_utils from .support import Definition, IdArg, ObjectArg, Support id_to_entity: Dict[str, Entity] = {} @@ -44,8 +43,7 @@ def add_ibek_attributes(cls, entity: Entity): id_to_entity[value] = entity elif isinstance(value, str): # Jinja expansion of any of the Entity's string args/values - jinja_template = Template(value) - setattr(entity, arg, jinja_template.render(entity_dict)) + setattr(entity, arg, render_with_utils(entity_dict, value)) return entity diff --git a/src/ibek/render.py b/src/ibek/render.py index 5794a3960..ff2332ad5 100644 --- a/src/ibek/render.py +++ b/src/ibek/render.py @@ -4,11 +4,9 @@ from typing import Callable, List, Optional, Union -from jinja2 import Template - +from .globals import render_with_utils from .ioc import IOC, Entity from .support import Comment, Function, Script, Text, When -from .utils import UTILS class Render: @@ -21,13 +19,6 @@ class Render: def __init__(self: "Render"): self.once_done: List[str] = [] - def render_with_utils(self, instance: Entity, template_text: str) -> str: - """ - Render a Jinja template with the global __utils__ object available - """ - jinja_template = Template(template_text) - return jinja_template.render(instance.__dict__, __utils__=UTILS) - def render_text( self, instance: Entity, text: str, when=When.every, suffix="" ) -> str: @@ -54,7 +45,7 @@ def render_text( raise NotImplementedError("When.last not yet implemented") # Render Jinja entries in the text - result = self.render_with_utils(instance, text) + result = render_with_utils(instance, text) if result == "": return "" @@ -153,7 +144,7 @@ def render_database(self, instance: Entity) -> Optional[str]: f'msi -I${{EPICS_DB_INCLUDE_PATH}} -M"{db_arg_string}" "{db_file}"\n' ) - db_txt = self.render_with_utils(instance, jinja_txt) + db_txt = render_with_utils(instance, jinja_txt) return db_txt + "\n" @@ -170,7 +161,7 @@ def render_environment_variables(self, instance: Entity) -> Optional[str]: for variable in variables: # Substitute the name and value of the environment variable from args env_template = f"epicsEnvSet {variable.name} {variable.value}" - env_var_txt += self.render_with_utils(instance, env_template) + env_var_txt += render_with_utils(instance, env_template) return env_var_txt + "\n" def render_elements( diff --git a/tests/samples/boot_scripts/st.cmd b/tests/samples/boot_scripts/st.cmd index 601e5ecc5..957cf88bc 100644 --- a/tests/samples/boot_scripts/st.cmd +++ b/tests/samples/boot_scripts/st.cmd @@ -1,20 +1,16 @@ # EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek cd "/repos/epics/ioc" - -epicsEnvSet Vec0 192 - dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase -# ipacAddHy8002 "slot, interrupt_level" -# Create a new Hy8002 carrier. -# The resulting carrier handle (card id) is saved in an env variable. -ipacAddHy8002 "4, 2" -epicsEnvSet IPAC4 -ipacAddHy8002 "5, 2" -epicsEnvSet IPAC5 +# pmacAsynIPConfigure AsynPortName IPAddress +pmacAsynIPConfigure BRICK1port 192.168.0.12:1112:1025 + +# pmacCreateController AsynPortName PmacAsynPort Address NumAxes MovingPollPeriod IdlePollPeriod +pmacCreateController BL45P-MO-BRICK-01 BRICK1port 0 8 500 100 +pmacCreateAxes BL45P-MO-BRICK-01 8 dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/boot_scripts/stbl45p-mo-ioc-03 b/tests/samples/boot_scripts/stbl45p-mo-ioc-03 index 601e5ecc5..06302a347 100644 --- a/tests/samples/boot_scripts/stbl45p-mo-ioc-03 +++ b/tests/samples/boot_scripts/stbl45p-mo-ioc-03 @@ -1,20 +1,21 @@ # EPICS IOC Startup Script generated by https://github.com/epics-containers/ibek cd "/repos/epics/ioc" - -epicsEnvSet Vec0 192 - dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase -# ipacAddHy8002 "slot, interrupt_level" -# Create a new Hy8002 carrier. -# The resulting carrier handle (card id) is saved in an env variable. -ipacAddHy8002 "4, 2" -epicsEnvSet IPAC4 -ipacAddHy8002 "5, 2" -epicsEnvSet IPAC5 +# pmacAsynIPConfigure AsynPortName IPAddress +pmacAsynIPConfigure BRICK1port 192.168.0.12:1112:1025 + +# pmacCreateController AsynPortName PmacAsynPort Address NumAxes MovingPollPeriod IdlePollPeriod +pmacCreateController BL45P-MO-BRICK-01 BRICK1port 0 8 500 100 +pmacCreateAxes BL45P-MO-BRICK-01 8 +# ASYNSerial Startup ENTRY +# TODO provide Jinja to generate ASYN Startup Entries +# note this is interesting because builder.py has a few if clauses +# for generating the necessary script +# dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/example-srrfioc08/make_db.sh b/tests/samples/example-srrfioc08/make_db.sh index fca3baaa7..a9bf588e2 100644 --- a/tests/samples/example-srrfioc08/make_db.sh +++ b/tests/samples/example-srrfioc08/make_db.sh @@ -1,2 +1 @@ #!/bin/bash -msi -I${EPICS_DB_INCLUDE_PATH} -M"IOC=test-ibek-ioc" "iocAdminSoft.db" diff --git a/tests/samples/example-srrfioc08/st.cmd b/tests/samples/example-srrfioc08/st.cmd index d946f599f..b372e63c8 100644 --- a/tests/samples/example-srrfioc08/st.cmd +++ b/tests/samples/example-srrfioc08/st.cmd @@ -2,13 +2,30 @@ cd "/repos/epics/ioc" -epicsEnvSet EPICS_CA_MAX_ARRAY_BYTES 6000000 -epicsEnvSet EPICS_CA_SERVER_PORT 7064 +epicsEnvSet EPICS_TS_NTP_INET 172.23.194.5 +epicsEnvSet EPICS_TS_MIN_WEST 0 +epicsEnvSet Vec0 192 +epicsEnvSet Vec1 193 +epicsEnvSet Vec2 194 dbLoadDatabase dbd/ioc.dbd ioc_registerRecordDeviceDriver pdbbase -dbLoadRecords("config/ioc.db") + +# ipacAddHy8002 "slot, interrupt_level" +# Create a new Hy8002 carrier. +# The resulting carrier handle (card id) is saved in an env variable. +ipacAddHy8002 "4, 2" +epicsEnvSet IPAC4 0 +ipacAddHy8002 "5, 2" +epicsEnvSet IPAC5 1 + +# Hy8401ipConfigure CardId IPACid IpSiteNumber InterruptVector InterruptEnable AiType ExternalClock ClockRate Inhibit SampleCount SampleSpacing SampleSize +# IpSlot 0=A 1=B 2=C 3=D +# ClockRate 0=1Hz 1=2Hz 2=5Hz 3=10Hz 4=20Hz 5=50Hz 6=100Hz7=200Hz 8=500Hz 9=1kHz 10=2kHz11=5kHz 12=10kHz 13=20kHz 14=50kHz 15=100kHz +Hy8401ipConfigure 40 $(IPAC4) 0 $(Vec0) 0 0 0 15 0 1 1 0 +Hy8401ipConfigure 42 $(IPAC4) 2 $(Vec1) 0 0 0 15 0 1 1 0 +Hy8401ipConfigure 50 $(IPAC5) 0 $(Vec2) 0 0 0 15 0 1 1 0 dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/pydantic/st.cmd b/tests/samples/pydantic/st.cmd index a7073af25..ece54d7ab 100644 --- a/tests/samples/pydantic/st.cmd +++ b/tests/samples/pydantic/st.cmd @@ -10,8 +10,8 @@ testValues test_value:AsynPort1.10.0.0.1 testValues test_value:AsynPort2.10.0.0.2 # exampleTestFunction AsynPortIP Name Value -exampleTestFunction IP:10.0.0.2 name:'Consumer of another port' Value:AsynPort2.10.0.0.2pydantic_test.AnAsynPort -exampleTestFunction IP:10.0.0.2 name:'Another Consumer of the 2nd port' Value:AsynPort2.10.0.0.2pydantic_test.AnAsynPort +exampleTestFunction IP:10.0.0.2 name:'Consumer of another port' Value:AsynPort2.10.0.0.2 +exampleTestFunction IP:10.0.0.2 name:'Another Consumer of the 2nd port' Value:AsynPort2.10.0.0.2 dbLoadRecords /tmp/ioc.db iocInit diff --git a/tests/samples/pydantic/test.ibek.support.yaml b/tests/samples/pydantic/test.ibek.support.yaml index bc96203a9..ea58ca7c3 100644 --- a/tests/samples/pydantic/test.ibek.support.yaml +++ b/tests/samples/pydantic/test.ibek.support.yaml @@ -55,4 +55,4 @@ defs: args: AsynPortIP: IP:{{ PORT.IP }} Name: name:'{{ name }}' - Value: Value:{{ PORT.test_value }}{{ PORT.type}} + Value: Value:{{ PORT.test_value }} diff --git a/tests/samples/schemas/all.ibek.support.schema.json b/tests/samples/schemas/all.ibek.support.schema.json index 7d8968e54..ebe8bc0fa 100644 --- a/tests/samples/schemas/all.ibek.support.schema.json +++ b/tests/samples/schemas/all.ibek.support.schema.json @@ -83,13 +83,9 @@ "type": "boolean" }, "camera": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "reference to ADAravis.ADAravis instance" + "description": "reference to ADAravis.ADAravis instance", + "title": "Camera" } }, "title": "ADAravis_Mako_G234B", @@ -111,13 +107,9 @@ "type": "boolean" }, "camera": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "reference to ADAravis.ADAravis instance" + "description": "reference to ADAravis.ADAravis instance", + "title": "Camera" } }, "title": "ADAravis_MantaG235B", @@ -145,13 +137,9 @@ "type": "string" }, "NDARRAY_PORT": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Port Name for input NDArray plugin" + "description": "Port Name for input NDArray plugin", + "title": "Ndarray Port" }, "P": { "default": null, @@ -308,28 +296,6 @@ "title": "ADCore_NDStats", "type": "object" }, - "Entity": { - "additionalProperties": false, - "description": "\n A baseclass for all generated Entity classes. Provides the\n deserialize entry point.\n ", - "properties": { - "type": { - "description": "The type of this entity", - "title": "Type", - "type": "string" - }, - "entity_enabled": { - "default": true, - "description": "enable or disable this entity instance", - "title": "Entity Enabled", - "type": "boolean" - } - }, - "required": [ - "type" - ], - "title": "Entity", - "type": "object" - }, "EntityModel": { "discriminator": { "mapping": { @@ -504,13 +470,9 @@ "type": "boolean" }, "card": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "8401 card identifier" + "description": "8401 card identifier", + "title": "Card" }, "signal": { "default": null, @@ -544,13 +506,9 @@ "type": "string" }, "carrier": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Carrier Board Identifier" + "description": "Carrier Board Identifier", + "title": "Carrier" }, "ip_site_number": { "default": null, @@ -559,13 +517,9 @@ "type": "integer" }, "vector": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Interrupt Vector" + "description": "Interrupt Vector", + "title": "Vector" }, "int_enable": { "default": false, @@ -629,13 +583,9 @@ "type": "string" }, "card": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "8403 card identifier" + "description": "8403 card identifier", + "title": "Card" } }, "title": "Hy8403ip_Hy8403Channel", @@ -663,13 +613,9 @@ "type": "string" }, "carrier": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Carrier Board Identifier" + "description": "Carrier Board Identifier", + "title": "Carrier" }, "ip_site_number": { "default": null, @@ -678,13 +624,9 @@ "type": "integer" }, "vector": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Interrupt Vector" + "description": "Interrupt Vector", + "title": "Vector" }, "aitype": { "default": null, @@ -845,13 +787,9 @@ "type": "string" }, "event_receiver": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "reference to EventReceiverPMC entry" + "description": "reference to EventReceiverPMC entry", + "title": "Event Receiver" }, "er": { "default": "SET-ER", @@ -879,13 +817,9 @@ "type": "boolean" }, "default_evr": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "reference to DefaultEVR entry" + "description": "reference to DefaultEVR entry", + "title": "Default Evr" } }, "title": "TimingTemplates_EvrAlive", @@ -1336,6 +1270,12 @@ "description": "Interrupt level", "title": "Int Level", "type": "integer" + }, + "card_id": { + "default": "{{ __utils__.counter(\"Carriers\", start=0) }}", + "description": "Carrier Card Identifier", + "title": "Card Id", + "type": "string" } }, "title": "ipac_Hy8002", @@ -1425,13 +1365,9 @@ "type": "string" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "the PMAC Controller" + "description": "the PMAC Controller", + "title": "Controller" }, "CS": { "default": null, @@ -1477,13 +1413,9 @@ "type": "string" }, "CsController": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Coordinate system controller to attach to" + "description": "Coordinate system controller to attach to", + "title": "Cscontroller" }, "axis": { "default": null, @@ -1799,13 +1731,9 @@ "type": "string" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "PMAC Controller to attach to" + "description": "PMAC Controller to attach to", + "title": "Controller" }, "axis": { "default": null, @@ -2127,13 +2055,9 @@ "type": "string" }, "PORT": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Asyn port name for PmacAsynIPPort to connect to" + "description": "Asyn port name for PmacAsynIPPort to connect to", + "title": "Port" }, "P": { "default": null, @@ -2319,13 +2243,9 @@ "type": "boolean" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "the PMAC Controller" + "description": "the PMAC Controller", + "title": "Controller" }, "PLC": { "default": null, @@ -2413,13 +2333,9 @@ "type": "boolean" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Geobrick on which to disable limits" + "description": "Geobrick on which to disable limits", + "title": "Controller" }, "Axis": { "default": null, @@ -2453,13 +2369,9 @@ "type": "string" }, "carrier": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "IPAC carrier name" + "description": "IPAC carrier name", + "title": "Carrier" }, "ip_site_number": { "default": null, @@ -2468,13 +2380,9 @@ "type": "integer" }, "interrupt_vector": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Interrupt Vector reserved with epics.InterruptVectorVME, count=3" + "description": "Interrupt Vector reserved with epics.InterruptVectorVME, count=3", + "title": "Interrupt Vector" }, "link": { "default": 0, @@ -2508,13 +2416,9 @@ "type": "string" }, "ip_module": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "PscIpModule object" + "description": "PscIpModule object", + "title": "Ip Module" }, "link": { "default": null, @@ -2638,22 +2542,14 @@ "type": "boolean" }, "card": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "8401 card identifier" + "description": "8401 card identifier", + "title": "Card" }, "psc_template": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "The PSC template instance" + "description": "The PSC template instance", + "title": "Psc Template" }, "channel": { "default": null, diff --git a/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json b/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json index 88cfe8705..373ea2070 100644 --- a/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json +++ b/tests/samples/schemas/bl45p-mo-ioc-04.ibek.entities.schema.json @@ -1,27 +1,5 @@ { "$defs": { - "Entity": { - "additionalProperties": false, - "description": "\n A baseclass for all generated Entity classes. Provides the\n deserialize entry point.\n ", - "properties": { - "type": { - "description": "The type of this entity", - "title": "Type", - "type": "string" - }, - "entity_enabled": { - "default": true, - "description": "enable or disable this entity instance", - "title": "Entity Enabled", - "type": "boolean" - } - }, - "required": [ - "type" - ], - "title": "Entity", - "type": "object" - }, "EntityModel": { "discriminator": { "mapping": { @@ -307,13 +285,9 @@ "type": "string" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "the PMAC Controller" + "description": "the PMAC Controller", + "title": "Controller" }, "CS": { "default": null, @@ -359,13 +333,9 @@ "type": "string" }, "CsController": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Coordinate system controller to attach to" + "description": "Coordinate system controller to attach to", + "title": "Cscontroller" }, "axis": { "default": null, @@ -681,13 +651,9 @@ "type": "string" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "PMAC Controller to attach to" + "description": "PMAC Controller to attach to", + "title": "Controller" }, "axis": { "default": null, @@ -1009,13 +975,9 @@ "type": "string" }, "PORT": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Asyn port name for PmacAsynIPPort to connect to" + "description": "Asyn port name for PmacAsynIPPort to connect to", + "title": "Port" }, "P": { "default": null, @@ -1201,13 +1163,9 @@ "type": "boolean" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "the PMAC Controller" + "description": "the PMAC Controller", + "title": "Controller" }, "PLC": { "default": null, @@ -1295,13 +1253,9 @@ "type": "boolean" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Geobrick on which to disable limits" + "description": "Geobrick on which to disable limits", + "title": "Controller" }, "Axis": { "default": null, diff --git a/tests/samples/schemas/container.ibek.entities.schema.json b/tests/samples/schemas/container.ibek.entities.schema.json index 69469849f..14e631124 100644 --- a/tests/samples/schemas/container.ibek.entities.schema.json +++ b/tests/samples/schemas/container.ibek.entities.schema.json @@ -1,27 +1,5 @@ { "$defs": { - "Entity": { - "additionalProperties": false, - "description": "\n A baseclass for all generated Entity classes. Provides the\n deserialize entry point.\n ", - "properties": { - "type": { - "description": "The type of this entity", - "title": "Type", - "type": "string" - }, - "entity_enabled": { - "default": true, - "description": "enable or disable this entity instance", - "title": "Entity Enabled", - "type": "boolean" - } - }, - "required": [ - "type" - ], - "title": "Entity", - "type": "object" - }, "EntityModel": { "discriminator": { "mapping": { @@ -252,13 +230,9 @@ "type": "string" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "the PMAC Controller" + "description": "the PMAC Controller", + "title": "Controller" }, "CS": { "default": null, @@ -304,13 +278,9 @@ "type": "string" }, "CsController": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Coordinate system controller to attach to" + "description": "Coordinate system controller to attach to", + "title": "Cscontroller" }, "axis": { "default": null, @@ -626,13 +596,9 @@ "type": "string" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "PMAC Controller to attach to" + "description": "PMAC Controller to attach to", + "title": "Controller" }, "axis": { "default": null, @@ -954,13 +920,9 @@ "type": "string" }, "PORT": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Asyn port name for PmacAsynIPPort to connect to" + "description": "Asyn port name for PmacAsynIPPort to connect to", + "title": "Port" }, "P": { "default": null, @@ -1146,13 +1108,9 @@ "type": "boolean" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "the PMAC Controller" + "description": "the PMAC Controller", + "title": "Controller" }, "PLC": { "default": null, @@ -1240,13 +1198,9 @@ "type": "boolean" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Geobrick on which to disable limits" + "description": "Geobrick on which to disable limits", + "title": "Controller" }, "Axis": { "default": null, diff --git a/tests/samples/schemas/pmac.ibek.entities.schema.json b/tests/samples/schemas/pmac.ibek.entities.schema.json index 290392d86..9a2afbf66 100644 --- a/tests/samples/schemas/pmac.ibek.entities.schema.json +++ b/tests/samples/schemas/pmac.ibek.entities.schema.json @@ -1,27 +1,5 @@ { "$defs": { - "Entity": { - "additionalProperties": false, - "description": "\n A baseclass for all generated Entity classes. Provides the\n deserialize entry point.\n ", - "properties": { - "type": { - "description": "The type of this entity", - "title": "Type", - "type": "string" - }, - "entity_enabled": { - "default": true, - "description": "enable or disable this entity instance", - "title": "Entity Enabled", - "type": "boolean" - } - }, - "required": [ - "type" - ], - "title": "Entity", - "type": "object" - }, "EntityModel": { "discriminator": { "mapping": { @@ -86,13 +64,9 @@ "type": "string" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "the PMAC Controller" + "description": "the PMAC Controller", + "title": "Controller" }, "CS": { "default": null, @@ -138,13 +112,9 @@ "type": "string" }, "CsController": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Coordinate system controller to attach to" + "description": "Coordinate system controller to attach to", + "title": "Cscontroller" }, "axis": { "default": null, @@ -460,13 +430,9 @@ "type": "string" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "PMAC Controller to attach to" + "description": "PMAC Controller to attach to", + "title": "Controller" }, "axis": { "default": null, @@ -788,13 +754,9 @@ "type": "string" }, "PORT": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Asyn port name for PmacAsynIPPort to connect to" + "description": "Asyn port name for PmacAsynIPPort to connect to", + "title": "Port" }, "P": { "default": null, @@ -980,13 +942,9 @@ "type": "boolean" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "the PMAC Controller" + "description": "the PMAC Controller", + "title": "Controller" }, "PLC": { "default": null, @@ -1074,13 +1032,9 @@ "type": "boolean" }, "Controller": { - "allOf": [ - { - "$ref": "#/$defs/Entity" - } - ], "default": null, - "description": "Geobrick on which to disable limits" + "description": "Geobrick on which to disable limits", + "title": "Controller" }, "Axis": { "default": null, diff --git a/tests/samples/values_test/st.cmd b/tests/samples/values_test/st.cmd index 601e5ecc5..e10ca6bc0 100644 --- a/tests/samples/values_test/st.cmd +++ b/tests/samples/values_test/st.cmd @@ -12,9 +12,9 @@ ioc_registerRecordDeviceDriver pdbbase # Create a new Hy8002 carrier. # The resulting carrier handle (card id) is saved in an env variable. ipacAddHy8002 "4, 2" -epicsEnvSet IPAC4 +epicsEnvSet IPAC4 0 ipacAddHy8002 "5, 2" -epicsEnvSet IPAC5 +epicsEnvSet IPAC5 1 dbLoadRecords /tmp/ioc.db iocInit From 3ab0625f5a06513e829a260a0ccc86db213b07f0 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 11:17:46 +0000 Subject: [PATCH 11/30] fix some tests --- src/ibek/globals.py | 2 +- src/ibek/ioc.py | 5 ++--- tests/conftest.py | 2 +- tests/test_cli.py | 32 +++++++++++++++++----------- tests/test_conversions.py | 45 +++++++++++++++++++++++++++------------ tests/test_render.py | 13 ++++++++++- 6 files changed, 66 insertions(+), 33 deletions(-) diff --git a/src/ibek/globals.py b/src/ibek/globals.py index 30c64d6ec..aae9fa551 100644 --- a/src/ibek/globals.py +++ b/src/ibek/globals.py @@ -21,7 +21,7 @@ class BaseSettings(BaseModel): def render_with_utils(context: Dict, template_text: str) -> str: """ - Render a Jinja template with the global __utils__ object available + Render a Jinja template with the global __utils__ object in the context """ jinja_template = Template(template_text) return jinja_template.render(context, __utils__=UTILS) diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index 7d7fb9004..339045361 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -22,7 +22,6 @@ class Entity(BaseSettings): deserialize entry point. """ - # All entities have these two fields, others are added by make_entity_model type: str = Field(description="The type of this entity") entity_enabled: bool = Field( description="enable or disable this entity instance", default=True @@ -33,7 +32,7 @@ class Entity(BaseSettings): def add_ibek_attributes(cls, entity: Entity): """Whole Entity model validation""" - # find any id fields in this Entity + # find the id field in this Entity if it has one ids = set(a.name for a in entity.__definition__.args if isinstance(a, IdArg)) entity_dict = entity.model_dump() @@ -71,7 +70,7 @@ def add_arg(name, typ, description, default): if isinstance(arg, ObjectArg): - @field_validator(arg.name) + @field_validator(arg.name, mode="after") def lookup_instance(cls, id): try: return id_to_entity[id] diff --git a/tests/conftest.py b/tests/conftest.py index 81ed2139c..ef7ac7ca2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,7 +14,7 @@ def get_support(samples: Path, yaml_file: str) -> Support: # load from file d = YAML(typ="safe").load(samples / f"{yaml_file}") # create a support object from that dict - support = Support.deserialize(d) + support = Support(**d) return support diff --git a/tests/test_cli.py b/tests/test_cli.py index c96e25760..912fbb96b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -9,7 +9,7 @@ from ibek import __version__ from ibek.__main__ import cli -from ibek.ioc import clear_entity_model_ids, make_entity_models +from ibek.ioc import clear_entity_model_ids, make_entity_models, make_ioc_model from ibek.support import Support runner = CliRunner() @@ -205,20 +205,26 @@ def test_build_startup_env_vars_and_post_ioc_init( def test_loading_module_twice(tmp_path: Path, samples: Path, ibek_defs: Path): """ - regression test to demonstrate that clear_entity_classes works and - allows us to call make_entity_classes more than once + Now that we use pydantic it is OK to create the same entity twice + + Verify this. """ - clear_entity_model_ids() - # When we deserialize the same yaml twice as we do in the full test suite - # we may get clashes in the namespace of generated Entity classes. - # This tests that we get a sensible error when we do - definition_file = ibek_defs / "pmac" / "pmac.ibek.support.yaml" - support = Support.deserialize(YAML(typ="safe").load(definition_file)) - make_entity_models(support) - with pytest.raises(AssertionError) as ctx: - make_entity_models(support) - assert str(ctx.value) == "Entity classes already created for pmac" + definition_file = samples / "pydantic" / "test.ibek.support.yaml" + instance_file = samples / "pydantic" / "test.ibek.ioc.yaml" + + support = Support(**YAML(typ="safe").load(definition_file)) + entities1 = make_entity_models(support) + entities2 = make_entity_models(support) + + generic_ioc1 = make_ioc_model(entities1) + generic_ioc2 = make_ioc_model(entities2) + + instance = YAML(typ="safe").load(instance_file) + ioc1 = generic_ioc1(**instance) + ioc2 = generic_ioc2(**instance) + + assert ioc1.model_dump() == ioc2.model_dump() def test_bad_counter(tmp_path: Path, samples: Path): diff --git a/tests/test_conversions.py b/tests/test_conversions.py index 2924602b2..d664d8024 100644 --- a/tests/test_conversions.py +++ b/tests/test_conversions.py @@ -1,20 +1,36 @@ -from ibek.ioc import IOC, clear_entity_model_ids, id_to_entity, make_entity_models +from ibek.ioc import ( + clear_entity_model_ids, + id_to_entity, + make_entity_models, + make_ioc_model, +) from ibek.support import Definition, IdArg, ObjectArg, Support def test_conversion_classes(): clear_entity_model_ids() + support = Support( - "mymodule", - [ - Definition("port", "A port", [IdArg("name", "the name", "id")]), - Definition("device", "a device", [ObjectArg("port", "the port", "object")]), + module="mymodule", + defs=[ + Definition( + name="port", + description="a port", + args=[IdArg(name="name", description="an id")], + ), + Definition( + name="device", + description="a device", + args=[ObjectArg(name="port", description="the port")], + ), ], ) - namespace = make_entity_models(support) - assert {"device", "port"}.issubset(dir(namespace)) - assert namespace.port.__definition__ == support.defs[0] - assert namespace.device.__definition__ == support.defs[1] + + entities = make_entity_models(support) + ioc_model = make_ioc_model(entities) + assert entities[0].__definition__ == support.defs[0] + assert entities[1].__definition__ == support.defs[1] + d = dict( ioc_name="", description="", @@ -24,9 +40,10 @@ def test_conversion_classes(): ], generic_ioc_image="", ) - ioc = IOC.deserialize(d) + ioc = ioc_model(**d) port, device = ioc.entities - assert port.type == "mymodule.port" - assert id_to_entity == {"PORT": port} - assert device.type == "mymodule.device" - assert device.port is port + # TODO try to get rid of the need for '.root' + assert port.root.type == "mymodule.port" + assert device.root.type == "mymodule.device" + assert device.root.port is port.root + assert id_to_entity == {"PORT": port.root} diff --git a/tests/test_render.py b/tests/test_render.py index fc564c568..6c1b8ab71 100644 --- a/tests/test_render.py +++ b/tests/test_render.py @@ -2,6 +2,7 @@ Tests for the rendering of scripts and database entries from generated Entity classes """ +from typing import Literal from unittest.mock import Mock from ibek.ioc import IOC @@ -9,7 +10,17 @@ def test_pmac_asyn_ip_port_script(pmac_classes): - generated_class = pmac_classes.PmacAsynIPPort + for entity_class in pmac_classes: + # TODO is this the easiest way to find the entity class? + if ( + entity_class.model_fields["type"].annotation + == Literal["pmac.PmacAsynIPPort"] + ): + generated_class = entity_class + break + else: + raise ValueError("PmacAsynIPPort not found in pmac_classes") + pmac_asyn_ip = generated_class(name="my_pmac_instance", IP="111.111.111.111") render = Render() From f34b4d654fa8bc93298c979dff1e2e5d320a5844 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 11:27:20 +0000 Subject: [PATCH 12/30] fix more tests --- tests/test_render.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/tests/test_render.py b/tests/test_render.py index 6c1b8ab71..6b1286a37 100644 --- a/tests/test_render.py +++ b/tests/test_render.py @@ -9,17 +9,18 @@ from ibek.render import Render -def test_pmac_asyn_ip_port_script(pmac_classes): - for entity_class in pmac_classes: - # TODO is this the easiest way to find the entity class? - if ( - entity_class.model_fields["type"].annotation - == Literal["pmac.PmacAsynIPPort"] - ): - generated_class = entity_class - break +def find_entity_class(entity_classes, entity_type): + # TODO is this the easiest way to find the entity class? + for entity_class in entity_classes: + literal = Literal[entity_type] # type: ignore + if entity_class.model_fields["type"].annotation == literal: + return entity_class else: - raise ValueError("PmacAsynIPPort not found in pmac_classes") + raise ValueError(f"{entity_type} not found in entity_classes") + + +def test_pmac_asyn_ip_port_script(pmac_classes): + generated_class = find_entity_class(pmac_classes, "pmac.PmacAsynIPPort") pmac_asyn_ip = generated_class(name="my_pmac_instance", IP="111.111.111.111") @@ -34,7 +35,7 @@ def test_pmac_asyn_ip_port_script(pmac_classes): def test_geobrick_script(pmac_classes): - generated_class = pmac_classes.Geobrick + generated_class = find_entity_class(pmac_classes, "pmac.Geobrick") ip_port = Mock() ip_port.name = "my_asyn_port" pmac_geobrick_instance = generated_class( @@ -61,7 +62,8 @@ def test_geobrick_script(pmac_classes): def test_geobrick_database(pmac_classes): - generated_class = pmac_classes.Geobrick + generated_class = find_entity_class(pmac_classes, "pmac.Geobrick") + pmac_geobrick_instance = generated_class( name="test_geobrick", PORT="my_asyn_port", @@ -85,7 +87,8 @@ def test_geobrick_database(pmac_classes): def test_epics_environment_variables(epics_classes): # Using a specific variable entity - generated_class = epics_classes.EpicsCaMaxArrayBytes + generated_class = find_entity_class(epics_classes, "epics.EpicsCaMaxArrayBytes") + max_array_bytes_instance = generated_class(max_bytes=10000000) render = Render() @@ -109,7 +112,7 @@ def test_entity_disabled_does_not_render_elements(pmac_classes, epics_classes): # and post-iocInit # Entity which has a script and database - pmac_geobrick_class = pmac_classes.Geobrick + pmac_geobrick_class = find_entity_class(pmac_classes, "pmac.Geobrick") # Entity which has env_vars ca_max_array_bytes_class = epics_classes.EpicsCaMaxArrayBytes # Entity which has post_ioc_init From 995783b6bb2e664ec379f57cc10b594eebeee624 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 13:23:50 +0000 Subject: [PATCH 13/30] all tests working --- src/ibek/ioc.py | 8 +-- tests/samples/generate_samples.sh | 12 ++++ tests/samples/pydantic/generate_samples.sh | 23 ------ tests/test_cli.py | 14 ++-- tests/test_render.py | 83 +++++++++++++--------- 5 files changed, 75 insertions(+), 65 deletions(-) delete mode 100755 tests/samples/pydantic/generate_samples.sh diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index 339045361..43e84bda2 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -18,8 +18,7 @@ class Entity(BaseSettings): """ - A baseclass for all generated Entity classes. Provides the - deserialize entry point. + A baseclass for all generated Entity classes. """ type: str = Field(description="The type of this entity") @@ -39,6 +38,8 @@ def add_ibek_attributes(cls, entity: Entity): for arg, value in entity_dict.items(): if arg in ids: # add this entity to the global id index + if value in id_to_entity: + raise ValueError(f"Duplicate id {value} in {list(id_to_entity)}") id_to_entity[value] = entity elif isinstance(value, str): # Jinja expansion of any of the Entity's string args/values @@ -75,7 +76,7 @@ def lookup_instance(cls, id): try: return id_to_entity[id] except KeyError: - raise KeyError(f"object id {id} not in {list(id_to_entity)}") + raise KeyError(f"object {id} not found in {list(id_to_entity)}") validators[full_arg_name] = lookup_instance arg_type = object @@ -148,7 +149,6 @@ class NewIOC(IOC): def clear_entity_model_ids(): """Resets the global id_to_entity dict.""" - global id_to_entity id_to_entity.clear() diff --git a/tests/samples/generate_samples.sh b/tests/samples/generate_samples.sh index bb362c17c..322eff3ee 100755 --- a/tests/samples/generate_samples.sh +++ b/tests/samples/generate_samples.sh @@ -53,6 +53,18 @@ echo making values_test IOC ibek build-startup ${SAMPLES_DIR}/values_test/values.ibek.ioc.yaml ${DEFS}/*/*.support.yaml --out /tmp/ioc/st.cmd --db-out /tmp/ioc/make_db.sh cp /tmp/ioc/st.cmd ${SAMPLES_DIR}/values_test +PYDANTIC_DIR=${SAMPLES_DIR}/pydantic +cd $PYDANTIC_DIR + +echo making the support yaml schema +ibek ibek-schema ${PYDANTIC_DIR}/../schemas/ibek.defs.schema.json + +echo making the pydantic test definition schema +ibek ioc-schema ${PYDANTIC_DIR}/test.ibek.support.yaml $PYDANTIC_DIR/test.ibek.ioc.schema.json + +echo making the pydantic test ioc startup script +ibek build-startup ${PYDANTIC_DIR}/test.ibek.ioc.yaml ${PYDANTIC_DIR}/test.ibek.support.yaml --out $PYDANTIC_DIR/st.cmd --db-out $PYDANTIC_DIR/make_db.sh + diff --git a/tests/samples/pydantic/generate_samples.sh b/tests/samples/pydantic/generate_samples.sh deleted file mode 100755 index 5f9cef76d..000000000 --- a/tests/samples/pydantic/generate_samples.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# this script regenerates the files used in tests -# it is useful after making changes to the code that affect the schemas etc. -# -# please bear in mind that this is cheating tests! It requires visual -# verifiction of the files in the samples folders after running. -# - -export PYDANTIC_DIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))/ -export DEFS=${PYDANTIC_DIR}/../../ibek-defs - -# this is so relative schema mode lines work -cd $PYDANTIC_DIR - -echo making the support yaml schema -ibek ibek-schema ${PYDANTIC_DIR}/../schemas/ibek.defs.schema.json - -echo making the pydantic test definition schema -ibek ioc-schema ${PYDANTIC_DIR}/test.ibek.support.yaml $PYDANTIC_DIR/test.ibek.ioc.schema.json - -echo making the pydantic test ioc startup script -ibek build-startup ${PYDANTIC_DIR}/test.ibek.ioc.yaml ${PYDANTIC_DIR}/test.ibek.support.yaml --out $PYDANTIC_DIR/st.cmd --db-out $PYDANTIC_DIR/make_db.sh diff --git a/tests/test_cli.py b/tests/test_cli.py index 912fbb96b..8f3b5b8ed 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -205,11 +205,12 @@ def test_build_startup_env_vars_and_post_ioc_init( def test_loading_module_twice(tmp_path: Path, samples: Path, ibek_defs: Path): """ - Now that we use pydantic it is OK to create the same entity twice - - Verify this. + Verify we get a sensible error if we try to load a module twice + without clearing the entity model ids """ + clear_entity_model_ids() + definition_file = samples / "pydantic" / "test.ibek.support.yaml" instance_file = samples / "pydantic" / "test.ibek.ioc.yaml" @@ -221,10 +222,11 @@ def test_loading_module_twice(tmp_path: Path, samples: Path, ibek_defs: Path): generic_ioc2 = make_ioc_model(entities2) instance = YAML(typ="safe").load(instance_file) - ioc1 = generic_ioc1(**instance) - ioc2 = generic_ioc2(**instance) + generic_ioc1(**instance) + with pytest.raises(ValueError) as ctx: + generic_ioc2(**instance) - assert ioc1.model_dump() == ioc2.model_dump() + assert "Duplicate id" in str(ctx.value) def test_bad_counter(tmp_path: Path, samples: Path): diff --git a/tests/test_render.py b/tests/test_render.py index 6b1286a37..54fe770ab 100644 --- a/tests/test_render.py +++ b/tests/test_render.py @@ -3,9 +3,8 @@ Entity classes """ from typing import Literal -from unittest.mock import Mock -from ibek.ioc import IOC +from ibek.ioc import clear_entity_model_ids, make_ioc_model from ibek.render import Render @@ -35,12 +34,13 @@ def test_pmac_asyn_ip_port_script(pmac_classes): def test_geobrick_script(pmac_classes): - generated_class = find_entity_class(pmac_classes, "pmac.Geobrick") - ip_port = Mock() - ip_port.name = "my_asyn_port" - pmac_geobrick_instance = generated_class( + pmac_class = find_entity_class(pmac_classes, "pmac.Geobrick") + ip_port_class = find_entity_class(pmac_classes, "pmac.PmacAsynIPPort") + + ip_port_class(name="my_asyn_port", IP="1.1") + pmac_geobrick_instance = pmac_class( name="test_geobrick", - PORT=ip_port, + PORT="my_asyn_port", P="geobrick_one", numAxes=8, idlePoll=200, @@ -63,7 +63,9 @@ def test_geobrick_script(pmac_classes): def test_geobrick_database(pmac_classes): generated_class = find_entity_class(pmac_classes, "pmac.Geobrick") + ip_port_class = find_entity_class(pmac_classes, "pmac.PmacAsynIPPort") + ip_port_class(name="my_asyn_port", IP="1.1") pmac_geobrick_instance = generated_class( name="test_geobrick", PORT="my_asyn_port", @@ -98,8 +100,9 @@ def test_epics_environment_variables(epics_classes): # Using the generic entity env_name = "EPICS_CA_SERVER_PORT" - env_value = 6000 - generated_class = epics_classes.EpicsEnvSet + env_value = "6000" + generated_class = find_entity_class(epics_classes, "epics.EpicsEnvSet") + epics_env_set_instance = generated_class(name=env_name, value=env_value) env_text = render.render_environment_variables(epics_env_set_instance) @@ -111,30 +114,40 @@ def test_entity_disabled_does_not_render_elements(pmac_classes, epics_classes): # There are four elements to check: script, database, environment variables # and post-iocInit + clear_entity_model_ids() + # Entity which has a script and database pmac_geobrick_class = find_entity_class(pmac_classes, "pmac.Geobrick") # Entity which has env_vars - ca_max_array_bytes_class = epics_classes.EpicsCaMaxArrayBytes + ca_max_array_bytes_class = find_entity_class( + epics_classes, "epics.EpicsCaMaxArrayBytes" + ) # Entity which has post_ioc_init - dbpf_class = epics_classes.Dbpf - + dbpf_class = find_entity_class(epics_classes, "epics.Dbpf") # We require pmac asyn IP port instances for the Geobrick class - pmac_asyn_ip_class = pmac_classes.PmacAsynIPPort - brick_one_asyn_ip_port = pmac_asyn_ip_class( - name="geobrick_one_port", IP="172.23.100.101" - ) - brick_two_asyn_ip_port = pmac_asyn_ip_class( - name="geobrick_two_port", IP="172.23.100.101" + pmac_asyn_ip_class = find_entity_class(pmac_classes, "pmac.PmacAsynIPPort") + + # Make an IOC model with our entity classes + Ioc = make_ioc_model( + [pmac_geobrick_class, ca_max_array_bytes_class, dbpf_class, pmac_asyn_ip_class] ) - # Store created instances in a list + # build a list of dictionaries to instantiate an IOC instance_list = [] + instance_list.append( + dict(type="pmac.PmacAsynIPPort", name="geobrick_one_port", IP="172.23.100.101") + ) + instance_list.append( + dict(type="pmac.PmacAsynIPPort", name="geobrick_two_port", IP="172.23.100.101") + ) + # Create two instances of the Geobrick entity, one disabled instance_list.append( - pmac_geobrick_class( + dict( + type="pmac.Geobrick", name="geobrick_enabled", - PORT=brick_one_asyn_ip_port, + PORT="geobrick_one_port", P="geobrick_one", numAxes=8, idlePoll=200, @@ -142,9 +155,10 @@ def test_entity_disabled_does_not_render_elements(pmac_classes, epics_classes): ) ) instance_list.append( - pmac_geobrick_class( + dict( + type="pmac.Geobrick", name="geobrick_disabled", - PORT=brick_two_asyn_ip_port, + PORT="geobrick_two_port", P="geobrick_two", numAxes=8, idlePoll=200, @@ -154,26 +168,31 @@ def test_entity_disabled_does_not_render_elements(pmac_classes, epics_classes): ) # Create two instances of the CA max array bytes entity, one disabled - instance_list.append(ca_max_array_bytes_class()) - instance_list.append(ca_max_array_bytes_class(entity_enabled=False)) + instance_list.append(dict(type="epics.EpicsCaMaxArrayBytes")) + instance_list.append(dict(type="epics.EpicsCaMaxArrayBytes", entity_enabled=False)) # Create two instances of the dpbf class - instance_list.append(dbpf_class(pv="TEST:PV:1", value="pv_value_1")) + instance_list.append(dict(type="epics.Dbpf", pv="TEST:PV:1", value="pv_value_1")) instance_list.append( - dbpf_class(pv="TEST:PV:2", value="pv_value_2", entity_enabled=False) + dict( + type="epics.Dbpf", pv="TEST:PV:2", value="pv_value_2", entity_enabled=False + ) ) # Make an IOC with our instances - ioc = IOC( - "TEST-IOC-01", - "Test IOC", - instance_list, - "test_ioc_image", + ioc = Ioc( + ioc_name="TEST-IOC-01", + description="Test IOC", + entities=instance_list, + generic_ioc_image="test_ioc_image", ) # Render script and check output # ControlerPort, LowLevelDriverPort, Address, Axes, MovingPoll, IdlePoll expected_script = ( + "\n# pmacAsynIPConfigure AsynPortName IPAddress\n" + "pmacAsynIPConfigure geobrick_one_port 172.23.100.101:1025\n" + "pmacAsynIPConfigure geobrick_two_port 172.23.100.101:1025\n" "\n# pmacCreateController AsynPortName PmacAsynPort Address NumAxes " "MovingPollPeriod IdlePollPeriod\n" "pmacCreateController geobrick_enabled geobrick_one_port 0 8 800 200\n" From 31647ea22deb2519d572c7a154d2474a93848d43 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 13:26:48 +0000 Subject: [PATCH 14/30] update ibek-defs --- ibek-defs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ibek-defs b/ibek-defs index 508d36c43..8772cc34e 160000 --- a/ibek-defs +++ b/ibek-defs @@ -1 +1 @@ -Subproject commit 508d36c431f80fca0b53cb575fd596cc379e1731 +Subproject commit 8772cc34ebfca1803b0e77a932813b99570fbdfe From c406526d403fe758e50604bbb721b12b8ef32d1a Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 13:32:15 +0000 Subject: [PATCH 15/30] update TODOs --- src/ibek/support.py | 9 --------- tests/test_pydantic.py | 8 -------- 2 files changed, 17 deletions(-) diff --git a/src/ibek/support.py b/src/ibek/support.py index dbbfb6aca..2f0cb660d 100644 --- a/src/ibek/support.py +++ b/src/ibek/support.py @@ -31,15 +31,6 @@ class Arg(BaseSettings): ) -# FloatArg must be defined before StrArg, otherwise we get: -# -# TypeError: Invalid JSON type -# -# During Support.deserialize, when default float values in pmac.ibek.support.yaml do not -# have a trailing 'f'. It is due to the order of declaration of subclasses of -# Arg. When StrArg is before FloatArg, apischema attempts to deserialize as a -# string first. The coercion from str to number requires a trailing f if there -# is a decimal. TODO is this still an issue with Pydantic? class FloatArg(Arg): """An argument with a float value""" diff --git a/tests/test_pydantic.py b/tests/test_pydantic.py index 984512331..22711e34d 100644 --- a/tests/test_pydantic.py +++ b/tests/test_pydantic.py @@ -24,10 +24,6 @@ def run_cli(*args): def test_ioc_schema(tmp_path: Path, samples: Path): """generate the global ibek schema""" - # TODO: temporarily using a fixed path to try schema in vscode - tmp_path = Path("/tmp") / "pydantic_test" - tmp_path.mkdir(exist_ok=True) - ibek_schema_path = tmp_path / "ibek.schema.json" run_cli("ibek-schema", ibek_schema_path) expected = json.loads((samples / "schemas" / "ibek.defs.schema.json").read_text()) @@ -52,10 +48,6 @@ def test_ioc_schema(tmp_path: Path, samples: Path): def test_ioc_build(tmp_path: Path, samples: Path): """generate the global ibek schema""" - # TODO: temporarily using a fixed path to try schema in vscode - tmp_path = Path("/tmp") / "pydantic_test" - tmp_path.mkdir(exist_ok=True) - pydantic_sample_path = samples / "pydantic" support_yaml_path = pydantic_sample_path / "test.ibek.support.yaml" From 899f7feb36cf7dcf942d49f3c2f1393c09b53403 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 13:42:47 +0000 Subject: [PATCH 16/30] fix dependencies --- pyproject.toml | 2 -- src/ibek/support.py | 3 --- 2 files changed, 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e7423617c..224db3d39 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,12 +15,10 @@ classifiers = [ ] description = "IOC Builder for EPICS and Kubernetes" dependencies = [ - "typing-extensions", "pydantic", "typer", "ruamel.yaml", "jinja2", - "typing-extensions;python_version<'3.8'", ] # Add project dependencies here, e.g. ["click", "numpy"] dynamic = ["version"] license.file = "LICENSE" diff --git a/src/ibek/support.py b/src/ibek/support.py index 2f0cb660d..382374b48 100644 --- a/src/ibek/support.py +++ b/src/ibek/support.py @@ -109,7 +109,6 @@ class Function(BaseSettings): header: str = Field( description="commands/comments to appear before the function", default="" ) - # TODO will be an enum when: When = Field(description="one of first / every / last", default="every") type: Literal["function"] = "function" @@ -121,7 +120,6 @@ class Comment(BaseSettings): """ type: Literal["comment"] = "comment" - # TODO will be an enum when: When = Field(description="One of first / every / last", default="every") value: str = Field( description="A comment to add into the startup script", default="" @@ -134,7 +132,6 @@ class Text(BaseSettings): """ type: Literal["text"] = "text" - # TODO will be an enum when: str = Field(description="One of first / every / last", default="every") value: str = Field(description="raw text to add to the startup script", default="") From e21035cb25a619482b4ceb576ebd4ccb9d94edbc Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 13:48:58 +0000 Subject: [PATCH 17/30] add check of defaults to pydantic tests --- tests/samples/pydantic/st.cmd | 2 +- tests/samples/pydantic/test.ibek.ioc.schema.json | 2 +- tests/samples/pydantic/test.ibek.ioc.yaml | 1 - tests/samples/pydantic/test.ibek.support.yaml | 1 + 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/samples/pydantic/st.cmd b/tests/samples/pydantic/st.cmd index ece54d7ab..e837b94c6 100644 --- a/tests/samples/pydantic/st.cmd +++ b/tests/samples/pydantic/st.cmd @@ -6,7 +6,7 @@ ioc_registerRecordDeviceDriver pdbbase # testValues TestValue -testValues test_value:AsynPort1.10.0.0.1 +testValues test_value:AsynPort1.127.0.0.1 testValues test_value:AsynPort2.10.0.0.2 # exampleTestFunction AsynPortIP Name Value diff --git a/tests/samples/pydantic/test.ibek.ioc.schema.json b/tests/samples/pydantic/test.ibek.ioc.schema.json index ae768e509..7daf0ead5 100644 --- a/tests/samples/pydantic/test.ibek.ioc.schema.json +++ b/tests/samples/pydantic/test.ibek.ioc.schema.json @@ -44,7 +44,7 @@ "type": "string" }, "IP": { - "default": null, + "default": "127.0.0.1", "description": "IP address of port", "title": "Ip", "type": "string" diff --git a/tests/samples/pydantic/test.ibek.ioc.yaml b/tests/samples/pydantic/test.ibek.ioc.yaml index de4db9fea..51bbeb2f9 100644 --- a/tests/samples/pydantic/test.ibek.ioc.yaml +++ b/tests/samples/pydantic/test.ibek.ioc.yaml @@ -9,7 +9,6 @@ generic_ioc_image: ghcr.io/epics-containers/ioc-template:23.3.2 entities: - type: pydantic_test.AnAsynPort name: AsynPort1 - IP: 10.0.0.1 - type: pydantic_test.AnAsynPort name: AsynPort2 diff --git a/tests/samples/pydantic/test.ibek.support.yaml b/tests/samples/pydantic/test.ibek.support.yaml index ea58ca7c3..b57c0c3db 100644 --- a/tests/samples/pydantic/test.ibek.support.yaml +++ b/tests/samples/pydantic/test.ibek.support.yaml @@ -13,6 +13,7 @@ defs: - type: str name: IP description: IP address of port + default: 127.0.0.1 values: - name: test_value From ab4e25c5739cf4a8a59fa5e3175faf7ba375739b Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 13:56:42 +0000 Subject: [PATCH 18/30] fix lint --- src/ibek/render.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ibek/render.py b/src/ibek/render.py index ff2332ad5..24fa469bc 100644 --- a/src/ibek/render.py +++ b/src/ibek/render.py @@ -45,7 +45,7 @@ def render_text( raise NotImplementedError("When.last not yet implemented") # Render Jinja entries in the text - result = render_with_utils(instance, text) + result = render_with_utils(instance, text) # type: ignore if result == "": return "" @@ -144,7 +144,7 @@ def render_database(self, instance: Entity) -> Optional[str]: f'msi -I${{EPICS_DB_INCLUDE_PATH}} -M"{db_arg_string}" "{db_file}"\n' ) - db_txt = render_with_utils(instance, jinja_txt) + db_txt = render_with_utils(instance, jinja_txt) # type: ignore return db_txt + "\n" @@ -161,7 +161,7 @@ def render_environment_variables(self, instance: Entity) -> Optional[str]: for variable in variables: # Substitute the name and value of the environment variable from args env_template = f"epicsEnvSet {variable.name} {variable.value}" - env_var_txt += render_with_utils(instance, env_template) + env_var_txt += render_with_utils(instance, env_template) # type: ignore return env_var_txt + "\n" def render_elements( From a8f88dc8b7d8cd1426cd9fef8c4b875533c21e74 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 14:07:44 +0000 Subject: [PATCH 19/30] remove back quotes in docstrings --- docs/conf.py | 2 +- src/ibek/ioc.py | 4 ++-- src/ibek/modules.py | 4 ++-- src/ibek/render.py | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index fbe43fb2a..6681aae85 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,7 +50,7 @@ # If true, Sphinx will warn about all references where the target cannot # be found. -nitpicky = True +nitpicky = False # A list of (type, target) tuples (by default empty) that should be ignored when # generating warnings in "nitpicky mode". Note that type should include the diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index 43e84bda2..078559080 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -114,8 +114,8 @@ def lookup_instance(cls, id): def make_entity_models(support: Support): """ - Create `Entity` subclasses for all `Definition` instances in the given - `Support` instance. Returns a list of the Entity subclasses Models. + Create Entity subclasses for all Definition instances in the given + Support instance. Returns a list of the Entity subclasses Models. """ entity_models = [] diff --git a/src/ibek/modules.py b/src/ibek/modules.py index 24d34ac37..6310aefde 100644 --- a/src/ibek/modules.py +++ b/src/ibek/modules.py @@ -1,5 +1,5 @@ -"""Blank module to be populated with modules, which contain `Entity` subclasses -made with `make_entity_classes`""" +"""Blank module to be populated with modules, which contain Entity subclasses +made with make_entity_models""" from typing import List __all__: List[str] = [] diff --git a/src/ibek/render.py b/src/ibek/render.py index 24fa469bc..686be8e15 100644 --- a/src/ibek/render.py +++ b/src/ibek/render.py @@ -23,14 +23,14 @@ def render_text( self, instance: Entity, text: str, when=When.every, suffix="" ) -> str: """ - Add in the next line of text, honouring the ``once`` flag which will + Add in the next line of text, honouring the once flag which will only add the line once per IOC. Jinja rendering of values/args has already been done in Entity.__post_init__ but we pass all strings though jinja again to render any other jinja in the IOC (e.g. database and function entries) - ``once`` uses the name of the definition + suffix to track which lines + once uses the name of the definition + suffix to track which lines have been rendered already. The suffix can be used where a given Entity has more than one element to render once (e.g. functions) """ From 72188cfd4764029f19d713a9503d308c188d5e5f Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 14:18:00 +0000 Subject: [PATCH 20/30] try to fix docs --- docs/conf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 6681aae85..f6aafa4c5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,7 +50,7 @@ # If true, Sphinx will warn about all references where the target cannot # be found. -nitpicky = False +nitpicky = True # A list of (type, target) tuples (by default empty) that should be ignored when # generating warnings in "nitpicky mode". Note that type should include the @@ -65,6 +65,7 @@ ("py:class", "'object'"), ("py:class", "'id'"), ("py:class", "typing_extensions.Literal"), + [("py:class", "type")], ] # Both the class’ and the __init__ method’s docstring are concatenated and From 69d050e736a71f7c22be9942357e5995db1f6017 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 14 Jul 2023 14:49:31 +0000 Subject: [PATCH 21/30] remove apischema sphinx plugin --- docs/conf.py | 6 ++++-- pyproject.toml | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f6aafa4c5..d87f1d3b3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -46,11 +46,13 @@ "sphinx_copybutton", # For the card element "sphinx_design", + # for pydantic + "sphinx_autodoc_typehints", ] # If true, Sphinx will warn about all references where the target cannot # be found. -nitpicky = True +nitpicky = False # A list of (type, target) tuples (by default empty) that should be ignored when # generating warnings in "nitpicky mode". Note that type should include the @@ -65,7 +67,7 @@ ("py:class", "'object'"), ("py:class", "'id'"), ("py:class", "typing_extensions.Literal"), - [("py:class", "type")], + ("py:class", "type"), ] # Both the class’ and the __init__ method’s docstring are concatenated and diff --git a/pyproject.toml b/pyproject.toml index 224db3d39..a5595b547 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,6 @@ dev = [ "pydata-sphinx-theme>=0.12", "pytest", "pytest-cov", - "sphinx_apischema", "sphinx-autobuild", "sphinx-copybutton", "sphinx-design", From 1a727d52bd534176fe2a633197e89cc977f8198d Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 17 Jul 2023 09:59:29 +0000 Subject: [PATCH 22/30] fix sphinx --- docs/conf.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index d87f1d3b3..fac58f8b4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -40,19 +40,15 @@ "sphinx.ext.viewcode", # Adds the inheritance-diagram generation directive "sphinx.ext.inheritance_diagram", - # Makes autodoc understand apischema annotated classes/functions - "sphinx_apischema", # Add a copy button to each code block "sphinx_copybutton", # For the card element "sphinx_design", - # for pydantic - "sphinx_autodoc_typehints", ] # If true, Sphinx will warn about all references where the target cannot # be found. -nitpicky = False +nitpicky = True # A list of (type, target) tuples (by default empty) that should be ignored when # generating warnings in "nitpicky mode". Note that type should include the @@ -67,12 +63,11 @@ ("py:class", "'object'"), ("py:class", "'id'"), ("py:class", "typing_extensions.Literal"), - ("py:class", "type"), ] -# Both the class’ and the __init__ method’s docstring are concatenated and -# inserted into the main body of the autoclass directive -autoclass_content = "both" +# Dont use the __init__ docstring because pydantic base classes cause sphinx +# to generate a lot of warnings +autoclass_content = "class" # Order the members by the order they appear in the source code autodoc_member_order = "bysource" @@ -80,6 +75,7 @@ # Don't inherit docstrings from baseclasses autodoc_inherit_docstrings = False + # Output graphviz directive produced images in a scalable format graphviz_output_format = "svg" From fd14fb44092910e64ac3e3423a2764b6c9cc6e62 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 17 Jul 2023 09:59:55 +0000 Subject: [PATCH 23/30] add comment re schema error messages --- src/ibek/ioc.py | 14 +++++++++++++- tests/samples/generate_samples.sh | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ibek/ioc.py b/src/ibek/ioc.py index 078559080..50a230f0d 100644 --- a/src/ibek/ioc.py +++ b/src/ibek/ioc.py @@ -29,7 +29,19 @@ class Entity(BaseSettings): @model_validator(mode="after") # type: ignore def add_ibek_attributes(cls, entity: Entity): - """Whole Entity model validation""" + """ + Whole Entity model validation + + TODO at present an object reference to an ID where the referred object violates + schema is seen as "KeyError: "object XXX not found in [...]" which hides the + schema violation error. + + This could potentially be fixed by doing the validation here instead + (removing extra:forbid from the model_config). BUT, at present passing + the info arg to this function receives a dict of the IOC instance + that created this entity, not the entity itself. This may be a + pydantic bug? + """ # find the id field in this Entity if it has one ids = set(a.name for a in entity.__definition__.args if isinstance(a, IdArg)) diff --git a/tests/samples/generate_samples.sh b/tests/samples/generate_samples.sh index 322eff3ee..48fc228d7 100755 --- a/tests/samples/generate_samples.sh +++ b/tests/samples/generate_samples.sh @@ -13,6 +13,7 @@ export DEFS=${SAMPLES_DIR}/../../ibek-defs # this is so relative schema mode lines work cd $SAMPLES_DIR +set -x echo making the support yaml schema ibek ibek-schema ${SAMPLES_DIR}/schemas/ibek.defs.schema.json From 90ee451f56596bcb8febf3fa3536c5adad1e0653 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 17 Jul 2023 13:40:19 +0000 Subject: [PATCH 24/30] add simple references example --- examples/test_refs.py | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 examples/test_refs.py diff --git a/examples/test_refs.py b/examples/test_refs.py new file mode 100644 index 000000000..2f1f6b282 --- /dev/null +++ b/examples/test_refs.py @@ -0,0 +1,56 @@ +from __future__ import annotations + +from typing import Dict, List, Optional + +from pydantic import BaseModel, ConfigDict, Field, 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)}") + + +class Entities(BaseModel): + entities: List[Entity] = Field(..., description="The entities in this model") + + +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"}, + ] + } +) From 003f6b234e206ff693559ae8db0586bcad6b8d31 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 17 Jul 2023 14:25:35 +0000 Subject: [PATCH 25/30] 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 From 479c330456358c9af514713137f18648e8e246e4 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 17 Jul 2023 14:39:15 +0000 Subject: [PATCH 26/30] another example of refs - more like ioc.py --- examples/test_refs3.py | 90 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 examples/test_refs3.py diff --git a/examples/test_refs3.py b/examples/test_refs3.py new file mode 100644 index 000000000..c6607aa4a --- /dev/null +++ b/examples/test_refs3.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +from typing import Dict, Literal, Optional, Sequence, Union + +from pydantic import ( + BaseModel, + ConfigDict, + Field, + RootModel, + create_model, + field_validator, + model_validator, +) + +id_to_entity: Dict[str, Entity] = {} + + +class Entity(BaseModel): + type: Literal["e"] + 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 + +entity_models = [Entity2, Entity2] + + +class EntityModel(RootModel): + root: Union[tuple(entity_models)] = Field(discriminator="type") # type: ignore + + +class Entities(BaseModel): + model_config = ConfigDict(extra="forbid") + entities: Sequence[EntityModel] = Field( # type: ignore + description="List of entities this IOC instantiates" + ) + + +model1 = Entities( + **{ + "entities": [ + {"type": "e", "name": "one", "value": "OneValue"}, + {"type": "e", "name": "two", "value": "TwoValue", "ref": "one"}, + ] + } +) + +# demonstrate that entity one has a reference to entity two +assert model1.entities[1].root.ref.value == "OneValue" + +# this should throw an error because entity one has illegal arguments +model2 = Entities( + **{ + "entities": [ + { + "type": "e", + "name": "one", + "value": "OneValue", + "illegal": "bad argument", + }, + {"type": "e", "name": "two", "value": "TwoValue", "ref": "one"}, + ] + } +) From b44b119618f582ac84eb72f4663f77289a563f00 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 17 Jul 2023 19:49:57 +0000 Subject: [PATCH 27/30] fix pydantic test broken yaml file --- examples/test_refs3.py | 38 ++++++++++++++++------- tests/samples/pydantic/test.ibek.ioc.yaml | 2 +- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/examples/test_refs3.py b/examples/test_refs3.py index c6607aa4a..6b7c0935b 100644 --- a/examples/test_refs3.py +++ b/examples/test_refs3.py @@ -16,7 +16,7 @@ class Entity(BaseModel): - type: Literal["e"] + type: str = Field(description="The type of this entity") name: str = Field(..., description="The name of this entity") value: str = Field(..., description="The value of this entity") ref: Optional[str] = Field( @@ -31,6 +31,14 @@ def add_ibek_attributes(cls, entity: Entity): return entity +class Entity1(Entity): + type: Literal["e1"] = Field(description="The type of this entity") + + +class Entity2(Entity): + type: Literal["e2"] = Field(description="The type of this entity") + + @field_validator("ref", mode="after") def lookup_instance(cls, id): try: @@ -41,32 +49,38 @@ def lookup_instance(cls, id): validators = {"Entity": lookup_instance} -# add validator to the Entity class using create model -Entity2 = create_model( - "Entity", +# add validator to the Entity classes using create model +EntityOne = create_model( + "EntityOne", + __validators__=validators, + __base__=Entity1, +) # type: ignore + +EntityTwo = create_model( + "EntityTwo", __validators__=validators, - __base__=Entity, + __base__=Entity2, ) # type: ignore -entity_models = [Entity2, Entity2] +entity_models = (EntityOne, EntityTwo) class EntityModel(RootModel): - root: Union[tuple(entity_models)] = Field(discriminator="type") # type: ignore + root: Union[entity_models] = Field(discriminator="type") # type: ignore class Entities(BaseModel): model_config = ConfigDict(extra="forbid") entities: Sequence[EntityModel] = Field( # type: ignore - description="List of entities this IOC instantiates" + description="List of entities classes we want to create" ) model1 = Entities( **{ "entities": [ - {"type": "e", "name": "one", "value": "OneValue"}, - {"type": "e", "name": "two", "value": "TwoValue", "ref": "one"}, + {"type": "e1", "name": "one", "value": "OneValue"}, + {"type": "e2", "name": "two", "value": "TwoValue", "ref": "one"}, ] } ) @@ -78,13 +92,13 @@ class Entities(BaseModel): model2 = Entities( **{ "entities": [ + {"type": "e2", "name": "two", "value": "TwoValue", "ref": "one"}, { - "type": "e", + "type": "e1", "name": "one", "value": "OneValue", "illegal": "bad argument", }, - {"type": "e", "name": "two", "value": "TwoValue", "ref": "one"}, ] } ) diff --git a/tests/samples/pydantic/test.ibek.ioc.yaml b/tests/samples/pydantic/test.ibek.ioc.yaml index 398bc42bc..51bbeb2f9 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 - IPpp: 10.0.0.2 + IP: 10.0.0.2 - type: pydantic_test.Consumer name: A Consumer From 9b9891f8967006c0fab7473e530b6bd856d5008a Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Tue, 18 Jul 2023 07:00:34 +0000 Subject: [PATCH 28/30] update examples with more info --- .vscode/launch.json | 2 +- examples/README.md | 15 +++ examples/{test_refs.py => test_refs1.py} | 0 examples/yaml/test-ibek.sh | 11 ++ examples/yaml/test.ibek.ioc.schema.json | 128 +++++++++++++++++++++++ examples/yaml/test.ibek.ioc.yaml | 17 +++ examples/yaml/test.ibek.support.yaml | 31 ++++++ 7 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 examples/README.md rename examples/{test_refs.py => test_refs1.py} (100%) create mode 100755 examples/yaml/test-ibek.sh create mode 100644 examples/yaml/test.ibek.ioc.schema.json create mode 100644 examples/yaml/test.ibek.ioc.yaml create mode 100644 examples/yaml/test.ibek.support.yaml diff --git a/.vscode/launch.json b/.vscode/launch.json index f65cb376b..d41428bfb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Debug Unit Test", + "name": "Debug example test", "type": "python", "request": "launch", "justMyCode": false, diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 000000000..228a21ce1 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,15 @@ +Intro +===== + +These example scripts are used to investigate an issue with error reporting in ibek. + +They also serve as a good minimal example of how to do object references within a pydantic 2 model. + +The incrementing numeric suffix represents a progression from the most simple possible example of a pydantic model with a reference to a more complex example that more closely resembles ibek's approach which dynamically creates the Entity classes. + +In the yaml subfolder is a support module yaml and IOC yaml that will make ibek load a very similar model to that described in these test scripts. + +Issue under investigation +========================= + +The issue is that when an object refers to another object then the error reported is that the offending object's id cannot be found. This masks the underlying schema issue which is what should be reported first. The custom field validator created in make_entity_model seems to be throwing the error before the schema validation issue is reported. diff --git a/examples/test_refs.py b/examples/test_refs1.py similarity index 100% rename from examples/test_refs.py rename to examples/test_refs1.py diff --git a/examples/yaml/test-ibek.sh b/examples/yaml/test-ibek.sh new file mode 100755 index 000000000..05bf13ea7 --- /dev/null +++ b/examples/yaml/test-ibek.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# This script runs tests against ibek that use the same set of objects +# employed by the test_refsX.py scripts in the above folder. +# It demonstrates that unline the above scripts ibek gets the wrong error +# KeyError: 'object one not found in []' +# when it should get +# Extra inputs are not permitted [type=extra_forbidden, input_value='bad argument', input_type=str] + +ibek ioc-schema test.ibek.support.yaml test.ibek.support.schema.json +ibek build-startup test.ibek.ioc.yaml test.ibek.support.yaml diff --git a/examples/yaml/test.ibek.ioc.schema.json b/examples/yaml/test.ibek.ioc.schema.json new file mode 100644 index 000000000..7c5aa087c --- /dev/null +++ b/examples/yaml/test.ibek.ioc.schema.json @@ -0,0 +1,128 @@ +{ + "$defs": { + "EntityModel": { + "discriminator": { + "mapping": { + "test.e1": "#/$defs/test_e1", + "test.e2": "#/$defs/test_e2" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/$defs/test_e1" + }, + { + "$ref": "#/$defs/test_e2" + } + ], + "title": "EntityModel" + }, + "test_e1": { + "additionalProperties": false, + "properties": { + "type": { + "const": "test.e1", + "default": "test.e1", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "name": { + "default": null, + "description": "identifier e1", + "title": "Name", + "type": "string" + }, + "value": { + "default": null, + "description": "value of e1", + "title": "Value", + "type": "string" + }, + "ref": { + "default": null, + "description": "reference to another entity", + "title": "Ref" + } + }, + "title": "test_e1", + "type": "object" + }, + "test_e2": { + "additionalProperties": false, + "properties": { + "type": { + "const": "test.e2", + "default": "test.e2", + "description": "The type of this entity", + "title": "Type" + }, + "entity_enabled": { + "default": true, + "description": "enable or disable this entity instance", + "title": "Entity Enabled", + "type": "boolean" + }, + "name": { + "default": null, + "description": "identifier e2", + "title": "Name", + "type": "string" + }, + "value": { + "default": null, + "description": "value of e2", + "title": "Value", + "type": "string" + }, + "ref": { + "default": null, + "description": "reference to another entity", + "title": "Ref" + } + }, + "title": "test_e2", + "type": "object" + } + }, + "additionalProperties": false, + "properties": { + "ioc_name": { + "description": "Name of IOC instance", + "title": "Ioc Name", + "type": "string" + }, + "description": { + "description": "Description of what the IOC does", + "title": "Description", + "type": "string" + }, + "generic_ioc_image": { + "description": "The generic IOC container image registry URL", + "title": "Generic Ioc Image", + "type": "string" + }, + "entities": { + "description": "List of entities this IOC instantiates", + "items": { + "$ref": "#/$defs/EntityModel" + }, + "title": "Entities", + "type": "array" + } + }, + "required": [ + "ioc_name", + "description", + "generic_ioc_image", + "entities" + ], + "title": "NewIOC", + "type": "object" +} \ No newline at end of file diff --git a/examples/yaml/test.ibek.ioc.yaml b/examples/yaml/test.ibek.ioc.yaml new file mode 100644 index 000000000..35ed8a646 --- /dev/null +++ b/examples/yaml/test.ibek.ioc.yaml @@ -0,0 +1,17 @@ +# yaml-language-server: $schema=test.ibek.ioc.schema.json + +ioc_name: test +description: a basic example for testing ioc-template +generic_ioc_image: ghcr.io/epics-containers/ioc-template:23.3.2 + +entities: + - type: test.e1 + name: one + value: OneValue + illegal: bad argument + # above to demonstrate how ibek handles this error incorrectly + + - type: test.e2 + name: two + value: TwoValue + ref: one diff --git a/examples/yaml/test.ibek.support.yaml b/examples/yaml/test.ibek.support.yaml new file mode 100644 index 000000000..348264ac8 --- /dev/null +++ b/examples/yaml/test.ibek.support.yaml @@ -0,0 +1,31 @@ +# yaml-language-server: $schema=../../tests/samples/schemas/ibek.defs.schema.json +module: test + +defs: + - name: e1 + description: Example One + args: + - type: id + name: name + description: identifier e1 + - type: str + name: value + description: value of e1 + - type: object + name: ref + description: reference to another entity + default: null + + - name: e2 + description: Example One + args: + - type: id + name: name + description: identifier e2 + - type: str + name: value + description: value of e2 + - type: object + name: ref + description: reference to another entity + default: null From 99b5ab8cbc5e3bca295fa472f31fdb4ce6f726da Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Tue, 18 Jul 2023 07:33:10 +0000 Subject: [PATCH 29/30] add test example that is identical to ibek? --- examples/README.md | 14 +++++ examples/test_refs4.py | 115 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 examples/test_refs4.py diff --git a/examples/README.md b/examples/README.md index 228a21ce1..a9e8532e5 100644 --- a/examples/README.md +++ b/examples/README.md @@ -13,3 +13,17 @@ Issue under investigation ========================= The issue is that when an object refers to another object then the error reported is that the offending object's id cannot be found. This masks the underlying schema issue which is what should be reported first. The custom field validator created in make_entity_model seems to be throwing the error before the schema validation issue is reported. + +At present for the incorrect schema in entity e1 ibek reports: + +``` +KeyError: 'object one not found in []' +``` + +And test_refs4.py reports + +``` +Extra inputs are not permitted [type=extra_forbidden, input_value='bad argument', input_type=str] +``` + +The latter is the useful error that points you at the root cause. \ No newline at end of file diff --git a/examples/test_refs4.py b/examples/test_refs4.py new file mode 100644 index 000000000..706b61704 --- /dev/null +++ b/examples/test_refs4.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +from typing import Dict, Literal, Optional, Sequence, Union + +from pydantic import ( + BaseModel, + ConfigDict, + Field, + RootModel, + create_model, + field_validator, + model_validator, +) +from pydantic.fields import FieldInfo + +id_to_entity: Dict[str, Entity] = {} + + +class Entity(BaseModel): + type: str = Field(description="The type of this entity") + 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 + + +args = {"type": (Literal["e1"], FieldInfo(description="The type of this 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 classes using create model +EntityOne = create_model( + "EntityOne", + **args, + __validators__=validators, + __base__=Entity, +) # type: ignore + +args2 = {"type": (Literal["e2"], FieldInfo(description="The type of this entity"))} + + +@field_validator("ref", mode="after") +def lookup_instance2(cls, id): + try: + return id_to_entity[id] + except KeyError: + raise KeyError(f"object {id} not found in {list(id_to_entity)}") + + +validators2 = {"Entity": lookup_instance2} + +EntityTwo = create_model( + "EntityTwo", + **args2, + __validators__=validators2, + __base__=Entity, +) # type: ignore s + +entity_models = (EntityOne, EntityTwo) + + +class EntityModel(RootModel): + root: Union[entity_models] = Field(discriminator="type") # type: ignore + + +class Entities(BaseModel): + model_config = ConfigDict(extra="forbid") + entities: Sequence[EntityModel] = Field( # type: ignore + description="List of entities classes we want to create" + ) + + +model1 = Entities( + **{ + "entities": [ + {"type": "e1", "name": "one", "value": "OneValue"}, + {"type": "e2", "name": "two", "value": "TwoValue", "ref": "one"}, + ] + } +) + +# demonstrate that entity one has a reference to entity two +assert model1.entities[1].root.ref.value == "OneValue" + +# this should throw an error because entity one has illegal arguments +model2 = Entities( + **{ + "entities": [ + { + "type": "e1", + "name": "one", + "value": "OneValue", + "illegal": "bad argument", + }, + {"type": "e2", "name": "two", "value": "TwoValue", "ref": "one"}, + ] + } +) From dd3c950daf776e18b2c901da99cb4795a027129f Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Tue, 18 Jul 2023 10:08:00 +0000 Subject: [PATCH 30/30] updated examples to demo issue --- examples/README.md | 11 ++++++++++- examples/test_refs1.py | 12 ++++++++---- examples/yaml/test-ibek.sh | 2 +- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/examples/README.md b/examples/README.md index a9e8532e5..5701b7b6e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -26,4 +26,13 @@ And test_refs4.py reports Extra inputs are not permitted [type=extra_forbidden, input_value='bad argument', input_type=str] ``` -The latter is the useful error that points you at the root cause. \ No newline at end of file +The latter is the useful error that points you at the root cause. + +Resolution +========== + +The simplest test_refs1.py has been updated to demo the issue (forgot that +entity "one" already existed in model1!). + +I've posted a discussion on the subject here +https://github.com/pydantic/pydantic/discussions/6731 \ No newline at end of file diff --git a/examples/test_refs1.py b/examples/test_refs1.py index 2f1f6b282..78c7e2e09 100644 --- a/examples/test_refs1.py +++ b/examples/test_refs1.py @@ -42,15 +42,19 @@ class Entities(BaseModel): } ) -# demonstrate that entity one has a reference to entity two +# demonstrate that entity two has a reference to entity one assert model1.entities[1].ref.value == "OneValue" -# this should throw an error because entity one has illegal arguments +# this should throw an error because entity one_again has illegal arguments +# BUT the error shown is: +# KeyError: "object one_again not found in ['one', 'two']" +# which masks the underlying schema violation error that should look like: +# Extra inputs are not permitted [type=extra_forbidden, input_value='bad argument', model2 = Entities( **{ "entities": [ - {"name": "one", "value": "OneValue", "illegal": "bad argument"}, - {"name": "two", "value": "TwoValue", "ref": "one"}, + {"name": "one_again", "value": "OneValue", "illegal": "bad argument"}, + {"name": "two_again", "value": "TwoValue", "ref": "one_again"}, ] } ) diff --git a/examples/yaml/test-ibek.sh b/examples/yaml/test-ibek.sh index 05bf13ea7..d67708339 100755 --- a/examples/yaml/test-ibek.sh +++ b/examples/yaml/test-ibek.sh @@ -7,5 +7,5 @@ # when it should get # Extra inputs are not permitted [type=extra_forbidden, input_value='bad argument', input_type=str] -ibek ioc-schema test.ibek.support.yaml test.ibek.support.schema.json +ibek ioc-schema test.ibek.support.yaml test.ibek.ioc.schema.json ibek build-startup test.ibek.ioc.yaml test.ibek.support.yaml