Facets

Note

Facets are new in version 0.4

Introduction

A Facet represents a property of an instrument—for example, the wavelength setting on an optical power meter. Facets exist to ease driver development and help to provide a consistent driver interface with features like unit conversion and bounds-checking. They also make driver code more declarative, and hence easier to read. Take, for example, this snippet from the Thorlabs PM100D driver:

class PM100D(PowerMeter, VisaMixin):
    """A Thorlabs PM100D series power meter"""
    [...]
    wavelength = SCPI_Facet('sense:corr:wav', units='nm', type=float,
                            doc="Input signal wavelength")

This is not much code, yet it already gives us something pretty useful. If we open such a power meter, we can see how its wavelength facet behaves:

>>> pm.wavelength
<Quantity(852.0, 'nanometer')
>>> pm.wavelength = '532 nm'
>>> pm.wavelength
<Quantity(532.0, 'nanometer')
>>> pm.wavelength = 1064
DimensionalityError: Cannot convert from 'dimensionless' to 'nanometer'

As you can see, the facet automatically parses and checks units, and converts any ints to floats. We could also specify the allowed wavelength range if we wanted to.

You’ll notice the code above uses SCPI_Facet, which is a helper function for creating facets that use SCPI messaging standards. When we enter pm.wavelength, it sends the message "sense:corr:wav?" to the device, reads its response, and converts it into the proper type and units. Similarly, when we enter pm.wavelength = '532 nm', it sends the message "sense:corr:wav 532" to the device.

If you’re using a message-based device with slightly different message format, it’s easy to write your own wrapper function that calls MessageFacet. Check out the source of SCPI_Facet to see how this is done. It’s frequently useful to write a helper function like this for a given driver, even if it’s not message-based.

Facets are partially inspired by the Lantz concept of Features (or ‘Feats’).

API

class instrumental.drivers.Facet(fget=None, fset=None, doc=None, cached=True, type=None, units=None, value=None, limits=None, name=None)

Property-like class representing an attribute of an instrument.

Parameters:
  • fget (callable, optional) – A function to be used for getting the facet’s value.
  • fset (callable, optional) – A function to be used for setting the facet’s value.
  • doc (str, optional) – Docstring to describe the facet
  • cached (bool, optional) – Whether the facet should use caching. If True, the repeated writes of the same value will only write to the instrument once, while repeated reads of a value will only query the instrument once. Therefore, one should be careful to use caching only when it makes sense. Caching can be disabled on a per-get or per-set basis by using the use_cache parameter to get_value() or set_value().
  • type (callable, optional) – Type of the outward-facing value of the facet. Typically an actual type like int, but can be any callable that converts a value to the proper type.
  • units (pint.Units or corresponding str) – Physical units of the facet’s value. Used for converting both user input (when setting) and the output of fget (when getting).
  • value (dict-like, optional) – A map from ‘external’ values to ‘internal’ facet values. Used internally to convert input values for use with fset and to convert values returned by fget into ‘nice’ values fit force user consumption.
  • limits (sequence, optional) – Limits specified in [stop], [start, stop], or [start, stop, step] format. When given, raises a ValueError if a user tries to set a value that is out of range. step, if given, is used to round an in-range value before passing it to fset.
instrumental.drivers.MessageFacet(get_msg=None, set_msg=None, convert=None, **kwds)

Convenience function for creating message-based Facets.

Creates fget and fset functions that are passed to Facet, based on message templates. This is primarily used for writing your own Facet-creating helper functions for message-based drivers that have a unique message format. For standard SCPI-style messages, you can use SCPI_Facet() directly.

This is for use with VisaMixin, as it assumes the instrument has write and query methods.

Parameters:
  • get_msg (str, optional) – Message used to query the facet’s value. If omitted, getting is unsupported.
  • set_msg (str, optional) – Message used to set the facet’s value. This string is filled in with set_msg.format(value), where value is the user-given value being set.
  • convert (function or callable) – Function that converts both the string returned by querying the instrument and the set-value before it is passed to str.format(). Usually something like int or float.
  • **kwds – Any other keywords are passed along to the Facet constructor
instrumental.drivers.SCPI_Facet(msg, convert=None, readonly=False, **kwds)

Facet factory for use in VisaMixin subclasses that use SCPI messages

Parameters:
  • msg (str) – Base message used to create SCPI get- and set-messages. For example, if msg='voltage', the get-message is 'voltage?' and the set-message becomes 'voltage {}', where {} gets filled in by the value being set.
  • convert (function or callable) – Function that converts both the string returned by querying the instrument and the set-value before it is passed to str.format(). Usually something like int or float.
  • readonly (bool, optional) – Whether the Facet should be read-only.
  • **kwds – Any other keywords are passed along to the Facet constructor