Creating New Device Types¶
Container objects are built using both the base Device
class as well
as instances of the EntryInfo
.
Entry Info¶
In order to regulate and template the information that gets entered into the
Happi database, we use the concept of device containers. This allows a
developer to specify fields that are inherit to every device of a specific
type, in addition by specifying these keys using the EntryInfo
object, you have even greater control by declaring optional vs. mandatory,
default options when a user does not enter the value, and enforce specific
types.
-
class
happi.device.
EntryInfo
(doc=None, optional=True, enforce=None, default=None)¶ A piece of information related to a specific device
These are entered as class attributes for a given device container. They help control the information entered into a device
Parameters: - doc (str) – A short string to document the device
- optional (bool, optional) – By default all EntryInfo is optional, but in certain cases you may want to demand a particular piece of information upon initialization
- enforce (type, list, compiled regex, optional) – Specify that all entered information is entered in a specific format.
This can either by a Python type i.e. int, float e.t.c., a list of
acceptable values, or a compiled regex pattern i.e
re.compile(...)
- default (optional) – A default value for the trait to have if the user does not specify.
Keep in mind that this should be the same type as
enforce
if you are demanding a certain type.
Raises: ContainerError: – If there is an error with the way the enforced value interacts with its default value, or if the piece of information entered is unenforcable based on the the settings
Example
class MyDevice(Device): my_field = EntryInfo('My generated field') number = EntryInfo('Device number', enforce=int, default=0)
-
enforce_value
(value)¶ Enforce the rules of the EntryInfo
Parameters: value – Returns: Identical to the provided value except it may have been converted to the correct type Return type: value Raises: ValueError: – If the value is not the correct type, or does not match the pattern
Using a Device¶
In order to ensure that information is entered into the database in an
organized fashion, the client will only accept classes that inherit from
Device
. Each device will have the key information represented as
class attributes, available to be manipulated like any other regular property
Editing the information for a container is a simple as:
In [1]: from happi import Device
In [2]: device = Device(name='my_device')
In [3]: device.name = 'new_name'
The Device
class also supports extraneous data that may not have been
captured when the original container was created. You can either enter this as
a keyword, or enter it into the Device.extraneous
dictionary.
While you are free to play around with the device attributes, when loading the
object into the database you will need to make sure that all of the
Device.mandatory_info
has been entered, otherwise the client
will reject the device.
Example Class¶
In order to show the flexibility of the EntryInfo
class, we’ll put
together an example container. The class can be invoked in the same way you
would usually handle class inheritance, the only difference is that you specify
class attributes as EntryInfo objects:
import re
from happi.device import Device, EntryInfo
class MyDevice(Device):
model_no = EntryInfo('Model Number of Device', optional=False)
count = EntryInfo('Count of Device', enforce=int, default=0)
choices = EntryInfo('Choice Info', enforce=['a','b','c'])
no_whitespace = EntryInfo('Enforce no whitespace',
enforce = re.compile(r'[\S]*$')
By default, EntryInfo will create an optional keyword, whose default is
None
with the same name as the class attribute. You can always see how this
information will be put into the the database by looking at the output of the
Device.post()
method. As shown in the example above, using the EntryInfo
keywords, you can put a short doc string to give a better explanation of the
field, and also enforce that user enter a specific format of information.
While the user will always be able to enter None
for the attribute, if a
real value is given it will be checked against the specified enforce
keyword, raising ValueError
if invalid. Here is a table for how the
EntryInfo
check the type
Enforce | Method of enforcement |
---|---|
None | Any value will work |
type | type(value) |
list | list.index(value) |
regex | regex.match(value) != None |
Finally, fields that are important to the device can be marked as mandatory.
These should have no default value. When entering information you will not
neccesarily see a difference in between optional and mandatory
EntryInfo
, however the database client will reject the device if
these fields don’t have values associated with them.