ophyd-registry


Nameophyd-registry JSON
Version 1.5.0 PyPI version JSON
download
home_pageNone
SummaryA registry to keep track of, and retrieve, Ophyd objects.
upload_time2024-11-22 18:20:10
maintainerNone
docs_urlNone
authorNone
requires_python>=3.7
licenseNone
keywords synchrotron xray bluesky
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Ophyd Registry

[![Python Tests](https://github.com/spc-group/ophyd-registry/actions/workflows/ci.yml/badge.svg)](https://github.com/spc-group/ophyd-registry/actions/workflows/ci.yml)

A registry to keep track of, and retrieve, Ophyd objects.

The **Ophyd registry** provides a way to keep track of the devices
(including components, motors, signals, etc.) that have been defined
across a project. In order for the registry to know of a device, that
device must first be registered, though there are ways to do this
automatically.

This allows for a simple way to keep track of the Ophyd devices that were
created in your project.

```python

import ophyd
from ophydregistry import OphydRegistry

# Register the devices when they're created
registry = OphydRegistry()
registry.register(ophyd.sim.motor)

# Then elsewhere in your project, use them...
registry['motor'].set(15.3)

```

Installation
============

The easiest way to install the ophyd registry is with pip from PyPI:

```bash
python -m pip install ophyd-registry
```

To create a **developer installation**:

```bash
git clone https://github.com/spc-group/ophyd-registry.git
python -m pip install "ophyd_registry[dev]"
```

Usage
=====

Registering Devices
-------------------

There are three ways to have an instrument registry know about a
device.

1. Implicitly capture all Ophyd objects
2. Register a device class
3. Register individual objects

By default, a new instrument registry will alert itself to all future
devices:

```python
from ophydregistry import Registry
registry = Registry()

the_device = MyDevice("255id:Dev:", name="my_device")

assert registry.find("my_device") is the_device
```

This greedy behavior can be suppressed with the *auto_register*
parameter. It can also be turned off after initialization by setting
the *auto_register* attribute to ``False``::

```python

registry = Registry(auto_register=False)

# Make a bunch of devices
...

# Turn if off for this one
registry.auto_register = False
device = MyDevice(...)
registry.auto_register = True

# Register some other devices maybe
...

```

If *auto_register* is false, then a device class can be
decorated to allow the registry to find it:

```python
from ophyd import Device
from ophydregistry import Registry

registry = Registry(auto_register=False)

@registry.register
class MyDevice(Device):
    ...

the_device = MyDevice("255id:Dev:", name="my_device")

assert registry.find("my_device") is the_device
```

Lastly, individual instantions of a device can be explicitly
registered.

```python
from ophyd import Device
from ophydregistry import Registry

registry = Registry(auto_register=False)

class MyDevice(Device):
    ...

the_device = MyDevice("255id:Dev:", name="my_device")
registry.register(the_device)

assert registry.find("my_device") is the_device
```

Looking Up Registered Devices/Components
----------------------------------------

Registered objects can be found by *name*, *label*, or both. The
easist way is to treat the registry like a dictionary:
``registry['motor1']``. This will look for an individual device first
by *name* then by *label*. It will raise an exception if the number of
devices is not 1.

For more sophisticated queries, the *Registry.find()* method will
return a single result, while *Registry.findall()* returns more than
one. By default, *findall()* will raise an exception if no objects
match the criteria, but this can be overridden with the *allow_none*
keyword argument.

The registry uses the built-in concept of device labels in Ophyd. The
registry's ``find()`` and ``findall()`` methods allows devices to be
looked up by label or device name. For example, assuming four devices
exist with the label "ion_chambers", then these devices can be
retrieved using the registry:

```python
ion_chambers = registry.findall(label="ion_chambers")
assert len(ion_chambers) == 4
```

Devices can also be found by name:

```python
ion_chambers = registry.find(name="I0")
assert len(ion_chambers) == 4
```

A set of the **root devices**, those without a parent, can be
retrieved at ``Registry.root_devices``.

Looking Up Sub-Components by Dot-Notation
-----------------------------------------

For simple devices, the full name of the sub-component should be
enough to retrieve the device. For example, to find the signal
*preset_time* on the device named "vortex_me4", the following may work
fine:

```python
preset_time = haven.registry.find("vortex_me4_preset_time")
```

However, **if the component is lazy** and has not been accessed prior
to being registered, then **it will not be available in the
registry**. Sub-components can instead be accessed by dot
notation. Unlike the full device name, dot-notation names only resolve
when the component is requested from the registry, at which point the
lazy components can be accessed.

For example, area detectors use many lazy components. If ``sim_det``
is an area detector with a camera component ``sim_det.cam``, then the
name of the gain channel is "sim_det_cam_gain", however this is a lazy
component so is not available. Instead, retrieving the device by
``haven.registry.find("sim_det.cam.gain")`` will first find the area
detector ("sim_det"), then access the *cam* attribute, and then cam's
*gain* attribute. This has the side-effect of instantiating the lazy
components.


Removing Devices
----------------

The ``OphydRegistry`` class behaves similarly to a python dictionary.

To **remove all devices** from the registry, use the ``clear()``
method:

```python

registry.clear()
```

To **remove disconnected devices** from the registry, use the ``pop_disconnected()`` method with an optional timeout:

```python

# Wait 5 seconds to give devices a chance to connect
disconnected_devices = registry.pop_disconnected(timeout=5)

```

To **remove individual objects**, use either the *del* keyword, or the
``pop()`` method. These approaches work with either the
``OphydObject`` instance itself, or the instance's name:

```python

# Just delete the item and move on
# (by name)
del registry["motor1"]
# (by reference)
motor = registry['motor1']
del registry[motor]

# Remove the item and use it
# (return a simulated motor if "motor1" is not in the registry)
motor = registry.pop("motor1", ophyd.sim.motor)
motor.set(5).wait()

```

Keeping References
------------------

It may be useful to not actually keep a strong reference to the
``OphydObject``s. This means that if all other references to the
object are removed, the device may be dropped from the registry.

By default, the registry keeps direct references to the objects that
get registered, but if initalized with ``keep_references=False`` the
Registry will not keep these references. Instead, **it is up to you to
keep references to the registered objects**.

```python

# Create two registers with both referencing behaviors
ref_registry = Registry(keep_references=True)
noref_registry = Registry(keep_references=False)
motor = EpicsMotor(...)

# Check if we can get the motor (should be no problem)
ref_registry[motor.name]  # <- succeeds
noref_registry[motor.name]  # <- succeeds

# Delete the object and try again
del motor
gc.collect()  # <- make sure it's *really* gone

# Check again if we can get the motor (now it gets fun)
ref_registry[motor.name]  # <- succeeds
noref_registry[motor.name]  # <- raises ComponentNotFound

```

Integrating with Typhos
-----------------------

Typhos includes a PyDM plugin that can directly interact with ophyd
devices. It requires ophyd objects to be registered in order to find
them. **ophyd_registry** can automatically register devices with
Typhos by simply passing the *use_typhos* argument when creating the
registry:

```python
    
from ophydregistry import Registry
registry = Registry(use_typos=True)

```

or setting the *use_typhos* attribute on an existing registry:

```python
    
from ophydregistry import Registry
registry = Registry()
registry.use_typhos = True

```

If using the typhos registry, calling the *clear()* method on the
ophyd registry will also clear the Typhos registry.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "ophyd-registry",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "synchrotron, xray, bluesky",
    "author": null,
    "author_email": "Mark Wolfman <wolfman@anl.gov>",
    "download_url": "https://files.pythonhosted.org/packages/41/d2/8dfb0b9160f300972cb7efc09e9efc8ed5eb4dba4c8b66f46428ca57e6b5/ophyd_registry-1.5.0.tar.gz",
    "platform": null,
    "description": "# Ophyd Registry\n\n[![Python Tests](https://github.com/spc-group/ophyd-registry/actions/workflows/ci.yml/badge.svg)](https://github.com/spc-group/ophyd-registry/actions/workflows/ci.yml)\n\nA registry to keep track of, and retrieve, Ophyd objects.\n\nThe **Ophyd registry** provides a way to keep track of the devices\n(including components, motors, signals, etc.) that have been defined\nacross a project. In order for the registry to know of a device, that\ndevice must first be registered, though there are ways to do this\nautomatically.\n\nThis allows for a simple way to keep track of the Ophyd devices that were\ncreated in your project.\n\n```python\n\nimport ophyd\nfrom ophydregistry import OphydRegistry\n\n# Register the devices when they're created\nregistry = OphydRegistry()\nregistry.register(ophyd.sim.motor)\n\n# Then elsewhere in your project, use them...\nregistry['motor'].set(15.3)\n\n```\n\nInstallation\n============\n\nThe easiest way to install the ophyd registry is with pip from PyPI:\n\n```bash\npython -m pip install ophyd-registry\n```\n\nTo create a **developer installation**:\n\n```bash\ngit clone https://github.com/spc-group/ophyd-registry.git\npython -m pip install \"ophyd_registry[dev]\"\n```\n\nUsage\n=====\n\nRegistering Devices\n-------------------\n\nThere are three ways to have an instrument registry know about a\ndevice.\n\n1. Implicitly capture all Ophyd objects\n2. Register a device class\n3. Register individual objects\n\nBy default, a new instrument registry will alert itself to all future\ndevices:\n\n```python\nfrom ophydregistry import Registry\nregistry = Registry()\n\nthe_device = MyDevice(\"255id:Dev:\", name=\"my_device\")\n\nassert registry.find(\"my_device\") is the_device\n```\n\nThis greedy behavior can be suppressed with the *auto_register*\nparameter. It can also be turned off after initialization by setting\nthe *auto_register* attribute to ``False``::\n\n```python\n\nregistry = Registry(auto_register=False)\n\n# Make a bunch of devices\n...\n\n# Turn if off for this one\nregistry.auto_register = False\ndevice = MyDevice(...)\nregistry.auto_register = True\n\n# Register some other devices maybe\n...\n\n```\n\nIf *auto_register* is false, then a device class can be\ndecorated to allow the registry to find it:\n\n```python\nfrom ophyd import Device\nfrom ophydregistry import Registry\n\nregistry = Registry(auto_register=False)\n\n@registry.register\nclass MyDevice(Device):\n    ...\n\nthe_device = MyDevice(\"255id:Dev:\", name=\"my_device\")\n\nassert registry.find(\"my_device\") is the_device\n```\n\nLastly, individual instantions of a device can be explicitly\nregistered.\n\n```python\nfrom ophyd import Device\nfrom ophydregistry import Registry\n\nregistry = Registry(auto_register=False)\n\nclass MyDevice(Device):\n    ...\n\nthe_device = MyDevice(\"255id:Dev:\", name=\"my_device\")\nregistry.register(the_device)\n\nassert registry.find(\"my_device\") is the_device\n```\n\nLooking Up Registered Devices/Components\n----------------------------------------\n\nRegistered objects can be found by *name*, *label*, or both. The\neasist way is to treat the registry like a dictionary:\n``registry['motor1']``. This will look for an individual device first\nby *name* then by *label*. It will raise an exception if the number of\ndevices is not 1.\n\nFor more sophisticated queries, the *Registry.find()* method will\nreturn a single result, while *Registry.findall()* returns more than\none. By default, *findall()* will raise an exception if no objects\nmatch the criteria, but this can be overridden with the *allow_none*\nkeyword argument.\n\nThe registry uses the built-in concept of device labels in Ophyd. The\nregistry's ``find()`` and ``findall()`` methods allows devices to be\nlooked up by label or device name. For example, assuming four devices\nexist with the label \"ion_chambers\", then these devices can be\nretrieved using the registry:\n\n```python\nion_chambers = registry.findall(label=\"ion_chambers\")\nassert len(ion_chambers) == 4\n```\n\nDevices can also be found by name:\n\n```python\nion_chambers = registry.find(name=\"I0\")\nassert len(ion_chambers) == 4\n```\n\nA set of the **root devices**, those without a parent, can be\nretrieved at ``Registry.root_devices``.\n\nLooking Up Sub-Components by Dot-Notation\n-----------------------------------------\n\nFor simple devices, the full name of the sub-component should be\nenough to retrieve the device. For example, to find the signal\n*preset_time* on the device named \"vortex_me4\", the following may work\nfine:\n\n```python\npreset_time = haven.registry.find(\"vortex_me4_preset_time\")\n```\n\nHowever, **if the component is lazy** and has not been accessed prior\nto being registered, then **it will not be available in the\nregistry**. Sub-components can instead be accessed by dot\nnotation. Unlike the full device name, dot-notation names only resolve\nwhen the component is requested from the registry, at which point the\nlazy components can be accessed.\n\nFor example, area detectors use many lazy components. If ``sim_det``\nis an area detector with a camera component ``sim_det.cam``, then the\nname of the gain channel is \"sim_det_cam_gain\", however this is a lazy\ncomponent so is not available. Instead, retrieving the device by\n``haven.registry.find(\"sim_det.cam.gain\")`` will first find the area\ndetector (\"sim_det\"), then access the *cam* attribute, and then cam's\n*gain* attribute. This has the side-effect of instantiating the lazy\ncomponents.\n\n\nRemoving Devices\n----------------\n\nThe ``OphydRegistry`` class behaves similarly to a python dictionary.\n\nTo **remove all devices** from the registry, use the ``clear()``\nmethod:\n\n```python\n\nregistry.clear()\n```\n\nTo **remove disconnected devices** from the registry, use the ``pop_disconnected()`` method with an optional timeout:\n\n```python\n\n# Wait 5 seconds to give devices a chance to connect\ndisconnected_devices = registry.pop_disconnected(timeout=5)\n\n```\n\nTo **remove individual objects**, use either the *del* keyword, or the\n``pop()`` method. These approaches work with either the\n``OphydObject`` instance itself, or the instance's name:\n\n```python\n\n# Just delete the item and move on\n# (by name)\ndel registry[\"motor1\"]\n# (by reference)\nmotor = registry['motor1']\ndel registry[motor]\n\n# Remove the item and use it\n# (return a simulated motor if \"motor1\" is not in the registry)\nmotor = registry.pop(\"motor1\", ophyd.sim.motor)\nmotor.set(5).wait()\n\n```\n\nKeeping References\n------------------\n\nIt may be useful to not actually keep a strong reference to the\n``OphydObject``s. This means that if all other references to the\nobject are removed, the device may be dropped from the registry.\n\nBy default, the registry keeps direct references to the objects that\nget registered, but if initalized with ``keep_references=False`` the\nRegistry will not keep these references. Instead, **it is up to you to\nkeep references to the registered objects**.\n\n```python\n\n# Create two registers with both referencing behaviors\nref_registry = Registry(keep_references=True)\nnoref_registry = Registry(keep_references=False)\nmotor = EpicsMotor(...)\n\n# Check if we can get the motor (should be no problem)\nref_registry[motor.name]  # <- succeeds\nnoref_registry[motor.name]  # <- succeeds\n\n# Delete the object and try again\ndel motor\ngc.collect()  # <- make sure it's *really* gone\n\n# Check again if we can get the motor (now it gets fun)\nref_registry[motor.name]  # <- succeeds\nnoref_registry[motor.name]  # <- raises ComponentNotFound\n\n```\n\nIntegrating with Typhos\n-----------------------\n\nTyphos includes a PyDM plugin that can directly interact with ophyd\ndevices. It requires ophyd objects to be registered in order to find\nthem. **ophyd_registry** can automatically register devices with\nTyphos by simply passing the *use_typhos* argument when creating the\nregistry:\n\n```python\n    \nfrom ophydregistry import Registry\nregistry = Registry(use_typos=True)\n\n```\n\nor setting the *use_typhos* attribute on an existing registry:\n\n```python\n    \nfrom ophydregistry import Registry\nregistry = Registry()\nregistry.use_typhos = True\n\n```\n\nIf using the typhos registry, calling the *clear()* method on the\nophyd registry will also clear the Typhos registry.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A registry to keep track of, and retrieve, Ophyd objects.",
    "version": "1.5.0",
    "project_urls": {
        "Bug Tracker": "https://github.com/spc-group/ophyd-registry/issues",
        "Homepage": "https://github.com/spc-group/ophyd-registry"
    },
    "split_keywords": [
        "synchrotron",
        " xray",
        " bluesky"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "db81cb0c76134c437a02549e9e2b7fca29943d90d27d5e4760c0f0ec86454580",
                "md5": "2d38e0dd01e5b1adaef04c838e1dc1d7",
                "sha256": "b1d4ad886d02b4f067e0b44afdfe09ac4aca99047d6dc0ab86ba23e65ec60145"
            },
            "downloads": -1,
            "filename": "ophyd_registry-1.5.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "2d38e0dd01e5b1adaef04c838e1dc1d7",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 14036,
            "upload_time": "2024-11-22T18:20:06",
            "upload_time_iso_8601": "2024-11-22T18:20:06.854084Z",
            "url": "https://files.pythonhosted.org/packages/db/81/cb0c76134c437a02549e9e2b7fca29943d90d27d5e4760c0f0ec86454580/ophyd_registry-1.5.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "41d28dfb0b9160f300972cb7efc09e9efc8ed5eb4dba4c8b66f46428ca57e6b5",
                "md5": "df739e4b673e6888255ba7f824a786a3",
                "sha256": "31d0f32a3c24bff6f7c46f4e2f6e8731d38357f72a28489a72dbbb0034fba630"
            },
            "downloads": -1,
            "filename": "ophyd_registry-1.5.0.tar.gz",
            "has_sig": false,
            "md5_digest": "df739e4b673e6888255ba7f824a786a3",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 13109,
            "upload_time": "2024-11-22T18:20:10",
            "upload_time_iso_8601": "2024-11-22T18:20:10.338313Z",
            "url": "https://files.pythonhosted.org/packages/41/d2/8dfb0b9160f300972cb7efc09e9efc8ed5eb4dba4c8b66f46428ca57e6b5/ophyd_registry-1.5.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-22 18:20:10",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "spc-group",
    "github_project": "ophyd-registry",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "ophyd-registry"
}
        
Elapsed time: 1.04663s