nspyre
Subpackages
nspyre.cli
nspyre.data
nspyre.extras
nspyre.gui
nspyre.gui.style
nspyre.gui.widgets
nspyre.gui.widgets.experiment
nspyre.gui.widgets.flex_line_plot
nspyre.gui.widgets.heatmap
nspyre.gui.widgets.layout
nspyre.gui.widgets.line_plot
nspyre.gui.widgets.main
nspyre.gui.widgets.params
nspyre.gui.widgets.save_load
nspyre.gui.widgets.separator
nspyre.gui.widgets.snake
nspyre.gui.widgets.subsystem
nspyre.gui.widgets.update_loop
nspyre.gui.app
nspyre.gui.debug
nspyre.gui.threadsafe
nspyre.instrument
nspyre.misc
Package Contents
Classes
For sinking data from the |
|
For sourcing data to the |
|
List-like object that can be streamed efficiently through the |
|
Generalized experimental subsystem that allows for management of dependencies between subsystems for boot sequencing. |
|
Create a connection to an |
|
Wrapper for a device residing in an |
|
For consolidating connections to multiple instrument gateways. |
|
Wrapper for a device residing in an |
|
RPyC service that loads devices and exposes them to the client. |
|
Run a function in a new process. |
Functions
|
Run a command-line interface to allow user interaction with the data server. |
|
Run a command-line interface to allow user interaction with the instrument server. |
|
Start an instrument server and serve a CLI. |
|
Load data from a JSON file. |
|
Load data from a Python pickle file. |
|
Save data to a json file. |
|
Save data to a python pickle file. |
|
Initialize system-wide logging to stdout/err and, optionally, a file. |
Attributes
True if the packages for a Qt GUI are installed. |
|
Pint Quantity class. This is provided for backwards compatibility but is not recommended for future use. |
- nspyre.serve_data_server_cli(dataserv)
Run a command-line interface to allow user interaction with the data server.
- Parameters:
dataserv –
DataServer
object.
- nspyre.serve_instrument_server_cli(inserv)
Run a command-line interface to allow user interaction with the instrument server.
- Parameters:
inserv –
InstrumentServer
orInstrumentGateway
object.
- nspyre.start_instrument_server(drivers=None, inserv_kwargs=None)
Start an instrument server and serve a CLI.
- Parameters:
drivers – A list of dictionaries, where each dictionary contains keyword arguments to the InstrumentServer
add()
method.inserv_kwargs – Keyword arguments to pass to
InstrumentServer.__init__
.
- class nspyre.DataSink(name, addr='localhost', port=DATASERV_PORT, auto_reconnect=False)
For sinking data from the
DataServer
.data
can be used to directly access the python object pushed by the source. E.g.:First, start the data server:
$ nspyre-dataserv
from nspyre import DataSink, DataSource with DataSource('my_dataset') as src: src.push('Data!') with DataSink('my_dataset') as sink: sink.pop() print(sink.data)
Alternatively, if the data pushed by the source is a dictionary, its values can be accessed as if they were attributes of the sink, e.g.:
from nspyre import DataSink, DataSource with DataSource('my_dataset') as src: data = { 'some_data': 1, 'some_other_data': 'a string' } src.push(data) with DataSink('my_dataset') as sink: sink.pop() print(sink.some_data) print(sink.some_other_data)
- Parameters:
name (str) – Name of the data set.
addr (str) – Network address of the data server.
port (int) – Port of the data server.
auto_reconnect (bool) – If True, automatically reconnect to the data server if it is disconnected. Otherwise raise an error if connection fails.
- data: Any
The object pushed by the
DataSource
.
- start()
Connect to the data server.
- stop()
Disconnect from the data server.
- pop(timeout=None)
Block waiting for an updated version of the data from the data server. Once the data is received, the internal
data
attribute will be updated and the function will return.Typical usage example:
First start the data server from the console on machine A:
$ nspyre-dataserv
Run the python program on machine A implementing the experimental logic:
# machine A: "source"-side code # running on the same machine as the data server, in the same or a # different process from nspyre import DataSource import numpy as np # connect to the data server and create a data set, or connect to an # existing one with the same name if it was created earlier with DataSource('my_dataset') as source: # do an experiment where we measure voltage of something as a # function of frequency n = 100 frequencies = np.linspace(1e6, 100e6, n) voltages = np.zeros(n) for f in frequencies: signal_generator.set_frequency(f) voltages[i] = daq.get_voltage() # push most up-to-date data to the server source.push({'freq': frequencies, 'volts': voltages})
Then run the python program on machine B implementing the data plotting:
# machine B: "sink"-side code # running on a different machine as the source / data server from nspyre import DataSink # connect to the data set on the data server # IP of data server computer = '192.168.1.50' with DataSink('my_dataset', '192.168.1.50') as sink: while True: # block until an updated version of the data set is available sink.pop(): # sink.freq and sink.volts have been modified # replot the data to show the new values my_plot_update(sink.freq, sink.volts)
- Parameters:
timeout – Time to wait for an update in seconds. Set to
None
to wait forever.- Raises:
TimeoutError – A timeout occured.
RuntimeError – The sink isn’t properly initialized.
- class nspyre.DataSource(name, addr='localhost', port=DATASERV_PORT, auto_reconnect=False)
For sourcing data to the
DataServer
. Seepop()
for typical usage example.- Parameters:
name (str) – Name of the data set.
addr (str) – Network address of the data server.
port (int) – Port of the data server.
auto_reconnect (bool) – If True, automatically reconnect to the data server if it is disconnected. Otherwise raise an error if connection fails.
- start()
Connect to the data server.
- stop()
Disconnect from the data server.
- push(data)
Push new data to the data server.
- Parameters:
data – Any python object (must be pickleable) to send. Ideally, this should be a dictionary to allow for simple attribute access from the sink side like
sink.my_var
.
- nspyre.load_json(filename)
Load data from a JSON file.
- Parameters:
filename (Union[str, pathlib.Path]) – File to load from.
- Returns:
A Python object loaded from the file.
- Return type:
Any
- nspyre.load_pickle(filename)
Load data from a Python pickle file.
- Parameters:
filename (Union[str, pathlib.Path]) – File to load from.
- Returns:
A Python object loaded from the file.
- Return type:
Any
- nspyre.save_json(filename, data)
Save data to a json file.
- Parameters:
filename (Union[str, pathlib.Path]) – File to save to.
data (Any) – Python object to save.
- nspyre.save_pickle(filename, data)
Save data to a python pickle file.
- Parameters:
filename (Union[str, pathlib.Path]) – File to save to.
data (Any) – Python object to save.
- class nspyre.StreamingList(iterable=None)
List-like object that can be streamed efficiently through the
DataServer
.StreamingList
is meant to act as a drop-in replacement for a python list. When this object is pushed to the data server using a call topush()
, instead of sending the whole contents ofStreamingList
, only the differences since the lastpush()
are sent. This allows for much higher data throughput for larger data sets.Although
StreamingList
is typically able to automatically calculate the differences since the lastpush()
, there is one situation where this is not possible: if a mutable object that is contained somewhere inside theStreamingList
is modified, it cannot be detected. In this situation, theStreamingList
must be manually notified that one of its items has been updated, e.g.:import numpy as np from nspyre import DataSource from nspyre import StreamingList with DataSource('my_dataset') as src: sl = StreamingList() a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) c = np.array([7, 8, 9]) # these StreamingList calls will automatically calculate diffs sl.append(a) sl.append(b) sl.append(c) src.push(sl) # here we are modifying a mutable object inside of the StreamingList, # which it cannot detect a[1] = 10 # we can manually tell the StreamingList that its object 'a' was modified sl.updated_item(0) src.push(sl)
- Parameters:
iterable – iterable object to initialize the contents of the list with, e.g.
sl = StreamingList([1, 2, 3])
.
- updated_item(idx)
The item at the given index was modified, and, therefore, its cached value is no longer valid and must be updated.
- Parameters:
idx – index that was modified
- insert(idx, val, register_diff=True)
See docs for Python list.
- remove(val)
See docs for Python list.
- pop(idx)
See docs for Python list.
- append(val)
See docs for Python list.
- extend(val)
See docs for Python list.
- clear()
See docs for Python list.
- sort(*args, **kwargs)
See docs for Python list.
- reverse()
See docs for Python list.
- copy()
See docs for Python list.
- class nspyre.Subsystem(name, pre_dep_boot=None, post_dep_boot=None, default_boot_timeout=10, default_boot_inserv=None, default_boot_add_args=None, default_boot_add_kwargs=None, pre_dep_shutdown=None, post_dep_shutdown=None, dependencies=None)
Generalized experimental subsystem that allows for management of dependencies between subsystems for boot sequencing.
- Parameters:
name (str) – Subsystem name.
pre_dep_boot (Optional[Callable]) – Function to run before booting any dependency subsystems. It should take 1 argument, which is the subsystem object.
post_dep_boot (Optional[Callable]) – Function to run to boot the subsystem after booting any dependency subsystems. It should take 1 argument, which is the subsystem object. If None,
default_boot()
will be used.default_boot_timeout (float) – Time to wait (s) for the driver to initialize in
default_boot()
.default_boot_inserv (Optional[Union[nspyre.instrument.server.InstrumentServer, nspyre.instrument.gateway.InstrumentGateway]]) –
InstrumentServer
(or a connectedInstrumentGateway
) to add the driver to indefault_boot()
.default_boot_add_args (Optional[list]) – Arguments to pass to the
InstrumentServer
add()
method to create the driver indefault_boot()
.default_boot_add_kwargs (Optional[Dict]) – Keyword arguments to pass to the
InstrumentServer
add()
method to create the driver indefault_boot()
.pre_dep_shutdown (Optional[Callable]) – Function to run once shutdown is requested, but before shutting down any dependencies. It should take 1 argument, which is the subsystem object. If None,
default_shutdown()
will be used.post_dep_shutdown (Optional[Callable]) – Function to run after shutting down any dependencies. It should take 1 argument, which is the subsystem object.
dependencies (Optional[list]) – List of Subsystem objects this subsystem depends on. They will be booted (in order) before this subsystem, and shutdown (in reverse order) after this subsystem shuts down.
- default_boot()
Tries to add the driver to the
InstrumentServer
in a loop, untildefault_boot_timeout
has elapsed.
- default_shutdown()
Remove the driver from the
InstrumentServer
.
- boot(boot_dependencies=True)
- Parameters:
boot_dependencies (bool) – if True, boot all dependencies before booting this subsystem.
- shutdown(shutdown_dependencies=True)
Shutdown the subsystem.
- Parameters:
shutdown_dependencies (bool) – if True, shutdown all dependencies after shutting down
- nspyre.Qt_GUI: bool = False
True if the packages for a Qt GUI are installed.
- class nspyre.InstrumentGateway(addr='localhost', port=INSTRUMENT_SERVER_DEFAULT_PORT, conn_timeout=0.0, sync_timeout=RPYC_SYNC_TIMEOUT)
Create a connection to an
InstrumentServer
and access it’s devices. When accessing a device through the gateway usinggateway.my_device
notation, anInstrumentGatewayDevice
is returned.Usage Example:
from nspyre import InstrumentGateway with InstrumentGateway() as gw: # d is an InstrumentGatewayDevice object d = gw.dev1 # run the set_something() method of dev1 d.set_something(5) # run the get_something() method of dev1 and print its return value print(d.get_something())
- Parameters:
addr (str) – Network address of the
InstrumentServer
.port (int) – Port number of the
InstrumentServer
.conn_timeout (float) – Lower bound on the time to wait for the connection to be established.
sync_timeout (float) – Time to wait for requests / function calls to finish.
- Raises:
InstrumentGatewayError – Connection to the
InstrumentServer
failed.
- connect()
Attempt connection to an
InstrumentServer
.- Raises:
InstrumentGatewayError – Connection to the
InstrumentServer
failed.
- is_connected()
Return whether the gateway is connected.
- Return type:
bool
- disconnect()
Disconnect from the
InstrumentServer
.
- reconnect()
Disconnect then connect to the
InstrumentServer
again.- Raises:
InstrumentGatewayError – Connection to the
InstrumentServer
failed.
- class nspyre.InstrumentGatewayDevice(name, gateway)
Wrapper for a device residing in an
InstrumentGateway
. When we access an attribute of a device from anInstrumentGateway
, it will return an rpyc netref object. This creates a problem when the gateway disconnects from the instrument server, then later reconnects. If we have an rpyc netref that pointed to a device attribute, it will be stale because it was linked to the original gateway. However, if we instead pass around this InstrumentGatewayDevice, we can always re-access the gateway device whenever we want to access an attribute of the device. This way, if the gateway disconnects then reconnects, we will always be accessing the attributes of the newly connected gateway, rather than a stale netref.Accessing the “device” attribute will return (an rpyc netref to) the device object. Attributes of the device can be accessed directly from this object. E.g.:
from nspyre import InstrumentGateway with InstrumentGateway() as gw: # let's assume "dev1" was created on the instrument server as an # instance of "MyDriver" # d is an InstrumentGatewayDevice object d = gw.dev1 # run the get_something() method of dev1 and print its return value print(d.get_something()) # does the same thing print(d.device.get_something()) print(isinstance(gw.dev1, MyDriver)) # False print(isinstance(gw.dev1, InstrumentGatewayDevice)) # True print(isinstance(gw.dev1.device, MyDriver)) # True
- Parameters:
name (str) – Name of the device on the gateway.
gateway (InstrumentGateway) –
InstrumentGateway
object containing the device.
- exception nspyre.InstrumentGatewayError(*args, **kwargs)
Raised for failures related to the
InstrumentGateway
.- Parameters:
args – Arguments to pass to super class Exception().
kwargs – Keyword arguments to pass to super class Exception().
- class nspyre.InstrumentManager(*register_gateway_args, register_gateway=True, auto_device_discovery=True, **register_gateway_kwargs)
For consolidating connections to multiple instrument gateways. If only connecting to a single
InstrumentGateway
, you can simply pass the arguments and keyword arguments that you’d normally pass to the gateway here. TheInstrumentManager
returns anInstrumentManagerDevice
when a device attribute is accessed, e.g.:from nspyre import InstrumentManager with InstrumentManager() as mgr: # let's assume "dev1" was created on the instrument server as an # instance of "MyDriver" # d is an InstrumentManagerDevice object d = mgr.dev1 # run the get_something() method of dev1 and print its return value print(d.get_something()) print(isinstance(mgr.dev1, MyDriver)) # False print(isinstance(mgr.dev1, InstrumentManagerDevice)) # True
- Parameters:
register_gateway_args – See arguments for
register_gateway()
.register_gateway (bool) – if True, call
register_gateway()
.auto_device_discovery (bool) – if True, when an attribute of the manager is accessed, but the device hasn’t been registered yet with the manager using
register_device()
, the device will be automatically registered.register_gateway_kwargs – See keyword arguments for
register_gateway()
.
- register_gateway(*gateway_args, default_exclude=False, exclude=None, name_mapping=None, **gateway_kwargs)
Create and connect to an ~nspyre.instrument.gateway.InstrumentGateway, associate it with this
InstrumentManager
, and add all of its devices to thisInstrumentManager
.- Parameters:
gateway_args – See arguments for
InstrumentGateway
.gateway_kwargs – See keyword arguments for
InstrumentGateway
.default_exclude (bool) – If True, only add those devices specified in the
name_mapping
.exclude (Optional[list[str]]) – List of device names on the
InstrumentServer
that won’t be added to theInstrumentManager
.name_mapping (Optional[Dict[str, str]]) – Keys should be the device names on the
InstrumentServer
whose values are the corresponding desired name on theInstrumentManager
. Otherwise their name on theInstrumentManager
will be the same as that on theInstrumentServer
.
- register_device(dev, name=None)
Add a device to the
InstrumentManager
.- Parameters:
dev (nspyre.instrument.gateway.InstrumentGatewayDevice) – The device to add.
name (Optional[str]) – The name of the device on the
InstrumentManager
. IfNone
, theInstrumentGatewayDevice
name will be used.
- disconnect()
Disconnect from all
InstrumentGateway
.
- class nspyre.InstrumentManagerDevice(name, manager)
Wrapper for a device residing in an
InstrumentManager
. Performs similar a function as anInstrumentGatewayDevice
. See those docs for details.- Parameters:
name (str) – Name of the device on the gateway.
gateway –
InstrumentGateway
object containing the device.manager (InstrumentManager) –
- class nspyre.InstrumentServer(port=INSTRUMENT_SERVER_DEFAULT_PORT, sync_timeout=RPYC_SYNC_TIMEOUT)
RPyC service that loads devices and exposes them to the client.
The RPyC service starts a new thread running an RPyC server. Clients may connect and access devices or command the server to add, remove, or restart devices (through the
InstrumentGateway
).- Parameters:
port (int) – Port number to use for the RPyC server.
sync_timeout (float) – Time to wait for requests / function calls to finish.
- add(name, class_path, class_name, args=None, kwargs=None, import_or_file='file', local_args=False)
Create an instance of the specified class and add it to the instrument server.
- Parameters:
name (str) – Alias for the device.
class_path (str) – If import_or_file is
'file'
, path to the file on the filesystem containing the class, e.g.'~/drivers/rohde_schwarz/hmp4040.py'
. If import_or_file is'import'
, python module containing the class, e.g.'nspyre_drivers.rohde_schwarz.hmp4040.hmp4040'
.class_name (str) – Name of the class to create an instance of, e.g.
'HMP4040'
.args (Optional[list]) – Arguments to pass to
class_name.__init__
.kwargs (Optional[Dict]) – Keyword arguments to pass to
class_name.__init__
..import_or_file (str) –
'file'
for creating the device object from a file on the filesystem,'import'
for creating the device object from a python module.local_args (bool) – If True, all arguments to this method are assumed to be local variables not passed through an
InstrumentGateway
. In this case, the arguments will be taken as-is. If False, all arguments will be retrieved using rpyc.utils.classic.obtain in order to ensure they are not netrefs.
- Raises:
ValueError – An argument was invalid.
InstrumentServerDeviceExistsError – Tried to add a device that already exists.
InstrumentServerError – Anything else.
- remove(name)
Remove a device from the instrument server.
- Parameters:
name (str) – Alias for the device.
- Raises:
InstrumentServerError – Deleting the device failed.
- restart(name)
Restart the specified device by deleting it and creating a new instance.
- Parameters:
name (str) – Alias for the device.
- Raises:
InstrumentServerError – Deleting the device failed.
- restart_all()
Restart all devices on the server.
- Raises:
InstrumentServerError – Deleting a device failed.
- start()
Start the RPyC server.
- Raises:
InstrumentServerError – The server was already running.
- stop()
Stop the RPyC server.
- Raises:
InstrumentServerError – The server wasn’t running.
- devs()
Return all of the devices on the InstrumentSever.
- Returns:
The device names as keys and device objects as values.
- Return type:
dict
- on_connect(conn)
Called when a client connects to the RPyC server.
- Parameters:
conn (rpyc.core.protocol.Connection) –
- on_disconnect(conn)
Called when a client disconnects from the RPyC server.
- Parameters:
conn (rpyc.core.protocol.Connection) –
- exception nspyre.InstrumentServerDeviceExistsError(*args, **kwargs)
Raised if attempting to add a device that already exists to the
InstrumentServer
.- Parameters:
args – Arguments to pass to super class Exception().
kwargs – Keyword arguments to pass to super class Exception().
- exception nspyre.InstrumentServerError(*args, **kwargs)
Raised for failures related to the
InstrumentServer
.- Parameters:
args – Arguments to pass to super class Exception().
kwargs – Keyword arguments to pass to super class Exception().
- nspyre.nspyre_init_logger(log_level, log_path=None, log_path_level=None, prefix='', file_size=None, remove_handlers=True)
Initialize system-wide logging to stdout/err and, optionally, a file.
- Parameters:
log_level (int) – Log messages of lower severity than this will not be sent to stdout/err (e.g.
logging.INFO
).log_path (Optional[pathlib.Path]) – If a file, log to that file. If a directory, generate a log file name containing the prefix and date/time, and create a new log file in that directory. If
None
, only log to stdout/err.log_path_level (Optional[int]) – Logging level for the log file. Leave as
None
for same as log_level.prefix (str) – If a directory was specified for log_path, prepend this string to the log file name.
file_size (Optional[int]) – Maximum log file size (bytes). If this size is exceeded, the log file is rotated according to
RotatingFileHandler
(https://docs.python.org/3/library/logging.handlers.html).remove_handlers (bool) – If true, remove any existing log handlers.
- class nspyre.ProcessRunner(kill=True)
Run a function in a new process.
- Parameters:
kill – Whether to kill a previously running process that hasn’t completed.
- run(fun, *args, **kwargs)
Run the provided function in a separate process.
- Parameters:
fun – Function to run.
args – Arguments to pass to fun.
kwargs – Keyword arguments to pass to fun.
- Raises:
RuntimeError – The function from a previous call is still running.
- running()
Return True if the process is running.
- kill()
Kill the process.
- nspyre.Q_
Pint Quantity class. This is provided for backwards compatibility but is not recommended for future use.