Coverage for /opt/conda/envs/apienv/lib/python3.10/site-packages/daiquiri/core/schema/hardware/__init__.py: 98%
91 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-02-06 02:13 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-02-06 02:13 +0000
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3from marshmallow import Schema, fields, validates_schema, ValidationError, post_load
5from daiquiri.core.schema.validators import ValidatedRegexp, Any
7import logging
9logger = logging.getLogger(__name__)
12class HardwareObjectBaseSchema(Schema):
13 """Hardware as exposed by the server to the web client"""
15 id = fields.Str()
16 """Unique identifier for this object"""
18 protocol = fields.Str()
19 """Protocol, like 'bliss', 'tango'..."""
21 type = fields.Str()
22 """Normalized daiquiri hardware type"""
24 online = fields.Bool()
25 """True if the hardware is online"""
27 errors = fields.List(fields.Dict())
28 """A list of errors collected during the execution of the hardware"""
30 name = fields.Str()
31 """A fullname which identify the hardware for users"""
33 alias = fields.Str()
34 """A short name which can be used to identify the hardware for users"""
36 require_staff = fields.Bool()
37 """True if any action on the hardware requires staff privilege"""
39 callables = fields.List(fields.Str())
40 """Available commands provided by the hardware"""
42 properties = fields.Dict()
43 """Exposed state of the hardware"""
45 user_tags = fields.List(fields.Str())
46 """List of user tags in which the hardware is categorized"""
48 locked = fields.Str(allow_none=True)
49 """If not None, the device is locked for this reason, and no actions can be requested."""
52class SetObjectProperty(Schema):
53 property = ValidatedRegexp("word", required=True)
54 value = Any(required=True, allow_none=True)
57class CallObjectFunction(Schema):
58 function = ValidatedRegexp("word", required=True)
59 value = Any()
62class HardwareGroupSchema(Schema):
63 groupid = fields.Str(required=True)
64 name = fields.Str(required=True)
65 description = fields.Str()
66 objects = fields.List(fields.Str(), required=True)
67 state = fields.Bool()
70class HardwareTypeSchema(Schema):
71 type = fields.Str()
72 schema = fields.Str()
75class HOConfigAttribute(Schema):
76 """The Hardware Object Config Attribute Schema"""
78 id = fields.Str(required=True, metadata={"description": "Attribute id"})
79 name = fields.Str(metadata={"description": "Attribute name (can be customised)"})
80 ui_schema = fields.Dict(
81 metadata={"description": "Define how the UI renders this attribute"}
82 )
83 type = fields.Str(
84 metadata={
85 "enum": ["float", "int", "bool", "str"],
86 "description": "Attribute type",
87 }
88 )
89 step = fields.Float(metadata={"description": "Step size for attribute"})
90 min = fields.Float(metadata={"description": "Minimum value for attribute"})
91 max = fields.Float(metadata={"description": "Maximum value for attribute"})
94class HOConfigSchema(Schema):
95 """HardwareObject base configuration schema"""
97 name = fields.Str(metadata={"description": "Object name"})
98 id = fields.Str(metadata={"description": "Object id"})
99 auto_id = fields.Bool(
100 metadata={"description": "Whether the id was automatically generated"}
101 )
102 protocol = fields.Str(metadata={"description": "Protocol handler to use"})
103 url = fields.Str(
104 metadata={"description": "Url of the device including which protocol to use"}
105 )
106 require_staff = fields.Bool(
107 metadata={"description": "Whether this object requires staff to modify"}
108 )
109 attributes = fields.Nested(
110 HOConfigAttribute,
111 many=True,
112 metadata={"description": "Attribute configuration for run time schemas"},
113 )
115 @validates_schema
116 def schema_validate(self, data, **kwargs):
117 if not (data.get("protocol") or data.get("url")):
118 raise ValidationError(
119 "Object must have either a `protocol` or `url` defined"
120 )
122 @post_load
123 def populate(self, data, **kwargs):
124 if data.get("url"):
125 protocol, rest = data["url"].split("://")
126 data["protocol"] = protocol
128 if not data.get("id"):
129 parts = rest.split("/")
130 data["id"] = parts[-1]
131 data["auto_id"] = True
133 if not data.get("name"):
134 data["name"] = data.get("id")
136 return data
139class HardwareSchema(Schema):
140 def read_only(self, prop):
141 return self.fields[prop].metadata.get("readOnly", False)
143 def __contains__(self, val):
144 return val in self.fields
146 def __iter__(self):
147 self.__iter = iter(self.fields.keys())
148 return self.__iter
150 def __next__(self):
151 return next(self.__iter)
153 def validate(self, prop, value):
154 data = {}
155 data[prop] = value
156 valid = self.load(data)
158 return valid[prop]