labthings_fastapi.example_things
Example Thing subclasses, used for testing and demonstration purposes.
Most of these are broken in some way and used for testing. These should be moved into the unit tests.
Classes
An example Thing with a few affordances. |
|
A Thing that raises exceptions in actions/properties. |
|
A Thing that raises an exception in __init__. |
|
A Thing that raises an exception in __enter__. |
Functions
|
Define a Property on a |
Package Contents
- labthings_fastapi.example_things.lt_property(getter: Callable[[Owner], Value]) FunctionalProperty[Owner, Value]
- labthings_fastapi.example_things.lt_property(*, default: Value, readonly: bool = False, use_global_lock: Literal[False] | None = None, **constraints: Any) Value
- labthings_fastapi.example_things.lt_property(*, default_factory: Callable[[], Value], readonly: bool = False, use_global_lock: Literal[False] | None = None, **constraints: Any) Value
Define a Property on a
Thing.This function may be used to define Properties in two ways, as either a decorator or a field specifier. See the examples in the Properties.
Properties should always have a type annotation. This type annotation will be used in automatic documentation and also to serialise the value to JSON when it is sent over the network. This mean that the type of your property should either be JSON serialisable (i.e. simple built-in types) or a subclass of
pydantic.BaseModel.- Parameters:
getter – is a method of a class that returns the value of this property. This is usually supplied by using
propertyas a decorator.default – is the default value. Either this,
getterordefault_factorymust be specified. Specifying both or neither will raise an exception.default_factory – should return your default value. This may be used as an alternative to
defaultif you need to use a mutable datatype. For example, it would be better to specifydefault_factory=listthandefault=[]because the second form would be shared between allThings with this property.readonly – whether the property should be read-only via the
ThingClientinterface (i.e. over HTTP or via aDirectThingClient). This is automatically true ifpropertyis used as a decorator and no setter is specified.use_global_lock – may be set to
Falseto disable the global lock for setting this property. By default, if global locking is enabled, we hold the global lock while setting the property.**constraints – additional keyword arguments are passed to
pydantic.Fieldand allow constraints to be added to the property. For example,ge=0constrains a numeric property to be non-negative. Seepydantic.Fieldfor the full range of constraint arguments.
- Returns:
a property descriptor, either a
FunctionalPropertyif used as a decorator, or aDataPropertyif used as a field.- Raises:
MissingDefaultError – if no valid default value is supplied, and a getter is not in use.
OverspecifiedDefaultError – if the default is specified more than once (e.g.
default,default_factory, orgetter).
Typing Notes
This function has somewhat complicated type hints, for two reasons. Firstly, it may be used either as a decorator or as a field specifier, so
defaultperforms double duty as a default value or a getter. Secondly, when used as a field specifier the type hint for the property is attached to the attribute of the class to which the function’s output is assigned. This meanspropertydoes not know its type hint until after it’s been called.When used as a field specifier,
propertyreturns a genericDataPropertydescriptor instance, which will determine its type when it is attached to theThing. The type hint on the return value ofpropertyin that situation is a “white lie”: we annotate the return as having the same type as thedefaultvalue (or thedefault_factoryreturn value). This means that type checkers such asmypywill check that the default is valid for the type of the field, and won’t raise an error about assigning, for example, an instance ofDataProperty[int]to a field annotated asint.Finally, the type of the
defaultargument includesEllipsisTypeso that we can use...as its default value. This allows us to distinguish betweendefaultnot being set (...) and a desired default value ofNone. Similarly,...is the default value forgetterso we can raise a more helpful error if a non-callable value is passed as the first argument.
- class labthings_fastapi.example_things.MyThing(thing_server_interface: labthings_fastapi.thing_server_interface.ThingServerInterface)
Bases:
labthings_fastapi.thing.ThingAn example Thing with a few affordances.
Initialise a Thing.
The most important function of
__init__is attaching the thing_server_interface, and setting the path. Note thatThinginstances are usually created by aThingServerand not instantiated directly: if you do make aThingdirectly, you will need to supply aThingServerInterfacethat is connected to aThingServeror a suitable mock object.- Parameters:
thing_server_interface – The interface to the server that is hosting this Thing. It will be supplied when the
Thingis instantiated by theThingServeror bycreate_thing_without_serverwhich generates a mock interface.
- anaction(repeats: Annotated[int, Field(description='The number of times to try the action')], undocumented: int, title: Annotated[str, Field(description='the title of the invocation')] = 'Untitled', attempts: Annotated[list[str] | None, Field(description='Names for each attempt - I suggest final, Final, FINAL.')] = None) dict[str, str]
Quite a complicated action.
This action has lots of parameters and is designed to confuse my schema generator. I hope it doesn’t!
I might even use some Markdown here:
If this renders, it supports lists
With at least two items.
There is also a parameter and return block to satisfy docstring validators. This may be preferable to annotations on the arguments.
- Parameters:
repeats – How many times to do it.
undocumented – There’s no description on this field’s type hint.
title – A human-readable title.
attempts – A list of names of attempts.
- Returns:
A dictionary with strings as keys and values.
- make_a_dict(extra_key: str | None = None, extra_value: str | None = None) dict[str, str | None]
Do something that returns a dict.
- Parameters:
extra_key – An additional key.
extra_value – An additional value.
- Returns:
a dictionary.
- increment_counter() None
Increment the counter property.
This action doesn’t do very much - all it does, in fact, is increment the counter (which may be read using the
counterproperty).
- class labthings_fastapi.example_things.ThingWithBrokenAffordances(thing_server_interface: labthings_fastapi.thing_server_interface.ThingServerInterface)
Bases:
labthings_fastapi.thing.ThingA Thing that raises exceptions in actions/properties.
Initialise a Thing.
The most important function of
__init__is attaching the thing_server_interface, and setting the path. Note thatThinginstances are usually created by aThingServerand not instantiated directly: if you do make aThingdirectly, you will need to supply aThingServerInterfacethat is connected to aThingServeror a suitable mock object.- Parameters:
thing_server_interface – The interface to the server that is hosting this Thing. It will be supplied when the
Thingis instantiated by theThingServeror bycreate_thing_without_serverwhich generates a mock interface.
- broken_action() None
Do something that raises an exception.
- Raises:
RuntimeError – every time.
- broken_property() None
Raise an exception when the property is accessed.
- Raises:
RuntimeError – every time.
- class labthings_fastapi.example_things.ThingThatCantInstantiate(**kwargs: Any)
Bases:
labthings_fastapi.thing.ThingA Thing that raises an exception in __init__.
Fail to initialise.
- Parameters:
**kwargs – keyword arguments passed to Thing.__init__
- Raises:
RuntimeError – every time.
- class labthings_fastapi.example_things.ThingThatCantStart(thing_server_interface: labthings_fastapi.thing_server_interface.ThingServerInterface)
Bases:
labthings_fastapi.thing.ThingA Thing that raises an exception in __enter__.
Initialise a Thing.
The most important function of
__init__is attaching the thing_server_interface, and setting the path. Note thatThinginstances are usually created by aThingServerand not instantiated directly: if you do make aThingdirectly, you will need to supply aThingServerInterfacethat is connected to aThingServeror a suitable mock object.- Parameters:
thing_server_interface – The interface to the server that is hosting this Thing. It will be supplied when the
Thingis instantiated by theThingServeror bycreate_thing_without_serverwhich generates a mock interface.
- __enter__() None
Fail to start the thing.
- Raises:
RuntimeError – every time.