Skip to content

Commit 0f785f4

Browse files
authored
Merge pull request #258 from DiamondLightSource/fastcs-odin-dev
fastcs-odin developments
2 parents 9990065 + 5ee2f5d commit 0f785f4

File tree

5 files changed

+37
-16
lines changed

5 files changed

+37
-16
lines changed

src/fastcs/attributes.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66

77
from fastcs.attribute_io_ref import AttributeIORefT
88
from fastcs.datatypes import ATTRIBUTE_TYPES, DataType, T
9-
from fastcs.logging import logger as _logger
9+
from fastcs.logging import bind_logger
1010
from fastcs.tracer import Tracer
1111

1212
ONCE = float("inf")
1313
"""Special value to indicate that an attribute should be updated once on start up."""
1414

15-
logger = _logger.bind(logger_name=__name__)
15+
logger = bind_logger(logger_name=__name__)
1616

1717

1818
class Attribute(Generic[T, AttributeIORefT], Tracer):
@@ -171,6 +171,7 @@ async def update(self, value: T) -> None:
171171
logger.opt(exception=e).error(
172172
"On update callback failed", attribute=self, value=value
173173
)
174+
raise
174175

175176
def add_on_update_callback(self, callback: AttrOnUpdateCallback[T]) -> None:
176177
"""Add a callback to be called when the value of the attribute is updated
@@ -248,7 +249,8 @@ async def put(self, setpoint: T, sync_setpoint: bool = False) -> None:
248249
be rejected.
249250
250251
To directly change the value of the attribute, for example from an update loop
251-
that has read a new value from some underlying source, call the ``set`` method.
252+
that has read a new value from some underlying source, call the ``update``
253+
method.
252254
253255
"""
254256
setpoint = self._datatype.validate(setpoint)

src/fastcs/controller.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,15 @@ def _validate_io(self, ios: Sequence[AttributeIO[T, AttributeIORefT]]):
128128
def add_attribute(self, name, attribute: Attribute):
129129
if name in self.attributes and attribute is not self.attributes[name]:
130130
raise ValueError(
131-
f"Cannot add attribute {name}. "
132-
f"Controller {self} has has existing attribute {name}"
131+
f"Cannot add attribute {attribute}. "
132+
f"Controller {self} has has existing attribute {name}: "
133+
f"{self.attributes[name]}"
133134
)
134135
elif name in self.__sub_controller_tree.keys():
135136
raise ValueError(
136-
f"Cannot add attribute {name}. "
137-
f"Controller {self} has existing sub controller {name}"
137+
f"Cannot add attribute {attribute}. "
138+
f"Controller {self} has existing sub controller {name}: "
139+
f"{self.__sub_controller_tree[name]}"
138140
)
139141

140142
attribute.set_name(name)
@@ -145,13 +147,15 @@ def add_attribute(self, name, attribute: Attribute):
145147
def add_sub_controller(self, name: str, sub_controller: Controller):
146148
if name in self.__sub_controller_tree.keys():
147149
raise ValueError(
148-
f"Cannot add sub controller {name}. "
149-
f"Controller {self} has existing sub controller {name}"
150+
f"Cannot add sub controller {sub_controller}. "
151+
f"Controller {self} has existing sub controller {name}: "
152+
f"{self.__sub_controller_tree[name]}"
150153
)
151154
elif name in self.attributes:
152155
raise ValueError(
153-
f"Cannot add sub controller {name}. "
154-
f"Controller {self} has existing attribute {name}"
156+
f"Cannot add sub controller {sub_controller}. "
157+
f"Controller {self} has existing attribute {name}: "
158+
f"{self.attributes[name]}"
155159
)
156160

157161
sub_controller.set_path(self.path + [name])

src/fastcs/logging/__init__.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from ._graylog import GraylogStaticFields as GraylogStaticFields
88
from ._graylog import parse_graylog_env_fields as parse_graylog_env_fields
99
from ._graylog import parse_graylog_static_fields as parse_graylog_static_fields
10-
from ._logging import LogLevel, _configure_logger
10+
from ._logging import Logger, LogLevel, _configure_logger
1111

1212
logger = _logger.bind(logger_name="fastcs")
1313
"""FastCS logger
@@ -50,13 +50,25 @@
5050
fastcs. Instead there is a ``Tracer`` class for verbose logging with fine-grained
5151
controls that can be enabled by the user at runtime.
5252
53-
Use ``configure_logging`` to re-confi the logger at runtime. For more advanced
53+
Use ``configure_logging`` to re-configure the logger at runtime. For more advanced
5454
controls, configure the ``logger`` singleton directly.
5555
5656
See the ``loguru`` docs for more information: https://loguru.readthedocs.io
5757
"""
5858

5959

60+
def bind_logger(logger_name: str) -> Logger:
61+
"""Create a wrapper of the singleton fastcs logger with the given name bound
62+
63+
The name will be displayed in all log messages from the returned wrapper.
64+
65+
See the docstring for ``fastcs.logging.logger`` for more information.
66+
67+
"""
68+
69+
return logger.bind(logger_name=logger_name)
70+
71+
6072
def configure_logging(
6173
level: LogLevel | None = None,
6274
graylog_endpoint: GraylogEndpoint | None = None,

src/fastcs/transport/epics/ca/ioc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from fastcs.controller_api import ControllerAPI
1111
from fastcs.cs_methods import Command
1212
from fastcs.datatypes import DataType, T
13-
from fastcs.logging import logger as _logger
13+
from fastcs.logging import bind_logger
1414
from fastcs.tracer import Tracer
1515
from fastcs.transport.epics.ca.util import (
1616
builder_callable_from_attribute,
@@ -27,7 +27,7 @@
2727

2828

2929
tracer = Tracer(name=__name__)
30-
logger = _logger.bind(logger_name=__name__)
30+
logger = bind_logger(logger_name=__name__)
3131

3232

3333
class EpicsCAIOC:

src/fastcs/transport/epics/ca/util.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232

3333
EPICS_ALLOWED_DATATYPES = (Bool, DataType, Enum, Float, Int, String, Waveform)
34+
EPICS_WAVEFORM_LENGTH = 256
3435

3536
DATATYPE_FIELD_TO_RECORD_FIELD = {
3637
"prec": "PREC",
@@ -124,8 +125,10 @@ def cast_to_epics_type(datatype: DataType[T], value: T) -> object:
124125
return datatype.index_of(datatype.validate(value))
125126
else: # enum backed by string record
126127
return datatype.validate(value).name
128+
case String():
129+
return value[: EPICS_WAVEFORM_LENGTH - 1]
127130
case datatype if issubclass(type(datatype), EPICS_ALLOWED_DATATYPES):
128-
return datatype.validate(value)
131+
return value
129132
case _:
130133
raise ValueError(f"Unsupported datatype {datatype}")
131134

0 commit comments

Comments
 (0)