A pattern has emerged in the OpenFlexure Microscope codebase, where some Things have many properties that look like:
@thing_property
def mysetting(self) -> str:
"""Documentation for the mysetting property"""
return self.thing_settings.get("mysetting", "mydefaultvalue")
@mysetting.setter:
def mysetting(self, val: str):
self.thing_settings["mysetting"] = val
It would clearly be neater to create a shorthand for this. A ThingSetting descriptor could subclass PropertyDescriptor and implement a property that changes the thing's settings directly.
There are a few options for how this might look in a Thing definition. I think we need a few things in whatever syntax we come up with:
- The name of the setting
- A type
- A default value
- A docstring
- A neat way to determine whether it should be readable or writeable over HTTP would be good too.
Ideas for discussion
Here are a few options which I've summarised from the discussion below:
- A decorated default function would define a function that returns the default value, and a decorator to turn it into a property that can be read and written. I quite like this syntax. My only worry is that it might confuse someone who is not aware that the function is called only once, to obtain the default value. After the first run, there will be a value in the settings file, so the default is not used.
@thing_setting
def mysetting(self) -> bool:
"""A setting to switch something on and off"""
return False # this would be the default value
- A property-like decorator would work similarly to the current solution, but hide the boilerplate related to saving it persistently. This is very much like how one might define a simple property using
@property.:
_my_setting: bool = False
@thing_setting
def mysetting(self) -> bool:
"""A setting to switch something on and off"""
return self._my_setting
@mysetting.setter:
def mysetting(self, val: bool):
self._my_setting = val
- An explicit descriptor looks less like a structure someone might already be using, but is very similar to what is done in many typing/serialisation libraries:
mysetting = ThingSetting(default=False, type=bool, doc="A setting to switch something on and off")
- Using a type hint and field object along the lines of
dataclasses.field or pydantic.Field (pydantic's docs are helpful):
mysetting: bool = ThingSetting(default=False)
"""A setting to switch something on and off"""
I particularly like that standard Python is used for the type and docstring, which should help autocompletion/introspection/type checking/autodoc tools.
- An annotated type hint looks perhaps most obviously like a simple property to me:
mysetting: Annotated(bool, ThingSetting) = False
"""A setting to switch something on and off"""
There may be cases to consider requiring more options, in particular:
- Some settings might not want to be writeable over HTTP
- Some settings might not want to be readable over HTTP
- It may be desirable to allow Things to add settings not defined at the start - I'm less sure about this.
Discussion is welcome - I am keen to find syntax that makes sense to more people than just me!
A pattern has emerged in the OpenFlexure Microscope codebase, where some
Things have many properties that look like:It would clearly be neater to create a shorthand for this. A
ThingSettingdescriptor could subclassPropertyDescriptorand implement a property that changes the thing's settings directly.There are a few options for how this might look in a
Thingdefinition. I think we need a few things in whatever syntax we come up with:Ideas for discussion
Here are a few options which I've summarised from the discussion below:
@property.:dataclasses.fieldorpydantic.Field(pydantic's docs are helpful):There may be cases to consider requiring more options, in particular:
Discussion is welcome - I am keen to find syntax that makes sense to more people than just me!