Happi API
Client
- class happi.Client(database=None, **kwargs)
The client to control the contents of the Happi Database.
- Parameters:
database (happi.backends.Backend) – A already-instantiated backend.
kwargs – Keyword arguments passed to the
database
backend.
- Raises:
DatabaseError – Raised if the Client fails to instantiate the Database.
- add_item(item)
Add an item into the database.
- property all_items
A list of all contained items.
- change_container(item: HappiItem, target: type[HappiItem], edits: dict[str, Any] | None = None, how: str = 'right') dict[str, Any]
Return the kwargs necessary to transfer the information from
item
into a containertarget
. Checks are performed to ensure the contents are compatible (following enforce requirements in the target container)This function is built to be a helper function for an interactive cli tool, and passes information up accordingly. If keys are not significantly mismatched, this function can be used as is.
- Parameters:
item (happi.HappiItem) – HappiItem instance to be transferred to a new container
target (Type[happi.HappiItem]) – Container to contain new item
edits (dict[str, Any], optional) – Dictionary of edits to supersede values in original item
how (str, optional) – Method of resolving the entries between the original item and target container. Can be: - “right” : Expect a value for every entry in target container - “inner” : Expect values for only entries in BOTH original item and target container
- Raises:
TransferError – If there is a problem tranferring item into container
- Returns:
new_kwargs – kwargs to pass into a new HappiItem
- Return type:
Dict[str, Any]
- choices_for_field(field)
List all choices for a given field.
- Parameters:
field (string) – Field name to list all possible choices for i.e ‘beamline’, ‘name’, ‘z’, ‘prefix’, etc.
- Raises:
SearchError – If no items in the database have an entry for the given field.
- Returns:
field_choices – List of choices for a given field that are in the database.
- Return type:
- create_item(item_cls, **kwargs)
Instantiate a HappiItem from its container class and keyword arguments.
- Parameters:
item_cls (type) – The HappiItem container class to instantiate.
**kwargs – Information to pass through to the item, upon initialization.
- Returns:
item – An instantiated version of the item.
- Return type:
- Raises:
TypeError – If the provided class is not a subclass of
HappiItem
.
Example
item = client.create_item(Item, name='my_item' ...) item = client.create_item('Item', name='my_item',...)
- export(path=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>, sep='\t', attrs=None)
Export the contents of the database into a text file.
- Parameters:
path (File Handle) – File-like object to save text file. Defaults to stdout.
sep (str) – Separator to place inbetween columns of information.
attrs (iterable) – Attributes to include, these will be a list of values.
- static find_config()
Search for a
happi
configuration file.We first query the environment variable
$HAPPI_CFG
to see if this points to a specific configuration file. If this is not present, the variable set by$XDG_CONFIG_HOME
or if that is not set~/.config
- Returns:
path – Absolute path to configuration file.
- Return type:
- Raises:
EnvironmentError – If no configuration file can be found by the methodology detailed above.
- find_document(**kwargs)
Load an item document from the database.
If multiple matches are found, a single document will be returned to the user. How the database will choose to select this item is based on each individual implementation
- Parameters:
kwargs – Keyword pairs of information used to locate the item
- Returns:
document – A dict that matches the specified information.
- Return type:
- Raises:
SearchError – If no document with the given information is found.
See also
- find_item(**post)
Query the database for an individual HappiItem.
If multiple items are found, only the first is returned.
- Parameters:
**post – Key-value pairs of search criteria used to find the item.
- Raises:
SearchError – If no match for the given information is found.
- Returns:
item – A HappiItem instance for the document.
- Return type:
- classmethod from_config(cfg=None)
Create a client from a configuration file specification.
Configuration files looking something along the lines of:
[DEFAULT] path=path/to/my/db.json
All key value pairs will be passed directly into backend construction with the exception of the key
backend
which can be used to specify a specific type of backend if this differs from the configured default.- Parameters:
cfg (str, optional) – Path to a configuration file. If not entered,
find_config()
will be use.
- load_device(use_cache=True, **post)
Find an item in the database and instantiate it.
Essentially a shortcut for:
container = client.find_item(name='...') item = from_container(container)
- Parameters:
post – Key-value pairs of search criteria passed to
Client.find_item()
.use_cache (bool, optional) – Choice to use a cached item. See
from_container()
for more information.
- Returns:
Instantiated object.
- Return type:
- remove_item(item)
Remove an item from the database.
- Parameters:
item (
HappiItem
) – HappiItem to be removed from the database.
- retain_cache_context(clear_first: bool = True)
Context manager which can be used to retain the happi backend cache.
- Parameters:
clear_first (bool, optional) – Clear the cache before entering the block. Defaults to True.
- search(**kwargs)
Search the database for item(s).
- Parameters:
**kwargs – Information to filter through the database structured as key, value pairs for the desired pieces of EntryInfo.
- Returns:
res – The search results.
- Return type:
list of SearchResult
Example
gate_valves = client.search(type='Valve') hxr_valves = client.search(type='Valve', beamline='HXR')
- search_range(key: str, start: float, end: float | None = None, **kwargs) list[SearchResult]
Search the database for an item or items using a numerical range.
- Parameters:
key (str) – Database key to search.
start (float, optional) – Minimum beamline position to include items.
end (float, optional) – Maximum beamline position to include items.
**kwargs (optional) – Additional information used to filter through the database structured as key-value pairs for the desired pieces of EntryInfo.
- Return type:
list of SearchResult
Example
gate_valves = client.search_range('z', 0, 100, type='Valve') hxr_valves = client.search_range('z', 0, 100, type='Valve', beamline='HXR')
- search_regex(flags=re.IGNORECASE, **kwargs) list[SearchResult]
Search the database for items(s).
- Parameters:
flags (int, optional) – Defaulting to
re.IGNORECASE
, these flags are used for the regular expressions passed in.**kwargs – Information to filter through the database structured as key, value pairs for the desired pieces of EntryInfo. Every value is allowed to contain a Python regular expression.
- Return type:
list of SearchResult
Example
gate_valves = client.search_regex(beamline='Valve.*') three_valves = client.search_regex(_id='VALVE[123]')
- class happi.SearchResult(client, item)
A single search result from
Client.search
.Examples
This result can be keyed for metadata as in: >>> result[‘name’]
The HappiItem can be readily retrieved: >>> result.item
Or the object may be instantiated: >>> result.get()
- item
The resulting container.
- Type:
- get(k[, d]) D[k] if k in D, else d. d defaults to None.
Backends
- class happi.backends.core._Backend
Base class for backend database.
Backends are internal to happi and are subject to change. Users should interact with the
happi.Client
.- property all_items: list[dict[str, Any]]
List of all items in the database.
This base class
_Backend
provides no implementation and requires that a subclass provide its customized implementation.
- clear_cache() None
Request to clear any cached data.
Optional implementation may be customized in subclass.
- delete(_id: str) None
Delete a device instance from the database.
This base class
_Backend
provides no implementation and requires that a subclass provide its customized implementation.- Parameters:
_id (str) – ID of device.
- Raises:
PermissionError – If the write operation fails due to issues with permissions.
- find(multiples: bool = False, **kwargs) Generator[dict[str, Any], None, None]
Find an instance or instances that matches the search criteria.
This base class
_Backend
provides no implementation and requires that a subclass provide its customized implementation.- Parameters:
multiples (bool) – Find a single result or all results matching the provided information.
kwargs – Requested information.
- save(_id: str, post: dict[str, Any], insert: bool = True) None
Save information to the database.
This base class
_Backend
provides no implementation and requires that a subclass provide its customized implementation.- Parameters:
- Raises:
DuplicateError – If
insert
isTrue
, but there is already a device with the provided_id
.SearchError – If
insert
isFalse
, but there is no device with the provided_id
.PermissionError – If the write operation fails due to issues with permissions.
|
Abstraction for MongoDB backend. |
|
JSON database. |
|
Questionniare Backend. |
Containers
Built-ins
- class happi.HappiItem(**kwargs)
The smallest description of an object that can be entered in
happi
.The class does not need to be intialized with any specific piece of information except a name, but all of the attributes listed by
HappiItem.info_names
can be used to assign values toEntryInfo
upon initialization. Pieces of information that are deemed mandatory by the class must be filled in before the device is loaded into the database. Seemandatory_info
to see which attributes are neccesary.Additional metadata can be given to the device in the form of keywords on initialization, this information is kept in the
extraneous
attribute, and will be saved in to the database as long as it does not clash with an existing piece of metadata that the client uses to organize devices.- extraneous
Storage for information supplied during initialization that does not correspond to a specific EntryInfo.
- Type:
- Raises:
EntryError – If a piece of information supplied at startup is of the incorrect type.
ContainerError – If one of the pieces of
EntryInfo
has a default value of the incorrect type.
Example
d = HappiItem(name = 'my_device', # Alias name for device note = 'Example', # Piece of arbitrary metadata )
- active
Whether the instance is actively deployed
- args
Arguments to pass to device_class
- device_class
Python class that represents the instance
- documentation
Relevant documentation for the instance
- kwargs
Keyword arguments to pass to device_class
- name
Shorthand Python-valid name for the Python instance
- post()
Create a document to be loaded into the happi database.
- Returns:
post – Dictionary of all contained information.
- Return type:
- save()
Overwritten when the device instance is loaded from the client.
- show_info(handle=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>)
Show the device instance information in a PrettyTable.
- Parameters:
handle (file-like, optional) – Option to write to a file-like object.
Loading
- happi.from_container(item: HappiItem, attach_md: bool = True, run_post_attach_hook: bool = True, use_cache: bool = True, threaded: bool = False) Any
Load an object (or “device”) from a compatible HappiItem.
The item container is queried for the
device_class
,args
, andkwargs
. If the associated Python module is not already loaded it will be imported. The specified class is then instantiated with the given args and kwargs provided.The name
device
here refers to what is created after instantiatingdevice_class
.This function does not attempt to catch exceptions either during module imports or object creation. If you would like a series of independent devices to be loaded use
load_devices()
.By default, the instantiated object has the original container added on as
.md
. This allows applications to utilize additional metadata information that may not be included in the basic class constructor. On later calls, the container you request is checked against this stored metadata. If a discrepancy is found the object is forced to reload, not retrieved from the cache.- Parameters:
item (happi.HappiItem) – The item to load.
attach_md (bool, optional) – Attach the container to the instantiated object as
md
.run_post_attach_hook (bool, optional) – Run
post_happi_md
method on the device after attaching the container if possible.use_cache (bool, optional) – When devices are loaded they are stored in the
happi.cache
dictionary. This means that repeated attempts to load the device will return the same object. This prevents unnecessary EPICS connections from being initialized in the same process. If a new object is needed, setuse_cache
toFalse
and a new object will be created, overriding the current cached object. An object with matching name and differing metadata will always return a new instantiation of the device.threaded (bool, optional) – Set this to
True
when calling inside a thread. This is currently unused.
- Returns:
obj – This will be of the same type as the return value of the provided item’s
device_class
. As that may be a factory function or a class, the exact return type is not guaranteed.- Return type:
Any
- happi.load_devices(*items: HappiItem, pprint: bool = False, namespace: object | None = None, use_cache: bool = True, threaded: bool = False, post_load: Callable[[Any], None] | None = None, include_load_time: bool = False, load_time_threshold: float = 0.5, **kwargs)
Load a series of devices by way of their HappiItems into a namespace.
- Parameters:
*items (HappiItem) – List of happi containers to load.
pprint (bool, optional) – Print results of device loads.
namespace (object, optional) – Namespace to collect loaded devices in. By default this will be a
types.SimpleNamespace
.use_cache (bool, optional) – If set to
False
, we’ll ignore the cache and always make new devices.threaded (bool, optional) – Set to
True
to create each device in a background thread. Note that this assumes that no two devices provided are the same. You are not guaranteed to load from the cache correctly if you ask for the same device to be loaded twice in the same threaded load.post_load (function, optional) – Function of one argument to run on each device after instantiation. This could be especially useful during the threaded loading process.
include_load_time (bool, optional) – Include load time in each message.
load_time_threshold (float, optional) – Load time above this value, in seconds, will be shown if
include_load_time
is set.kwargs – Additional keyword arguments passed to
from_container()
.
Registry
- class happi.containers.HappiRegistry(*args, **kwargs)
Happi Container Registry singleton.
This registry keeps a mapping of full happi container names to their respective
HappiItem
subclasses.Entries in the registry are populated in the following order:
From the
happi.containers.DEFAULT_REGISTRY
dictionary. The names of the containers are assumed to already include any relevant qualifiers such as package names. That is, the default"OphydItem"
will be used as-is and retrieved from the registry by that name alone.Through Python package-defined entrypoints with the key
happi.containers
.For example, consider a package named
"mypackagename"
that defines the happi containerContainerName
inside of the Python modulemypackagename.happi.containers_module.ContainerName
. The fully qualified name - as accessed through the happi client for each item in the database - may be customized in the entrypoint.Here, we want the container to be accessible by way of
"desired_prefix.ContainerName"
. The following would be how this entrypoint should be configured insetup.py
.
setup( name="mypackagename", entry_points={ "happi.containers": [ "desired_prefix=mypackagename.happi.containers_module", ], }, )
Containers may also be added manually to the registry by way of:
import happi happi.containers.registry[item_name] = ContainerClass