Skip to content

Commit 0d24d7e

Browse files
committed
Propagate read-only metadata to the Thing Description.
1 parent 9ec8a20 commit 0d24d7e

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

src/labthings_fastapi/properties.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,8 @@ def property_affordance(
460460
title=self.title,
461461
forms=forms,
462462
description=self.description,
463+
readOnly=self.readonly,
464+
writeOnly=False, # write-only properties are not yet supported
463465
)
464466
# We merge the data schema with the property affordance (which subclasses the
465467
# DataSchema model) with the affordance second so its values take priority.

tests/test_property.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from labthings_fastapi.base_descriptor import DescriptorAddedToClassTwiceError
2828
from labthings_fastapi.exceptions import MissingTypeError, NotConnectedToServerError
2929
import labthings_fastapi as lt
30+
from labthings_fastapi.testing import create_thing_without_server
3031
from .utilities import raises_or_is_caused_by
3132

3233

@@ -298,3 +299,49 @@ def prop(self) -> bool:
298299
Example.prop.add_to_fastapi(mocker.Mock(), example)
299300
with pytest.raises(NotConnectedToServerError):
300301
Example.prop.property_affordance(example, None)
302+
303+
304+
def test_readonly_metadata():
305+
"""Check read-only data propagates to the Thing Description."""
306+
307+
class Example(lt.Thing):
308+
prop: int = lt.property(default=0)
309+
ro_property: int = lt.property(default=0, readonly=True)
310+
311+
@lt.property
312+
def ro_functional_property(self) -> int:
313+
"""This property should be read-only as there's no setter."""
314+
return 42
315+
316+
@lt.property
317+
def ro_functional_property_with_setter(self) -> int:
318+
return 42
319+
320+
@ro_functional_property_with_setter.setter
321+
def _set_ro_functional_property_with_setter(self, val: int) -> None:
322+
pass
323+
324+
ro_functional_property_with_setter.readonly = True
325+
326+
@lt.property
327+
def funcprop(self) -> int:
328+
return 42
329+
330+
@funcprop.setter
331+
def _set_funcprop(self, val: int) -> None:
332+
pass
333+
334+
example = create_thing_without_server(Example)
335+
336+
td = example.thing_description()
337+
338+
# Check read-write properties are not read-only
339+
for name in ["prop", "funcprop"]:
340+
assert td.properties[name].readOnly is False
341+
342+
for name in [
343+
"ro_property",
344+
"ro_functional_property",
345+
"ro_functional_property_with_setter",
346+
]:
347+
assert td.properties[name].readOnly is True

0 commit comments

Comments
 (0)