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.

Parameters:

item (HappiItem) – The item to store in the database.

Returns:

_id – The id of the item added.

Return type:

str

Raises:

EntryError – If all of the mandatory information for the item has not been specified or there is already an item with that id in 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 container target. 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:

list

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:

object

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:

str

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:

dict

Raises:

SearchError – If no document with the given information is found.

See also

find_item(), search()

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:

HappiItem

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:

object

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]')
validate()

Validate all of the items in the database.

This is done by attempting to initialize each item and asserting their mandatory information is present. Information is written to the logger.

Returns:

ids – List of item ids that have failed verification.

Return type:

list of str

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:

happi.HappiItem

metadata

The resulting HappiItem metadata.

Type:

dict

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:
  • _id (str) – ID of device.

  • post (dict) – Information to place in database.

  • insert (bool, optional) – Whether or not this a new device to the database.

Raises:
  • DuplicateError – If insert is True, but there is already a device with the provided _id.

  • SearchError – If insert is False, but there is no device with the provided _id.

  • PermissionError – If the write operation fails due to issues with permissions.

happi.backends.mongo_db.MongoBackend(host, ...)

Abstraction for MongoDB backend.

happi.backends.json_db.JSONBackend(path[, ...])

JSON database.

happi.backends.qs_db.QSBackend(expname, *[, ...])

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 to EntryInfo upon initialization. Pieces of information that are deemed mandatory by the class must be filled in before the device is loaded into the database. See mandatory_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.

entry_info

A list of all the EntryInfo associated with the device.

Type:

list

extraneous

Storage for information supplied during initialization that does not correspond to a specific EntryInfo.

Type:

dict

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:

dict

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.

class happi.OphydItem(**kwargs)
args

Arguments to pass to device_class

kwargs

Keyword arguments to pass to device_class

prefix

A base PV for all related records

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, and kwargs. 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 instantiating device_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, set use_cache to False 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:

  1. 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.

  2. Through Python package-defined entrypoints with the key happi.containers.

    For example, consider a package named "mypackagename" that defines the happi container ContainerName inside of the Python module mypackagename.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 in setup.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