diff --git a/spacq/devices/Scientific_Instruments/model9700.py b/spacq/devices/Scientific_Instruments/model9700.py index 9fbee73..1cde801 100644 --- a/spacq/devices/Scientific_Instruments/model9700.py +++ b/spacq/devices/Scientific_Instruments/model9700.py @@ -36,6 +36,10 @@ def _connected(self): def temperature(self): """ The value measured by the device, as a quantity in K. + + Returns + ------- + float """ while True: @@ -50,6 +54,10 @@ def temperature(self): def power(self): ''' The value of the PID as a percentage. + + Returns + ------- + float ''' # Sometimes does not answer the correct query, so need to ask until we get the desired response diff --git a/spacq/devices/abstract_device.py b/spacq/devices/abstract_device.py index 3f5f2bf..25f60c4 100644 --- a/spacq/devices/abstract_device.py +++ b/spacq/devices/abstract_device.py @@ -52,6 +52,9 @@ class DeviceTimeout(Exception): class SuperDevice(object): + """ + A superclass for all devices. + """ def _setup(self): """ Pre-connection setup. @@ -77,6 +80,32 @@ def _connected(self): class AbstractDevice(SuperDevice): """ A class for controlling devices which can be connected to either via Ethernet and (PyVISA or Telnet) or GPIB and Linux GPIB. + + Parameters + ---------- + Ethernet (tcpip::::instr): + ip_address : str, optional + Address on which the device is listening on port 111. + + Telnet (): + host_address : str, optional + String that list the IP address of the host. + Named this way to avoid issues with ip_address used for ethernet connections + + GPIB (gpib[gpib_board]::[::]::instr): + gpib_board : int, optional + GPIB board index. Defaults to 0. + gpib_pad : int, optional + Primary address of the device. + gpib_sad : int, optional + Secondary address of the device. Defaults to 0. + + USB (usb_resource): + usb_resource : str, optional + VISA resource of the form: USB[board]::::::[::]::RAW + + autoconnect : bool, optional + """ max_timeout = 15 # s @@ -93,24 +122,6 @@ def _setup(self): def __init__(self, ip_address=None, host_address=None, gpib_board=0, gpib_pad=None, gpib_sad=0, usb_resource=None, autoconnect=True): - """ - Ethernet (tcpip::::instr): - ip_address: Address on which the device is listening on port 111. - - Telnet (): - host_address: String that list the IP address of the host. - Named this way to avoid issues with ip_address used for ethernet connections - - GPIB (gpib[gpib_board]::[::]::instr): - gpib_board: GPIB board index. Defaults to 0. - gpib_pad: Primary address of the device. - gpib_sad: Secondary address of the device. Defaults to 0. - - USB (usb_resource): - usb_resource: VISA resource of the form: USB[board]::::::[::]::RAW - - autoconnect: Connect to the device upon instantiation. - """ self._setup() @@ -170,6 +181,13 @@ def __init__(self, ip_address=None, host_address=None, gpib_board=0, gpib_pad=No self.connect() def __repr__(self): + """ + Return a string representation of the device. + + Return + ------ + str + """ return '<{0}>'.format(self.__class__.__name__) def connect(self): @@ -226,7 +244,10 @@ def multi_command_stop(self): """ Stop redirecting to a buffer, and send the buffered commands. - Returns the results of queries if any were expected. + Returns + ------- + list of str + the results of queries if any were expected """ log.debug( @@ -262,6 +283,10 @@ def write(self, message): Write to the device. Supports multi-command. + + Parameters + ---------- + message : str """ if self.multi_command is not None: @@ -299,6 +324,15 @@ def write(self, message): def read_raw(self, chunk_size=512): """ Read everything the device has to say and return it exactly. + + Parameters + ---------- + chunk_size : int, optional + The maximum number of bytes to read at once. + + Returns + ------- + str """ log.debug('Reading from device "{0}".'.format(self.name)) @@ -327,6 +361,10 @@ def read_raw(self, chunk_size=512): def read(self): """ Read from the device, but strip terminating whitespace. + + Returns + ------- + str """ return self.read_raw().rstrip() @@ -335,6 +373,14 @@ def read(self): def ask_raw(self, message): """ Write, then read_raw. + + Parameters + ---------- + message : str + + Returns + ------- + str """ self.write(message) @@ -346,6 +392,14 @@ def ask(self, message): Write, then read. Supports multi-command. + + Parameters + ---------- + message : str + + Returns + ------- + str """ self.write(message) @@ -359,6 +413,14 @@ def ask(self, message): def query(self, message): """ Write then read using PyVisa's query command. + + Parameters + ---------- + message : str + + Returns + ------- + str """ return self.device.query(message) @@ -377,6 +439,14 @@ def find_resource(self, path): Return a Resource given a resource path spec. eg. ('subdevice A', 'subdevice B', 'resource C') -> Resource + + Parameters + ---------- + path : tuple of str + + Returns + ------- + Resource """ log.debug('Looking for resource {0}.'.format(path)) @@ -409,6 +479,10 @@ def find_resource(self, path): def idn(self): """ Ask the device for identification. + + Returns + ------- + str """ if self.driver in [drivers.pyvisa]: @@ -436,6 +510,10 @@ def opc(self): class AbstractSubdevice(SuperDevice): """ A subdevice (eg. channel) of a hardware device. + + Parameters + ---------- + device : AbstractDevice """ def _setup(self): diff --git a/spacq/devices/agilent/dm34401a.py b/spacq/devices/agilent/dm34401a.py index 2ff4679..9512efa 100644 --- a/spacq/devices/agilent/dm34401a.py +++ b/spacq/devices/agilent/dm34401a.py @@ -61,6 +61,10 @@ def reset(self): def integration_time(self): """ The integration time of the multimeter in terms of PLC. + + Returns + ------- + float """ return float(self.ask('sense:voltage:dc:nplc?')) @@ -76,6 +80,10 @@ def integration_time(self, value): def auto_zero(self): """ The auto zero state. + + Returns + ------- + str """ # result = self.ask('sense:voltage:dc:zero:auto?') diff --git a/spacq/devices/agilent/dm34410a.py b/spacq/devices/agilent/dm34410a.py index 576ac3d..ebc1db8 100644 --- a/spacq/devices/agilent/dm34410a.py +++ b/spacq/devices/agilent/dm34410a.py @@ -60,6 +60,10 @@ def reset(self): def integration_time(self): """ The integration time of the multimeter in terms of PLC. + + Returns + ------- + float """ return float(self.ask('sense:voltage:dc:nplc?')) @@ -75,6 +79,10 @@ def integration_time(self, value): def auto_zero(self): """ The auto zero state. + + Returns + ------- + str """ result = self.ask('sense:voltage:dc:zero:auto?') @@ -97,6 +105,10 @@ def auto_zero(self, value): def reading(self): """ The value measured by the device, as a quantity in V. + + Returns + ------- + float """ self.status.append('Taking reading') diff --git a/spacq/devices/agilent/mock/mock_dm34401a.py b/spacq/devices/agilent/mock/mock_dm34401a.py index e3a601a..105f36e 100644 --- a/spacq/devices/agilent/mock/mock_dm34401a.py +++ b/spacq/devices/agilent/mock/mock_dm34401a.py @@ -26,6 +26,17 @@ def _reset(self): self.mock_state['auto_zero'] = 1 def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + The response to return. + done : bool, optional + True if this is the last message in a sequence. + """ if not done: cmd, args, query = self._split_message(message) diff --git a/spacq/devices/agilent/mock/mock_dm34410a.py b/spacq/devices/agilent/mock/mock_dm34410a.py index 1ffb40e..0043f3b 100644 --- a/spacq/devices/agilent/mock/mock_dm34410a.py +++ b/spacq/devices/agilent/mock/mock_dm34410a.py @@ -26,6 +26,17 @@ def _reset(self): self.mock_state['auto_zero'] = 1 def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + The response to return. + done : bool, optional + True if this is the last message in a sequence. + """ if not done: cmd, args, query = self._split_message(message) diff --git a/spacq/devices/agilent/nwa8753et.py b/spacq/devices/agilent/nwa8753et.py index fe4a38e..a70d374 100644 --- a/spacq/devices/agilent/nwa8753et.py +++ b/spacq/devices/agilent/nwa8753et.py @@ -59,6 +59,10 @@ def reset(self): def cwFreq(self): """ The frequency of the networkAnalyzer output + + Returns + ------- + float """ return float(self.ask('cwfreq?')) @@ -72,6 +76,10 @@ def cwFreq(self, value): def power(self): """ The power (in dB) + + Returns + ------- + float """ return float(self.ask('powe?')) @@ -85,6 +93,10 @@ def power(self, value): def marker(self): """ The value measured by the device at marker, as a quantity in dB. + + Returns + ------- + float """ self.status.append('Taking reading') @@ -104,6 +116,10 @@ def marker(self): def markFreq(self): """ The frequency of the marker in Hz + + Returns + ------- + float """ return float(self.ask('MARK1?')) diff --git a/spacq/devices/basel/dacsp927.py b/spacq/devices/basel/dacsp927.py index 422a967..7b45303 100644 --- a/spacq/devices/basel/dacsp927.py +++ b/spacq/devices/basel/dacsp927.py @@ -17,6 +17,14 @@ class Port(AbstractSubdevice): """ An output port on the voltage source. + + Parameters + ---------- + device : AbstractDevice + The voltage source to which this Port belongs. + num : int + The index of this port. + """ def _setup(self): @@ -31,6 +39,9 @@ def _setup(self): @Synchronized() def _connected(self): + """ + Turn on the port and get the current voltage. + """ AbstractSubdevice._connected(self) # Turn on port @@ -59,8 +70,6 @@ def voltage_to_hex(self, voltage): def __init__(self, device, num, *args, **kwargs): """ Initialize the output port. - device: The voltage source to which this Port belongs. - num: The index of this port. """ AbstractSubdevice.__init__(self, device, *args, **kwargs) self.num = num @@ -91,6 +100,11 @@ def voltage(self, value): class dacsp927(AbstractDevice): """ Interface for the Physics Basel DAC SP 927 voltage source + + Parameters + ---------- + port_settings : dict, optional + A dictionary of values to give to each port upon creation. """ def _setup(self): @@ -106,7 +120,6 @@ def _setup(self): def __init__(self, port_settings=None, *args, **kwargs): """ Initialize the voltage source and all its ports. - port_settings: A dictionary of values to give to each port upon creation. """ if port_settings is None: diff --git a/spacq/devices/config.py b/spacq/devices/config.py index 9bcb429..3cee575 100644 --- a/spacq/devices/config.py +++ b/spacq/devices/config.py @@ -13,6 +13,12 @@ def device_tree(): """ Build a device tree from the existing devices. + + Returns + ------- + dict + A dictionary of dictionaries of dictionaries + (manufacturer -> model -> kind -> implementation). """ global cached_tree @@ -66,6 +72,10 @@ class ConnectionError(Exception): class DeviceConfig(object): """ Description for a device. + + Parameters + ---------- + name : str """ address_modes = Enum([ @@ -107,6 +117,10 @@ def __init__(self, name): def __getstate__(self): """ Return a modified dictionary for pickling. + + Returns + ------- + dict """ result = self.__dict__.copy() @@ -120,6 +134,10 @@ def __getstate__(self): def __setstate__(self, dict): """ Revert the changes done by __getstate__. + + Parameters + ---------- + dict : dict """ self.__dict__ = dict @@ -132,12 +150,23 @@ def __setstate__(self, dict): def device(self): """ The connected device object. + + Returns + ------- + AbstractDevice """ return self._device @device.setter def device(self, value): + """ + Set the connected device object. + + Parameters + ---------- + value : AbstractDevice + """ self._device = value self.gui_setup = None @@ -151,11 +180,14 @@ def diff_resources(self, new): """ Compare the resources belonging to 2 DeviceConfig objects. - The result is a tuple of: - resources which appear - resources which change - resources which disappear - where all "resources" are resource labels. + Parameters + ---------- + new : DeviceConfig + + Returns + ------- + tuple of set of str + (appeared, changed, disappeared) where each is a resource label. """ old_labels, new_labels = set(self.resources), set(new.resources) diff --git a/spacq/devices/cryomagnetics/mock/mock_model4g.py b/spacq/devices/cryomagnetics/mock/mock_model4g.py index 9251e1b..dc6520b 100755 --- a/spacq/devices/cryomagnetics/mock/mock_model4g.py +++ b/spacq/devices/cryomagnetics/mock/mock_model4g.py @@ -9,6 +9,13 @@ class MockChannel(object): """ A mock channel for a mock 4G power supply. + + Parameters + ---------- + device : MockModel4G + The mock device that this channel belongs to. + channel : int + The channel number. """ def __init__(self, device, channel, *args, **kwargs): self.mock_state = {} @@ -41,6 +48,12 @@ class MockData(object): It wraps a list that contains N datapoints in min to max, including min and max. Note that it is possible to have max < min. This will merely make the list go in descending order (such as if the 4G was sweeping down). + + Parameters + ---------- + data_min : float + data_max : float + N : int ''' def __init__(self, data_min, data_max, N): @@ -54,7 +67,13 @@ def __init__(self, data_min, data_max, N): self.data_list = [data_min] def GetDatum(self): - + """ + Returns the next datum in the list. + + Returns + ------- + float + """ result = self.data_list[self.index] #once the magnet sweeps to the last value, if one keeps retrieving values, it will stay @@ -75,6 +94,12 @@ class MockTimeData(object): t = 0 <-> data_min t = time_to_max <-> data_max where t is the time since instantiation + + Parameters + ---------- + data_min : float + data_max : float + time_to_max : float ''' def __init__(self, data_min, data_max, time_to_max): @@ -118,6 +143,17 @@ def _reset(self): self.mock_state['active_channel'] = 1 def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + The response to return. + done : bool, optional + True if this is the last message in a sequence. + """ if not done: cmd, args, query = self._split_message(message) diff --git a/spacq/devices/cryomagnetics/model4g.py b/spacq/devices/cryomagnetics/model4g.py index be683ad..9195dc1 100755 --- a/spacq/devices/cryomagnetics/model4g.py +++ b/spacq/devices/cryomagnetics/model4g.py @@ -19,6 +19,13 @@ class Channel(AbstractSubdevice): """ Interface for a channel on the Model4G + + Parameters + ---------- + device : AbstractDevice + The device to which this subdevice belongs. + channel : int + The channel number of this subdevice. """ @@ -83,10 +90,10 @@ def _connected(self): self._imag_target = self.magnet_current.original_value def _wait_for_sweep(self): - ''' + """ This is an internal function that loops until a sweep is complete. This allows some of the virtual features to wait until a sweep is complete before performing other commands. - ''' + """ for i in range(0,2): current_sweep = self.sweep @@ -135,6 +142,10 @@ def decorated(self, *args, **kwargs): def high_limit(self): """ The upper limit on the magnetic current + + Returns + ------- + Quantity """ response = self.device.ask('ulim?') stripped_response = Quantity.from_string(response)[0] @@ -145,6 +156,13 @@ def high_limit(self): @dynamic_converted_quantity_unwrapped('_units') @_set_channel() def high_limit(self,value): + """ + The upper limit on the magnetic current + + Parameters + ---------- + value : Quantity + """ self.device.write('ulim {0}'.format(value)) @property @@ -154,6 +172,10 @@ def high_limit(self,value): def low_limit(self): """ The lower limit on the magnetic current + + Returns + ------- + Quantity """ response = self.device.ask('llim?') stripped_response = Quantity.from_string(response)[0] @@ -164,6 +186,13 @@ def low_limit(self): @dynamic_converted_quantity_unwrapped('_units') @_set_channel() def low_limit(self,value): + """ + The lower limit on the magnetic current + + Parameters + ---------- + value : Quantity + """ self.device.write('llim {0}'.format(value)) @@ -174,6 +203,10 @@ def low_limit(self,value): def magnet_current(self): """ This is the persistent magnet current setting + + Returns + ------- + Quantity """ response = self.device.ask('imag?') stripped_response = Quantity.from_string(response)[0] @@ -185,6 +218,11 @@ def magnet_current(self): def persistent_switch_heater(self): """ The persistent switch heater + + Returns + ------- + str + The persistent switch heater state """ response = float(self.device.ask('pshtr?')) @@ -202,7 +240,15 @@ def persistent_switch_heater(self): @persistent_switch_heater.setter @Synchronized() @_set_channel() - def persistent_switch_heater(self,value): + def persistent_switch_heater(self, value): + """ + The persistent switch heater + + Parameters + ---------- + value : str + The persistent switch heater state + """ if value not in self.allowed_switch_heater: raise ValueError('Invalid heater switch value: {0}'.format(value)) @@ -224,6 +270,10 @@ def persistent_switch_heater(self,value): def power_supply_current(self): """ The power supply output current + + Returns + ------- + Quantity """ response = self.device.ask('iout?') stripped_response = Quantity.from_string(response)[0] @@ -232,10 +282,18 @@ def power_supply_current(self): @quantity_wrapped('A') @Synchronized() @_set_channel() - def ranges(self,range_id): - ''' + def ranges(self, range_id): + """ Used to grab the range for a given range id. - ''' + + Parameters + ---------- + range_id : int + + Returns + ------- + str + """ if range_id != 0: lower = self.device.ask('range? {0}'.format(range_id-1)) else: @@ -252,6 +310,10 @@ def ranges(self,range_id): def rate_0(self): """ A rate for a rate range + + Returns + ------- + Quantity """ return float(self.device.ask('rate? 0')) @@ -260,7 +322,13 @@ def rate_0(self): @Synchronized() @_set_channel() def rate_0(self,value): + """ + A rate for a rate range + Parameters + ---------- + value : Quantity + """ self.device.write('rate 0 {0}'.format(value)) @property @@ -270,6 +338,10 @@ def rate_0(self,value): def rate_1(self): """ A rate for a rate range + + Returns + ------- + Quantity """ return float(self.device.ask('rate? 1')) @@ -278,7 +350,13 @@ def rate_1(self): @Synchronized() @_set_channel() def rate_1(self,value): + """ + A rate for a rate range + Parameters + ---------- + value : Quantity + """ self.device.write('rate 1 {0}'.format(value)) @property @@ -288,6 +366,10 @@ def rate_1(self,value): def rate_2(self): """ A rate for a rate range + + Returns + ------- + Quantity """ return float(self.device.ask('rate? 2')) @@ -296,7 +378,13 @@ def rate_2(self): @Synchronized() @_set_channel() def rate_2(self,value): - + """ + A rate for a rate range + + Parameters + ---------- + value : Quantity + """ self.device.write('rate 2 {0}'.format(value)) @property @@ -306,8 +394,11 @@ def rate_2(self,value): def rate_3(self): """ A rate for a rate range + + Returns + ------- + Quantity """ - return float(self.device.ask('rate? 3')) @rate_3.setter @@ -315,7 +406,13 @@ def rate_3(self): @Synchronized() @_set_channel() def rate_3(self,value): - + """ + A rate for a rate range + + Parameters + ---------- + value : Quantity + """ self.device.write('rate 3 {0}'.format(value)) @property @@ -325,6 +422,10 @@ def rate_3(self,value): def rate_4(self): """ A rate for a rate range + + Returns + ------- + Quantity """ return float(self.device.ask('rate? 4')) @@ -333,7 +434,13 @@ def rate_4(self): @Synchronized() @_set_channel() def rate_4(self,value): + """ + A rate for a rate range + Parameters + ---------- + value : Quantity + """ self.device.write('rate 4 {0}'.format(value)) @property @@ -342,6 +449,11 @@ def rate_4(self,value): def sweep(self): """ The sweeper control. + + Returns + ------- + str + The sweeper control state """ response = str(self.device.ask('sweep?')) return response @@ -350,7 +462,14 @@ def sweep(self): @Synchronized() @_set_channel() def sweep(self,value): - + """ + The sweeper control. + + Parameters + ---------- + value : str + The sweeper control state + """ if value not in self.allowed_sweep: raise ValueError('Invalid sweep value: {0}'.format(value)) @@ -362,6 +481,10 @@ def sweep(self,value): def units(self): """ Get current units of the device. + + Returns + ------- + str """ self.device.active_channel = self.channel @@ -383,6 +506,10 @@ def units(self): def units(self,value): """ Set current units. + + Parameters + ---------- + value : str """ if value not in self.allowed_units: raise ValueError('Invalid units: {0}'.format(value)) @@ -416,6 +543,10 @@ def virt_energysave_mode(self, value): ''' If enabled: after incrementing virt_imag_sweep_to, the magnet will go into persistent mode, and then start a sweep of the power supply current to 0 + + Parameters + ---------- + value : int ''' self._energysave_mode = value @@ -424,16 +555,24 @@ def virt_energysave_mode(self, value): @dynamic_quantity_wrapped('_units') def virt_imag(self): ''' - Getter: Simply returns the magnet current. - Setter: - This wraps virt_iout_sweep_to with current syncing, as well as optional energy saving. + + Returns + ------- + Quantity ''' return self.magnet_current.original_value @virt_imag.setter @dynamic_converted_quantity_unwrapped('_units') def virt_imag(self, value): + """ + This wraps virt_iout_sweep_to with current syncing, as well as optional energy saving. + + Parameters + ---------- + value : Quantity + """ if self.virt_energysave_mode == 4: self.virt_sync_currents = 'start' @@ -465,17 +604,25 @@ def virt_imag(self, value): @property @dynamic_quantity_wrapped('_units') def virt_imag_sweep_to(self): - ''' - Getter: + """ Simply returns the magnet current. - Setter: - This wraps virt_iout_sweep_to with current syncing, as well as optional energy saving. - ''' + + Returns + ------- + Quantity + """ return self._imag_target @virt_imag_sweep_to.setter @dynamic_converted_quantity_unwrapped('_units') def virt_imag_sweep_to(self, value): + """ + This wraps virt_iout_sweep_to with current syncing, as well as optional energy saving. + + Parameters + ---------- + value : Quantity + """ if self.persistent_switch_heater != 'on': self.persistent_switch_heater = 'on' @@ -492,10 +639,11 @@ def virt_imag_sweep_to(self, value): @dynamic_quantity_wrapped('_units') def virt_iout(self): """ - Getter: Simply returns the power supply current. - Setter: - Used to increment the output power supply current using lower level controls. + + Returns + ------- + Quantity Note: power_supply_current is already wrapped with units, so no need to wrap this function. """ @@ -504,6 +652,13 @@ def virt_iout(self): @virt_iout.setter @dynamic_converted_quantity_unwrapped('_units') def virt_iout(self, value): + """ + Used to increment the output power supply current using lower level controls. + + Parameters + ---------- + value : Quantity + """ # determine whether to set the hilim or lolim for increment, then sweep if value == 0: @@ -533,10 +688,11 @@ def virt_iout(self, value): @dynamic_quantity_wrapped('_units') def virt_iout_sweep_to(self): """ - Getter: Simply returns the power supply current. - Setter: - Used to increment the output power supply current using lower level controls. + + Returns + ------- + Quantity Note: power_supply_current is already wrapped with units, so no need to wrap this function. """ @@ -545,6 +701,13 @@ def virt_iout_sweep_to(self): @virt_iout_sweep_to.setter @dynamic_converted_quantity_unwrapped('_units') def virt_iout_sweep_to(self, value): + """ + Used to increment the output power supply current using lower level controls. + + Parameters + ---------- + value : Quantity + """ # determine whether to set the hilim or lolim for increment, then sweep if value == 0: @@ -577,6 +740,10 @@ def virt_sweep_sleep(self): """ Debugging purposes, although potentially the basis for a feature in the future. Changes the sleep period in _wait_for_sweep after detecting the sweep is done. + + Returns + ------- + Quantity """ return self._sweep_sleep @@ -591,6 +758,11 @@ def virt_sweep_sleep(self,value): def virt_sync_currents(self): """ Used to sync the currents. Note this is a virtual feature not present in the actual device. + + Returns + ------- + str + Either 'synced' or 'not synced' """ if self.magnet_current == self.power_supply_current: return 'synced' @@ -613,6 +785,9 @@ def virt_heater_wait_mode(self): @virt_heater_wait_mode.setter def virt_heater_wait_mode(self, value): + """ + This is a virtual feature that allows the user to wait for the heaters to warm up before continuing. + """ if value not in self.allowed_heater_wait_mode: raise ValueError('Invalid heater wait mode value: {0}'.format(value)) @@ -728,6 +903,10 @@ def reset(self): def active_channel(self): """ The active device channel. + + Returns + ------- + int """ return float(self.ask('chan?')) @@ -744,6 +923,11 @@ def active_channel(self,value): def virt_both_persistent_switch_heaters(self): """ The heaters on both channels. Control over both is desirable in order to avoid eddy currents in the system. + + Returns + ------- + str + The heaters state """ heaters = [channel.persistent_switch_heater for channel in self.channels[1:]] @@ -757,7 +941,14 @@ def virt_both_persistent_switch_heaters(self): @virt_both_persistent_switch_heaters.setter @Synchronized() - def virt_both_persistent_switch_heaters(self,value): + def virt_both_persistent_switch_heaters(self, value): + """ + Set the heaters on both channels. + + Parameters + ---------- + value : str + """ if value not in self.allowed_both_heaters: raise ValueError('Invalid heater switch value: {0}'.format(value)) @@ -770,6 +961,10 @@ def virt_both_persistent_switch_heaters(self,value): def virt_both_units(self): """ Get current units of both device's channels. + + Returns + ------- + str """ both_units = [channel.units for channel in self.channels[1:]] all_units_same = all(both_units[0] == units for units in both_units) @@ -782,9 +977,13 @@ def virt_both_units(self): @virt_both_units.setter - def virt_both_units(self,value): + def virt_both_units(self, value): """ Set current units on both channels. + + Parameters + ---------- + value : str """ if value not in self.allowed_both_units: raise ValueError('Invalid units: {0}'.format(value)) diff --git a/spacq/devices/iqc/ch4_voltage_source.py b/spacq/devices/iqc/ch4_voltage_source.py index b9d7fbf..a38e055 100644 --- a/spacq/devices/iqc/ch4_voltage_source.py +++ b/spacq/devices/iqc/ch4_voltage_source.py @@ -19,6 +19,24 @@ class Port(AbstractSubdevice): """ An output port on the voltage source. + + Parameters + ---------- + device : ch4VoltageSource + num : int + The index of this port. + resolution : int, optional + How many bits the output value contains. + apply_settings : bool, optional + Whether to automatically apply all the settings. + min_value : float, optional + max_value : float, optional + adaptive_filtering : bool, optional + calibrate_connected : bool, optional + Do not disconnect output while calibrating. + fast_settling : bool, optional + freq : int, optional + Clock rate in kHz. """ # Since there is no way to determine whether calibration has completed, @@ -74,17 +92,6 @@ def __init__(self, device, num, resolution=20, apply_settings=True, min_value=-1 fast_settling=True, freq=100, *args, **kwargs): """ Initialize the output port. - - device: The ch4VoltageSource to which this Port belongs. - num: The index of this port. - resolution: How many bits the output value contains. - apply_settings: Whether to automatically apply all the settings. - min_value: Smallest value the port can produce. - max_value: Largest value the port can produce. - adaptive_filtering: Enable adaptive filtering. - calibrate_connected: Do not disconnect output while calibrating. - fast_settling: Enable fast settling. - freq: Clock rate in kHz. """ AbstractSubdevice.__init__(self, device, *args, **kwargs) @@ -105,6 +112,14 @@ def __init__(self, device, num, resolution=20, apply_settings=True, min_value=-1 def calculate_voltage(self, voltage): """ Determine the value corresponding to the given voltage. + + Parameters + ---------- + voltage: The voltage to convert, as a quantity in V. + + Returns + ------- + int """ try: @@ -138,6 +153,10 @@ def write_to_dac(self, message): my lack of time & desire to properly reverse engineer the ni845x DLL If the conversation does not go according to plan, bails out with an AssertionError! + + Parameters + ---------- + message: The message to send, as a string of hexadecimal digits. """ message_length = BinaryEncoder.length(message) @@ -169,7 +188,9 @@ def apply_settings(self, calibrate=False): """ Apply the settings for the DAC on this port. - calibrate: Run self-calibration on this port as well. + Parameters + ---------- + calibrate: Whether to run self-calibration on this port as well. Note: If self-calibrating, it is essential to wait the calibration_delay after this method returns. """ @@ -194,6 +215,10 @@ def voltage(self): def voltage(self, value): """ Set the voltage on this port, as a quantity in V. + + Parameters + ---------- + value: The voltage to set. """ # Left-align the bits within the value: @@ -211,11 +236,19 @@ def autotune(self, voltage_resource, min_value=None, max_value=None, final_value """ Take some measured data and solve for the gain and offset. - voltage_resource: A resource which provides the realtime measured data for this port. - min_value: Smallest value to take into account. - max_value: Largest value to take into account. - final_value: Value to set port to after all measurements are taken. - set_result: Whether to apply the resulting gain and offset. + Parameters + ---------- + voltage_resource: resource + A resource which provides the realtime measured data for this port. + min_value: int + max_value: int + final_value: int + set_result: bool + Whether to apply the resulting gain and offset. + + Returns + ------- + (float, float) """ self.device.status.append('Autotuning port {0}'.format(self.num)) @@ -268,6 +301,11 @@ class ch4VoltageSource(AbstractDevice): Interface for the custom voltage source. It uses several TI DAC1220 chips and an NI USB-8451 to interface with them over SPI. + + Parameters + ---------- + port_settings: dict, optional + A dictionary of values to give to each port upon creation. """ @property @@ -294,8 +332,6 @@ def _setup(self): def __init__(self, port_settings=None, *args, **kwargs): """ Initialize the voltage source and all its ports. - - port_settings: A dictionary of values to give to each port upon creation. """ if port_settings is None: @@ -309,6 +345,15 @@ def __init__(self, port_settings=None, *args, **kwargs): def ask_encoded(self, msg, assertion=None): """ Encode and write the message; then read and decode the answer. + + Parameters + ---------- + msg : str + assertion : str, optional + + Returns + ------- + str """ self.write(BinaryEncoder.encode(msg)) diff --git a/spacq/devices/iqc/ch6_voltage_source.py b/spacq/devices/iqc/ch6_voltage_source.py index d8995f3..08aad66 100644 --- a/spacq/devices/iqc/ch6_voltage_source.py +++ b/spacq/devices/iqc/ch6_voltage_source.py @@ -21,6 +21,23 @@ class Port(AbstractSubdevice): """ An output port on the voltage source. + + Parameters + ---------- + device: ch6VoltageSource + num: int + The index of this port. + max_value: float + resolution: int + How many bits the output value contains. + apply_settings: bool, optional + Whether to automatically apply all the settings. + adaptive_filtering: bool, optional + calibrate_connected: bool, optional + Do not disconnect output while calibrating. + fast_settling: bool, optional + freq: int + Clock rate in kHz. """ # Since there is no way to determine whether calibration has completed, @@ -33,6 +50,14 @@ def format_for_dac(msg): Perform some formatting to make the device happy: flip all the bits in the message pad messages until their length in bytes is a multiple of 4 + + Parameters + ---------- + msg: string of hex digits + + Returns + ------- + string of hex digits """ log.debug('Formatting for DAC: {0}'.format(msg)) @@ -74,17 +99,6 @@ def __init__(self, device, num, max_value, resolution=20, apply_settings=True, a fast_settling=True, freq=100, *args, **kwargs): """ Initialize the output port. - - device: The ch6VoltageSource to which this Port belongs. - num: The index of this port. - resolution: How many bits the output value contains. - apply_settings: Whether to automatically apply all the settings. - min_value: Smallest value the port can produce. - max_value: Largest value the port can produce. - adaptive_filtering: Enable adaptive filtering. - calibrate_connected: Do not disconnect output while calibrating. - fast_settling: Enable fast settling. - freq: Clock rate in kHz. """ AbstractSubdevice.__init__(self, device, *args, **kwargs) @@ -105,6 +119,14 @@ def __init__(self, device, num, max_value, resolution=20, apply_settings=True, a def calculate_voltage(self, voltage): """ Determine the value corresponding to the given voltage. + + Parameters + ---------- + voltage: float + + Returns + ------- + int """ try: @@ -137,6 +159,10 @@ def write_to_dac(self, message): my lack of time & desire to properly reverse engineer the ni845x DLL If the conversation does not go according to plan, bails out with an AssertionError! + + Parameters + ---------- + message: string of hex digits """ message_length = BinaryEncoder.length(message) @@ -165,7 +191,9 @@ def apply_settings(self, calibrate=False): """ Apply the settings for the DAC on this port. - calibrate: Run self-calibration on this port as well. + Parameters + ---------- + calibrate: Whether to run self-calibration on this port as well. Note: If self-calibrating, it is essential to wait the calibration_delay after this method returns. """ @@ -190,6 +218,10 @@ def voltage(self): def voltage(self, value): """ Set the voltage on this port, as a quantity in V. + + Parameters + ---------- + value: float """ # Left-align the bits within the value: @@ -206,11 +238,15 @@ def autotune(self, voltage_resource, min_value=None, max_value=None, final_value """ Take some measured data and solve for the gain and offset. - voltage_resource: A resource which provides the realtime measured data for this port. - min_value: Smallest value to take into account. - max_value: Largest value to take into account. - final_value: Value to set port to after all measurements are taken. - set_result: Whether to apply the resulting gain and offset. + Parameters + ---------- + voltage_resource: resource + A resource which provides the realtime measured data for this port. + min_value: float, optional + max_value: float, optional + final_value: float, optional + set_result: bool, optional + Whether to apply the resulting gain and offset. """ self.device.status.append('Autotuning port {0}'.format(self.num)) @@ -263,6 +299,11 @@ class ch6VoltageSource(AbstractDevice): Interface for the custom voltage source. It uses several TI DAC1220 chips and an NI USB-8451 to interface with them over SPI. + + Parameters + ---------- + port_settings: dict, optional + Settings to pass to each port. """ @property @@ -291,8 +332,6 @@ def _setup(self): def __init__(self, port_settings=None, *args, **kwargs): """ Initialize the voltage source and all its ports. - - port_settings: A dictionary of values to give to each port upon creation. """ if port_settings is None: @@ -306,6 +345,11 @@ def __init__(self, port_settings=None, *args, **kwargs): def ask_encoded(self, msg, assertion=None): """ Encode and write the message; then read and decode the answer. + + Parameters + ---------- + msg: string of hex digits + assertion: string of hex digits, optional """ self.write(BinaryEncoder.encode(msg)) diff --git a/spacq/devices/iqc/mock/mock_ch4_voltage_source.py b/spacq/devices/iqc/mock/mock_ch4_voltage_source.py index 073c5ff..8ef0f86 100644 --- a/spacq/devices/iqc/mock/mock_ch4_voltage_source.py +++ b/spacq/devices/iqc/mock/mock_ch4_voltage_source.py @@ -48,6 +48,17 @@ def _reset(self): self.mock_state['ports'] = [MockPort() for _ in range(6)] def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + The expected result. + done : bool, optional + Whether the message is the last in a sequence. + """ if done: MockAbstractDevice.write(self, message, result, done) diff --git a/spacq/devices/iqc/mock/mock_ch6_voltage_source.py b/spacq/devices/iqc/mock/mock_ch6_voltage_source.py index c992abc..1f42355 100644 --- a/spacq/devices/iqc/mock/mock_ch6_voltage_source.py +++ b/spacq/devices/iqc/mock/mock_ch6_voltage_source.py @@ -48,6 +48,17 @@ def _reset(self): self.mock_state['ports'] = [MockPort() for _ in range(6)] def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + The expected response. + done : bool, optional + Whether the message is the last in a series. + """ if done: MockAbstractDevice.write(self, message, result, done) diff --git a/spacq/devices/iqc/mock/mock_voltage_source.py b/spacq/devices/iqc/mock/mock_voltage_source.py index 80232e7..2266b49 100644 --- a/spacq/devices/iqc/mock/mock_voltage_source.py +++ b/spacq/devices/iqc/mock/mock_voltage_source.py @@ -48,6 +48,17 @@ def _reset(self): self.mock_state['ports'] = [MockPort() for _ in range(16)] def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + The expected response. + done : bool, optional + Whether the message is the last in a series. + """ if done: MockAbstractDevice.write(self, message, result, done) diff --git a/spacq/devices/iqc/voltage_source.py b/spacq/devices/iqc/voltage_source.py index c871bdf..230351c 100644 --- a/spacq/devices/iqc/voltage_source.py +++ b/spacq/devices/iqc/voltage_source.py @@ -19,6 +19,23 @@ class Port(AbstractSubdevice): """ An output port on the voltage source. + + Parameters + ---------- + device : VoltageSource + num : int + The index of this port. + max_value : float + resolution : int + How many bits the output value contains. + apply_settings : bool, optional + Whether to automatically apply all the settings. + adaptive_filtering : bool, optional + calibrate_connected : bool, optional + Do not disconnect output while calibrating. + fast_settling : bool, optional + freq : int + Clock rate in kHz. """ # Since there is no way to determine whether calibration has completed, @@ -31,6 +48,14 @@ def format_for_dac(msg): Perform some formatting to make the device happy: flip all the bits in the message pad messages until their length in bytes is a multiple of 4 + + Parameters + ---------- + msg : str + + Returns + ------- + str """ log.debug('Formatting for DAC: {0}'.format(msg)) @@ -73,17 +98,6 @@ def __init__(self, device, num, max_value, resolution=20, apply_settings=True, a fast_settling=True, freq=100, *args, **kwargs): """ Initialize the output port. - - device: The VoltageSource to which this Port belongs. - num: The index of this port. - resolution: How many bits the output value contains. - apply_settings: Whether to automatically apply all the settings. - min_value: Smallest value the port can produce. - max_value: Largest value the port can produce. - adaptive_filtering: Enable adaptive filtering. - calibrate_connected: Do not disconnect output while calibrating. - fast_settling: Enable fast settling. - freq: Clock rate in kHz. """ AbstractSubdevice.__init__(self, device, *args, **kwargs) @@ -104,6 +118,14 @@ def __init__(self, device, num, max_value, resolution=20, apply_settings=True, a def calculate_voltage(self, voltage): """ Determine the value corresponding to the given voltage. + + Parameters + ---------- + voltage : float + + Returns + ------- + int """ try: @@ -137,6 +159,10 @@ def write_to_dac(self, message): my lack of time & desire to properly reverse engineer the ni845x DLL If the conversation does not go according to plan, bails out with an AssertionError! + + Parameters + ---------- + message : str """ message_length = BinaryEncoder.length(message) @@ -171,7 +197,9 @@ def apply_settings(self, calibrate=False): """ Apply the settings for the DAC on this port. - calibrate: Run self-calibration on this port as well. + Parameters + ---------- + calibrate: Whether to run self-calibration on this port as well. Note: If self-calibrating, it is essential to wait the calibration_delay after this method returns. """ @@ -196,6 +224,10 @@ def voltage(self): def voltage(self, value): """ Set the voltage on this port, as a quantity in V. + + Parameters + ---------- + value : float """ # Left-align the bits within the value: @@ -213,11 +245,19 @@ def autotune(self, voltage_resource, min_value=None, max_value=None, final_value """ Take some measured data and solve for the gain and offset. - voltage_resource: A resource which provides the realtime measured data for this port. - min_value: Smallest value to take into account. - max_value: Largest value to take into account. - final_value: Value to set port to after all measurements are taken. - set_result: Whether to apply the resulting gain and offset. + Parameters + ---------- + voltage_resource: resource + A resource which provides the realtime measured data for this port. + min_value: float, optional + max_value: float, optional + final_value: float, optional + set_result: bool, optional + Whether to apply the resulting gain and offset. + + Returns + ------- + (float, float) """ self.device.status.append('Autotuning port {0}'.format(self.num)) @@ -270,6 +310,11 @@ class VoltageSource(AbstractDevice): Interface for the custom voltage source. It uses several TI DAC1220 chips and an NI USB-8451 to interface with them over SPI. + + Parameters + ---------- + port_settings : dict, optional + A dictionary of values to give to each port upon creation. """ @property @@ -301,8 +346,6 @@ def _setup(self): def __init__(self, port_settings=None, *args, **kwargs): """ Initialize the voltage source and all its ports. - - port_settings: A dictionary of values to give to each port upon creation. """ if port_settings is None: @@ -316,6 +359,12 @@ def __init__(self, port_settings=None, *args, **kwargs): def ask_encoded(self, msg, assertion=None): """ Encode and write the message; then read and decode the answer. + + Parameters + ---------- + msg : str + assertion : str, optional + The expected response. """ msg_byte = bytes.fromhex(msg) diff --git a/spacq/devices/keithley/mock/mock_sourceMeter2401.py b/spacq/devices/keithley/mock/mock_sourceMeter2401.py index 773ff02..dc1d6b6 100644 --- a/spacq/devices/keithley/mock/mock_sourceMeter2401.py +++ b/spacq/devices/keithley/mock/mock_sourceMeter2401.py @@ -22,6 +22,17 @@ def _reset(self): self.mock_state['setting'] = 'default value' def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + The result of the write. + done : bool, optional + Whether the write is done. + """ if not done: cmd, args, query = self._split_message(message) diff --git a/spacq/devices/keithley/mock/mock_sourceMeter2450.py b/spacq/devices/keithley/mock/mock_sourceMeter2450.py index e5ceec9..13287d6 100644 --- a/spacq/devices/keithley/mock/mock_sourceMeter2450.py +++ b/spacq/devices/keithley/mock/mock_sourceMeter2450.py @@ -22,6 +22,17 @@ def _reset(self): self.mock_state['setting'] = 'default value' def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + The result to return. + done : bool, optional + Whether the command is done. + """ if not done: cmd, args, query = self._split_message(message) diff --git a/spacq/devices/keithley/mock/mock_voltagesource230.py b/spacq/devices/keithley/mock/mock_voltagesource230.py index a1fbd9a..39fa167 100644 --- a/spacq/devices/keithley/mock/mock_voltagesource230.py +++ b/spacq/devices/keithley/mock/mock_voltagesource230.py @@ -22,6 +22,17 @@ def _reset(self): self.mock_state['setting'] = 'default value' def write(self, message, result=None, done=False): + """ + Write to the mock device. + + Parameters + ---------- + message : str + result : str, optional + The result to return. + done : bool, optional + Whether the command is done. + """ if not done: cmd, args, query = self._split_message(message) diff --git a/spacq/devices/keithley/sourceMeter2401.py b/spacq/devices/keithley/sourceMeter2401.py index f8a266b..74db5c9 100644 --- a/spacq/devices/keithley/sourceMeter2401.py +++ b/spacq/devices/keithley/sourceMeter2401.py @@ -62,12 +62,18 @@ def reset(self): """ Reset the device to its default state. """ - log.info('Resetting "{0}".'.format(self.name)) self.write('*rst') @property def output(self): + """ + The output on/off state. + + Returns + ------- + {'on', 'off'} + """ # Coded setting of the output on/off (1 = on, 0 = off) result = self.ask('OUTP?') if result == '0': @@ -79,6 +85,13 @@ def output(self): @output.setter def output(self, value): + """ + Turn the output on or off. + + Parameters + ---------- + value : {'on', 'off'} + """ if value not in self.allowedOutput: raise ValueError('Invalid Output State: {0}'.format(value)) @@ -94,6 +107,13 @@ def output(self, value): @property @quantity_wrapped('V') def voltageIn(self): + """ + The voltage measured at the input. + + Returns + ------- + float + """ if self.currOutputState: outString = self.ask('READ?').decode() # The output returns a 5 number string, first number is voltage, second is current, third is res @@ -104,6 +124,13 @@ def voltageIn(self): @property @quantity_wrapped('A') def currentIn(self): + """ + The current measured at the input. + + Returns + ------- + float + """ if self.currOutputState: outString = self.ask('READ?').decode() return float(outString.split(',')[1]) @@ -113,6 +140,13 @@ def currentIn(self): @property @quantity_wrapped('V') def voltageOut(self): + """ + The voltage applied at the output. + + Returns + ------- + float + """ if self.currOutputState: return float(self.ask('SOUR:VOLT?')) else: @@ -121,6 +155,13 @@ def voltageOut(self): @voltageOut.setter @quantity_unwrapped('V') def voltageOut(self, value): + """ + Set the voltage applied at the output. + + Parameters + ---------- + voltage : float + """ self.write('SOUR:FUNC VOLT') self.write('SOUR:VOLT:LEV {0}'.format(value)) self.currentOutputVoltage = value @@ -128,6 +169,13 @@ def voltageOut(self, value): @property @quantity_wrapped('A') def currentOut(self): + """ + The current applied at the output. + + Returns + ------- + float + """ if self.currOutputState: return float(self.ask('SOUR:CURR?')) else: @@ -136,6 +184,13 @@ def currentOut(self): @currentOut.setter @quantity_unwrapped('A') def currentOut(self, value): + """ + Set the current applied at the output. + + Parameters + ---------- + current : float + """ #self.write('SOUR:FUNC CURR') self.write('SOUR:CURR:LEV {0}'.format(value)) self.currentOutputCurrent = value diff --git a/spacq/devices/keithley/sourceMeter2450.py b/spacq/devices/keithley/sourceMeter2450.py index c7dfad8..ef4b1b1 100644 --- a/spacq/devices/keithley/sourceMeter2450.py +++ b/spacq/devices/keithley/sourceMeter2450.py @@ -58,32 +58,74 @@ def reset(self): @property @quantity_wrapped('V') def voltageIn(self): + """ + The voltage measured at the input terminals. + + Returns + ------- + float + """ return float(self.ask('MEAS:VOLT?')) @property @quantity_wrapped('A') def currentIn(self): + """ + The current measured at the input terminals. + + Returns + ------- + float + """ return float(self.ask('MEAS:CURR?')) @property @quantity_wrapped('V') def voltageOut(self): + """ + The voltage applied at the output terminals. + + Returns + ------- + float + """ return self.currentOutputVoltage @voltageOut.setter @quantity_unwrapped('V') def voltageOut(self,value): + """ + The voltage applied at the output terminals. + + Returns + ------- + float + """ self.write('SOUR:VOLT {0}'.format(value)) self.currentOutputVoltage = value @property @quantity_wrapped('A') def currentOut(self): + """ + The current applied at the output terminals. + + Returns + ------- + float + """ return self.currentOutputCurrent @currentOut.setter @quantity_unwrapped('A') def currentOut(self,value): + """ + The current applied at the output terminals. + + Returns + ------- + float + """ self.write('SOUR:CURR {0}'.format(value)) self.currentOutputCurrent = value diff --git a/spacq/devices/keithley/voltagesource230.py b/spacq/devices/keithley/voltagesource230.py index e1d9c80..15e8c37 100644 --- a/spacq/devices/keithley/voltagesource230.py +++ b/spacq/devices/keithley/voltagesource230.py @@ -73,6 +73,14 @@ def reset(self): def calculate_voltage(self, voltage): """ Determine the value corresponding to the given voltage. + + Parameters + ---------- + voltage : float + + Returns + ------- + float """ try: @@ -91,6 +99,10 @@ def calculate_voltage(self, voltage): def set_voltage(self, voltage): """ Set the voltage on this port, as a quantity in V. + + Parameters + ---------- + float """ # Left-align the bits within the value: @@ -109,7 +121,11 @@ def set_voltage(self, voltage): @property def I_limit(self): """ - The current limit (in mA) + Return the current limit (in mA) + + Returns + ------- + float """ # If no I limit has been set, use the 2mA default if not hasattr(self, 'currentILimit'): @@ -120,6 +136,13 @@ def I_limit(self): @I_limit.setter def I_limit(self, value): + """ + Set the current limit (in mA) + + Parameters + ---------- + value : float + """ if value not in self.allowed_I_limit: raise ValueError('Invalid I Limit value: {0}'.format(value)) @@ -134,7 +157,11 @@ def I_limit(self, value): @property def dwell_time(self): """ - The dwell time of the vsrc + Return the dwell time of the vsrc + + Returns + ------- + float """ # If no dwell time has been set, use 10ms default if not hasattr(self, 'dwelltime'): @@ -143,6 +170,13 @@ def dwell_time(self): @dwell_time.setter def dwell_time(self, value): + """ + Set the dwell time of the vsrc + + Parameters + ---------- + value : float + """ if value < self.dwellMin or value > self.dwellMax: raise ValueError('Dwell time must be within [{0}, {1}]. Given: {2}.'.format(self.dwellMin, self.dwellMax, value)) self.dwelltime = value diff --git a/spacq/devices/lakeshore/mock/mock_model218.py b/spacq/devices/lakeshore/mock/mock_model218.py index 0616a1d..5639485 100644 --- a/spacq/devices/lakeshore/mock/mock_model218.py +++ b/spacq/devices/lakeshore/mock/mock_model218.py @@ -25,6 +25,17 @@ def _reset(self): pass def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + What to return when the message is a query. + done : bool, optional + Whether the message is complete. + """ if not done: cmd, args, query = self._split_message(message) diff --git a/spacq/devices/lakeshore/mock/mock_tc335.py b/spacq/devices/lakeshore/mock/mock_tc335.py index aeffed3..e6ea76a 100644 --- a/spacq/devices/lakeshore/mock/mock_tc335.py +++ b/spacq/devices/lakeshore/mock/mock_tc335.py @@ -26,6 +26,17 @@ def _reset(self): pass def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + What to return when the message is a query. + done : bool, optional + Whether the message is complete. + """ if not done: cmd, args, query = self._split_message(message) diff --git a/spacq/devices/lakeshore/mock/mock_tc335_old.py b/spacq/devices/lakeshore/mock/mock_tc335_old.py index 26f999a..c3a8865 100644 --- a/spacq/devices/lakeshore/mock/mock_tc335_old.py +++ b/spacq/devices/lakeshore/mock/mock_tc335_old.py @@ -25,6 +25,17 @@ def _reset(self): pass def write(self, message, result=None, done=False): + """ + Write a message to the device. + + Parameters + ---------- + message : str + result : str, optional + What to return when the message is a query. + done : bool, optional + Whether the message is complete. + """ if not done: cmd, args, query = self._split_message(message) diff --git a/spacq/devices/lakeshore/model218.py b/spacq/devices/lakeshore/model218.py index 50a34ad..37df50f 100644 --- a/spacq/devices/lakeshore/model218.py +++ b/spacq/devices/lakeshore/model218.py @@ -44,6 +44,13 @@ def reset(self): @quantity_wrapped('K') @Synchronized() def temperature1(self): + """ + Return the temperature of channel 1 in Kelvin. + + Returns + ------- + float + """ return float(self.ask('krdg? 1')) @@ -51,42 +58,91 @@ def temperature1(self): @quantity_wrapped('K') @Synchronized() def temperature2(self): + """ + Return the temperature of channel 2 in Kelvin. + + Returns + ------- + float + """ return float(self.ask('krdg? 2')) @property @quantity_wrapped('K') @Synchronized() def temperature3(self): + """ + Return the temperature of channel 3 in Kelvin. + + Returns + ------- + float + """ return float(self.ask('krdg? 3')) @property @quantity_wrapped('K') @Synchronized() def temperature4(self): + """ + Return the temperature of channel 4 in Kelvin. + + Returns + ------- + float + """ return float(self.ask('krdg? 4')) @property @quantity_wrapped('K') @Synchronized() def temperature5(self): + """ + Return the temperature of channel 5 in Kelvin. + + Returns + ------- + float + """ return float(self.ask('krdg? 5')) @property @quantity_wrapped('K') @Synchronized() def temperature6(self): + """ + Return the temperature of channel 6 in Kelvin. + + Returns + ------- + float + """ return float(self.ask('krdg? 6')) @property @quantity_wrapped('K') @Synchronized() def temperature7(self): + """ + Return the temperature of channel 7 in Kelvin. + + Returns + ------- + float + """ return float(self.ask('krdg? 7')) @property @quantity_wrapped('K') @Synchronized() def temperature8(self): + """ + Return the temperature of channel 8 in Kelvin. + + Returns + ------- + float + """ return float(self.ask('krdg? 8')) name = 'Model 218 Temperature Monitor' diff --git a/spacq/devices/lakeshore/tc335.py b/spacq/devices/lakeshore/tc335.py index 95a9c0f..193c8ef 100644 --- a/spacq/devices/lakeshore/tc335.py +++ b/spacq/devices/lakeshore/tc335.py @@ -66,6 +66,10 @@ def reset(self): def temperature(self): """ The value measured by the device, as a quantity in K. + + Returns + ------- + temperature : float """ self.status.append('Taking reading') @@ -91,6 +95,10 @@ def temperature(self): def powerA(self): """ The value measured by the device, as a quantity in %. + + Returns + ------- + power : float """ return float(self.ask('HTR? 1')) @@ -106,11 +114,25 @@ def powerA(self): @property @quantity_wrapped('K') def setPointA(self): + """ + Returns the setpoint of channel A in Kelvin. + + Returns + ------- + setPoint : float + """ return float(self.ask('SETP? 1')) @setPointA.setter @quantity_unwrapped('K') def setPointA(self, value): + """ + Sets the setpoint of channel A in Kelvin. + + Parameters + ---------- + setPoint : float + """ self.write('SETP 1,{0}'.format(value)) self.currentSetPointA = value @@ -127,12 +149,26 @@ def setPointA(self, value): @property def rangeA(self): + """ + Returns the range of channel A. + + Returns + ------- + range : string + """ value = int(self.ask('RANGE? 1')) reverse_dict = {0:'Off',1:'Low',2:'Medium',3:'High'} return reverse_dict[value] @rangeA.setter def rangeA(self, value): + """ + Sets the range of channel A. + + Parameters + ---------- + range : string + """ #if value not in self.allowed_ranges: # raise ValueError('Invalid rangeA value: {0}'.format(value)) diff --git a/spacq/devices/lakeshore/tc335_old.py b/spacq/devices/lakeshore/tc335_old.py index cb0fbf9..ed32249 100644 --- a/spacq/devices/lakeshore/tc335_old.py +++ b/spacq/devices/lakeshore/tc335_old.py @@ -51,6 +51,10 @@ def reset(self): def temperature(self): """ The value measured by the device, as a quantity in V. + + Returns + ------- + temperature : float """ self.status.append('Taking reading') diff --git a/spacq/devices/mock/mock_abstract_device.py b/spacq/devices/mock/mock_abstract_device.py index bd391e8..b34e87e 100644 --- a/spacq/devices/mock/mock_abstract_device.py +++ b/spacq/devices/mock/mock_abstract_device.py @@ -11,6 +11,11 @@ class MockAbstractDevice(AbstractDevice): """ A class for controlling fake devices. + + Parameters + ---------- + autoconnect : bool, optional + Whether to connect automatically. """ output = None @@ -19,6 +24,16 @@ class MockAbstractDevice(AbstractDevice): def _split_message(message): """ Split a message into usable components. + + Parameters + ---------- + message : str + + Returns + ------- + list of str + str + bool """ message = message.split(None, 1) @@ -83,6 +98,10 @@ def multi_command_start(self): def multi_command_stop(self): """ Return buffered responses. + + Returns + ------- + list of str """ responses = self.multi_command_responses @@ -93,6 +112,14 @@ def multi_command_stop(self): def write(self, message, result=None, done=False): """ Act on what is being written. + + Parameters + ---------- + message : str + result : str, optional + What to return when the message is a query. + done : bool, optional + Whether the message is complete. """ log.debug('Writing to device: {0!r}'.format(message)) @@ -122,6 +149,10 @@ def write(self, message, result=None, done=False): def read_raw(self, **kwargs): """ Return the result of the last write operation. + + Returns + ------- + str """ log.debug('Read from device: {0!r}'.format(self.output)) @@ -131,6 +162,10 @@ def read_raw(self, **kwargs): def ask(self, *args, **kwargs): """ Ask, but possibly buffer the answer. + + Returns + ------- + str """ result = AbstractDevice.ask(self, *args, **kwargs) diff --git a/spacq/devices/oxford/ips120_10.py b/spacq/devices/oxford/ips120_10.py index a3d9dfd..54542d1 100644 --- a/spacq/devices/oxford/ips120_10.py +++ b/spacq/devices/oxford/ips120_10.py @@ -70,6 +70,10 @@ def write(self, message): def device_status(self): """ All the status information for the device. + + Returns + ------- + Status """ result = self.ask('X') @@ -89,6 +93,10 @@ def device_status(self): def activity(self): """ What the device is currently up to. + + Returns + ------- + str """ return self.activities[self.device_status.activity] @@ -101,12 +109,23 @@ def activity(self, value): def heater_on(self): """ Whether the heater is enabled. + + Returns + ------- + bool """ return bool(self.device_status.heater & 1) @heater_on.setter def heater_on(self, value): + """ + Change the heater state. + + Parameters + ---------- + value : float + """ self.status.append('Turning heater o{0}'.format('n' if value else 'ff')) try: @@ -122,12 +141,23 @@ def heater_on(self, value): def perma_hot(self): """ Whether the heater should always remain on. + + Returns + ------- + bool """ return self._perma_hot @perma_hot.setter def perma_hot(self, value): + """ + Set whether the heater should always remain on. + + Parameters + ---------- + value : bool + """ self._perma_hot = value @property @@ -136,6 +166,10 @@ def perma_hot(self, value): def sweep_rate(self): """ The rate of the field sweep, as a quantity in T/s. + + Returns + ------- + float """ return float(self.ask('R9')[1:]) @@ -143,6 +177,13 @@ def sweep_rate(self): @sweep_rate.setter @quantity_unwrapped('T.s-1', 60) def sweep_rate(self, value): + """ + Set the rate of the field sweep. + + Parameters + ---------- + value : float + """ if value <= 0: raise ValueError('Sweep rate must be positive, not {0}.'.format(value)) @@ -153,6 +194,10 @@ def sweep_rate(self, value): def persistent_field(self): """ The output field when the heater was last disabled, as a quantity in T. + + Returns + ------- + float """ return float(self.ask('R18')[1:]) @@ -162,6 +207,10 @@ def persistent_field(self): def output_field(self): """ The actual field due to the output current in T. + + Returns + ------- + float """ return float(self.ask('R7')[1:]) @@ -171,6 +220,10 @@ def output_field(self): def set_point(self): """ The set point, as a quantity in T. + + Returns + ------- + float """ return float(self.ask('R8')[1:]) @@ -178,12 +231,23 @@ def set_point(self): @set_point.setter @quantity_unwrapped('T') def set_point(self, value): + """ + Set the set point. + + Parameters + ---------- + float + """ self.write('$J{0}'.format(value)) @property def field(self): """ The magnetic field, as a quantity in T. + + Returns + ------- + float """ return self.output_field @@ -191,6 +255,10 @@ def field(self): def set_field(self, value): """ Go through all the steps for setting the output field. + + Parameters + ---------- + float """ if self.output_field == value: @@ -220,6 +288,13 @@ def set_field(self, value): @field.setter @Synchronized() def field(self, value): + """ + Set the magnetic field. + + Parameters + ---------- + value : float + """ status = self.device_status assert status.system_status == 0, 'System status: {0}'.format(status.system_status) assert status.limits == 0, 'Limits: {0}'.format(status.limits) diff --git a/spacq/devices/rohde_schwarz/smf100a.py b/spacq/devices/rohde_schwarz/smf100a.py index 9a6df8c..3db6a9b 100644 --- a/spacq/devices/rohde_schwarz/smf100a.py +++ b/spacq/devices/rohde_schwarz/smf100a.py @@ -51,12 +51,23 @@ def reset(self): def enabled(self): """ Whether the RF output is enabled. + + Returns + ------- + bool """ return bool(int(self.ask('output:state?'))) @enabled.setter def enabled(self, value): + """ + Set whether the RF output is enabled. + + Parameters + ---------- + value : bool + """ self.write('output:state {0}'.format(int(value))) @property @@ -64,6 +75,10 @@ def enabled(self, value): def power(self): """ The RF output power, as a quantity in V. + + Returns + ------- + float """ return float(self.ask('source:power:power?')) @@ -71,6 +86,13 @@ def power(self): @power.setter @quantity_unwrapped('V') def power(self, value): + """ + Set the RF output power. + + Parameters + ---------- + value : float + """ if value < self.min_power or value > self.max_power: raise ValueError('Value {0} not within the allowed bounds: {1} to {2}'.format(value, self.min_power, self.max_power)) @@ -82,6 +104,10 @@ def power(self, value): def frequency(self): """ The RF output frequency, as a quantity in Hz. + + Returns + ------- + float """ return float(self.ask('source:frequency:cw?')) @@ -89,6 +115,13 @@ def frequency(self): @frequency.setter @quantity_unwrapped('Hz') def frequency(self, value): + """ + Set the RF output frequency. + + Parameters + ---------- + value : float + """ if value < self.min_freq or value > self.max_freq: raise ValueError('Value {0} not within the allowed bounds: {1} to {2}'.format(value, self.min_freq, self.max_freq)) diff --git a/spacq/devices/sample/abc1234.py b/spacq/devices/sample/abc1234.py index a051314..56690a4 100644 --- a/spacq/devices/sample/abc1234.py +++ b/spacq/devices/sample/abc1234.py @@ -50,12 +50,23 @@ def reset(self): def setting(self): """ This is a generic setting. + + Returns + ------- + str """ return self.ask('some:setting?') @setting.setter def setting(self, value): + """ + Set the generic setting. + + Parameters + ---------- + value : str + """ if value not in self.allowed_settings: raise ValueError('Invalid setting: {0}'.format(value)) @@ -67,6 +78,10 @@ def setting(self, value): def reading(self): """ The value measured by the device. + + Returns + ------- + float """ log.debug('Getting reading.') diff --git a/spacq/devices/stanford_research_systems/sg382.py b/spacq/devices/stanford_research_systems/sg382.py index dce1e5d..f015de5 100644 --- a/spacq/devices/stanford_research_systems/sg382.py +++ b/spacq/devices/stanford_research_systems/sg382.py @@ -78,6 +78,10 @@ def reset(self): def frequency(self): """ The output frequency of the signal generator + + Returns + ------- + float """ return float(self.ask('FREQ?')) @@ -85,6 +89,13 @@ def frequency(self): @frequency.setter @quantity_unwrapped('Hz') def frequency(self, value): + """ + Set the output frequency of the signal generator + + Parameters + ---------- + value : float + """ if value < self.minFreq or value > self.maxFreq: raise ValueError('Value {0} not within the allowed bounds: {1} to {2}'.format(value, self.minFreq, self.maxFreq)) @@ -95,6 +106,10 @@ def frequency(self, value): def FMDeviation(self): """ The amplitude of the frequency modulation + + Returns + ------- + float """ return float(self.ask('FDEV?')) @@ -102,27 +117,59 @@ def FMDeviation(self): @FMDeviation.setter @quantity_unwrapped('Hz') def FMDeviation(self, value): + """ + Set the amplitude of the frequency modulation + + Parameters + ---------- + value : float + """ self.write('FDEV {0}'.format(value)) @property def AMDepth(self): """ The amplitude of amplitude modulation (as a percentage of total signal [eg, 90.0 is 90%] + + Returns + ------- + float """ return float(self.ask('ADEP?')) @AMDepth.setter def AMDepth(self, value): + """ + Set the amplitude of amplitude modulation (as a percentage of total signal [eg, 90.0 is 90%] + + Parameters + ---------- + value : float + """ self.write('ADEP {0}'.format(value)) @property def phase(self): + """ + Returns the phase of the output + + Returns + ------- + float + """ # The phase of the output, (in degrees but SpanishAcquisition uses no units for this TODO: fix this) return float(self.ask('PHAS?')) @phase.setter def phase(self,value): + """ + Set the phase of the output + + Parameters + ---------- + value : float + """ if float(value) < self.minPhase or float(value) > self.maxPhase: raise ValueError('Value {0} not within the allowed bounds: {1} to {2}'.format(value, self.minPhase, self.maxPhase)) @@ -131,6 +178,13 @@ def phase(self,value): @property @quantity_wrapped('V') def BNCAmplitude(self): + """ + Returns the amplitude of the output on the BNC output line (if enabled) + + Returns + ------- + float + """ # The amplitude of the output on the BNC output line (if enabled) # Currently using Vpp value, as Spanish Acquisition doesn't handle dBm currently (TODO: add dBm units) return float(self.ask('AMPL? VPP')) @@ -138,6 +192,13 @@ def BNCAmplitude(self): @BNCAmplitude.setter @quantity_unwrapped('V') def BNCAmplitude(self,value): + """ + Set the amplitude of the output on the BNC output line + + Parameters + ---------- + value : float + """ if value < self.minBNCAmp or value > self.maxBNCAmp: raise ValueError('Value {0} not within the allowed bounds: {1} to {2}'.format(value, self.minBNCAmp, self.maxBNCAmp)) @@ -146,6 +207,13 @@ def BNCAmplitude(self,value): @property @quantity_wrapped('V') def typeNAmplitude(self): + """ + Returns the amplitude of the output on the Type N output line (if enabled) + + Returns + ------- + float + """ # The amplitude of the output on the Type N output line (if enabled) # Currently using Vpp value, as Spanish Acquisition doesn't handle dBm currently (TODO: add dBm units) return float(self.ask('AMPR? VPP')) @@ -153,6 +221,13 @@ def typeNAmplitude(self): @typeNAmplitude.setter @quantity_unwrapped('V') def typeNAmplitude(self,value): + """ + Set the amplitude of the output on the Type N output line + + Parameters + ---------- + value : float + """ if value < self.minTypeNAmp or value > self.maxTypeNAmp: raise ValueError('Value {0} not within the allowed bounds: {1} to {2}'.format(value, self.minTypeNAmp, self.maxTypeNAmp)) @@ -160,6 +235,13 @@ def typeNAmplitude(self,value): @property def modulationType(self): + """ + Returns the modulation type (eg, AM, FM, Phase, Blank, IQ) + + Returns + ------- + string + """ # Coded setting of the modulation type (eg, 1 = Amplitude Modulation) result = self.ask('TYPE?') if result == '0': @@ -179,6 +261,13 @@ def modulationType(self): @modulationType.setter def modulationType(self,value): + """ + Set the modulation type (eg, AM, FM, Phase, Blank, IQ) + + Parameters + ---------- + value : string + """ if value not in self.allowedModType: raise ValueError('Invalid Modulation Type: {0}'.format(value)) @@ -201,6 +290,13 @@ def modulationType(self,value): @property def modulationFunction(self): + """ + Returns the modulation function (eg, Sine, Ramp, Triangle, Square, Noise, External) + + Returns + ------- + string + """ # Coded setting of the modulation type (eg, 1 = Amplitude Modulation) result = self.ask('MFNC?') if result == '0': @@ -218,6 +314,13 @@ def modulationFunction(self): @modulationFunction.setter def modulationFunction(self,value): + """ + Set the modulation function (eg, Sine, Ramp, Triangle, Square, Noise, External) + + Parameters + ---------- + value : string + """ if value not in self.allowedModFunc: raise ValueError('Invalid Modulation Function: {0}'.format(value)) @@ -238,6 +341,13 @@ def modulationFunction(self,value): @property def modulationEnabled(self): + """ + Returns the modulation enable setting (on/off) + + Returns + ------- + string + """ # Turn on/off modulation of signal result = self.ask('MODL?') if result == '0': @@ -247,6 +357,13 @@ def modulationEnabled(self): @modulationEnabled.setter def modulationEnabled(self,value): + """ + Set the modulation enable setting (on/off) + + Parameters + ---------- + value : string + """ if value not in self.allowedEnable: raise ValueError('Invalid modulation enable setting: {0}'.format(value)) @@ -259,6 +376,13 @@ def modulationEnabled(self,value): @property def BNCEnable(self): + """ + Returns the BNC output enable setting (on/off) + + Returns + ------- + string + """ # Turn on/off the BNC output (it is automatically off above 62.5 MHz) result = self.ask('ENBL?') if result == '0': @@ -268,6 +392,13 @@ def BNCEnable(self): @BNCEnable.setter def BNCEnable(self,value): + """ + Set the BNC output enable setting (on/off) + + Parameters + ---------- + value : string + """ if value not in self.allowedEnable: raise ValueError('Invalid BNC enable setting: {0}'.format(value)) @@ -280,6 +411,13 @@ def BNCEnable(self,value): @property def typeNEnable(self): + """ + Returns the type-N output enable setting (on/off) + + Returns + ------- + string + """ # Turn on/off the type-N output result = self.ask('ENBR?') if result == '0': @@ -289,6 +427,13 @@ def typeNEnable(self): @typeNEnable.setter def typeNEnable(self,value): + """ + Set the type-N output enable setting (on/off) + + Parameters + ---------- + value : string + """ if value not in self.allowedEnable: raise ValueError('Invalid type-N enable setting: {0}'.format(value)) diff --git a/spacq/devices/stanford_research_systems/sim900.py b/spacq/devices/stanford_research_systems/sim900.py index 9da9fe6..f1c525d 100644 --- a/spacq/devices/stanford_research_systems/sim900.py +++ b/spacq/devices/stanford_research_systems/sim900.py @@ -74,6 +74,13 @@ def __init__(self, device, num, max_value, *args, **kwargs): @property @quantity_wrapped('V') def voltage(self): + """ + Return the voltage on this port, as a quantity in V. + + Returns + ------- + float + """ return self.currentVoltage @@ -82,6 +89,10 @@ def voltage(self): def voltage(self, value): """ Set the voltage on this port, as a quantity in V. + + Parameters + ---------- + value : float """ value = round(value, 3) resulting_voltage = value @@ -94,6 +105,10 @@ def voltage(self, value): class sim900(AbstractDevice): """ Interface for the SRS Sim900+Sim928 voltage source + + Parameters + ---------- + port_settings : dict, optional """ def _setup(self): diff --git a/spacq/devices/stanford_research_systems/sr830dsp.py b/spacq/devices/stanford_research_systems/sr830dsp.py index 958275a..dc7851a 100644 --- a/spacq/devices/stanford_research_systems/sr830dsp.py +++ b/spacq/devices/stanford_research_systems/sr830dsp.py @@ -76,6 +76,10 @@ def reset(self): def reference_freq(self): """ The frequency of the internal oscillator + + Returns + ------- + float """ return float(self.ask('FREQ?')) @@ -84,6 +88,13 @@ def reference_freq(self): @Synchronized() @quantity_unwrapped('Hz') def reference_freq(self, value): + """ + Set the frequency of the internal oscillator + + Parameters + ---------- + value : float + """ if value < self.min_freq or value > self.max_freq: raise ValueError('Value {0} not within the allowed bounds: {1} to {2}'.format(value, self.min_freq, self.max_freq)) @@ -93,12 +104,23 @@ def reference_freq(self, value): def reference_phase(self): """ The phase of the internal oscillator + + Returns + ------- + float """ return float(self.ask('PHAS?')) @reference_phase.setter def reference_phase(self, value): + """ + Set the phase of the internal oscillator + + Parameters + ---------- + value : float + """ if float(value) < self.min_phase or float(value) > self.max_phase: raise ValueError('Value {0} not within the allowed bounds: {1} to {2}'.format(value, self.min_phase, self.max_phase)) @@ -110,6 +132,10 @@ def reference_phase(self, value): def reference_amplitude(self): """ The amplitude of the internal oscillator sine wave + + Returns + ------- + float """ return float(self.ask('SLVL?')) @@ -129,6 +155,10 @@ def reference_amplitude(self, value): def amplitude_x(self): """ The amplitude of the x component of lock-in signal + + Returns + ------- + float """ return float(self.ask('OUTP? 1')) @@ -139,6 +169,10 @@ def amplitude_x(self): def amplitude_y(self): """ The amplitude of the y component of lock-in signal + + Returns + ------- + float """ return float(self.ask('OUTP? 2')) @@ -149,6 +183,10 @@ def amplitude_y(self): def amplitude_R(self): """ The amplitude of the R magnitude of lock-in signal + + Returns + ------- + float """ return float(self.ask('OUTP? 3')) @@ -158,6 +196,10 @@ def amplitude_R(self): def angle_theta(self): """ The amplitude of the angle theta of lock-in signal + + Returns + ------- + float """ return float(self.ask('OUTP? 4')) diff --git a/spacq/devices/tektronix/awg5014b.py b/spacq/devices/tektronix/awg5014b.py index 110a9e0..e1544fc 100644 --- a/spacq/devices/tektronix/awg5014b.py +++ b/spacq/devices/tektronix/awg5014b.py @@ -20,6 +20,14 @@ class Marker(AbstractSubdevice): """ Marker channel of an output channel. + + Parameters + ---------- + channel : int + The channel number. + number : int + The marker number. + device : AWG5014B """ def _setup(self): @@ -45,6 +53,10 @@ def __init__(self, device, channel, number, *args, **kwargs): def delay(self): """ The marker delay, as a quantity in s. + + Returns + ------- + float """ return float(self.device.ask('source{0}:marker{1}:delay?'.format(self.channel, self.number))) @@ -52,6 +64,13 @@ def delay(self): @delay.setter @quantity_unwrapped('s') def delay(self, v): + """ + Set the marker delay, as a quantity in s. + + Parameters + ---------- + v : float + """ self.device.write('source{0}:marker{1}:delay {2}'.format(self.channel, self.number, v)) @property @@ -59,6 +78,10 @@ def delay(self, v): def high(self): """ The marker high voltage, as a quantity in V. + + Returns + ------- + float """ return float(self.device.ask('source{0}:marker{1}:voltage:high?'.format(self.channel, self.number))) @@ -66,6 +89,13 @@ def high(self): @high.setter @quantity_unwrapped('V') def high(self, v): + """ + Set the marker high voltage, as a quantity in V. + + Parameters + ---------- + v : float + """ self.device.write('source{0}:marker{1}:voltage:high {2}'.format(self.channel, self.number, v)) @property @@ -73,6 +103,10 @@ def high(self, v): def low(self): """ The marker low voltage, as a quantity in V. + + Returns + ------- + float """ return float(self.device.ask('source{0}:marker{1}:voltage:low?'.format(self.channel, self.number))) @@ -80,12 +114,25 @@ def low(self): @low.setter @quantity_unwrapped('V') def low(self, v): + """ + Set the marker low voltage, as a quantity in V. + + Parameters + ---------- + v : float + """ self.device.write('source{0}:marker{1}:voltage:low {2}'.format(self.channel, self.number, v)) class Channel(AbstractSubdevice): """ Output channel of the AWG. + + Parameters + ---------- + channel : int + The channel number. + device : AWG5014B """ # Zero-to-peak amplitude range. @@ -118,6 +165,10 @@ def __init__(self, device, channel, *args, **kwargs): def waveform_name(self): """ The name of the output waveform for the channel. + + Returns + ------- + str """ result = self.device.ask('source{0}:waveform?'.format(self.channel)) @@ -126,6 +177,13 @@ def waveform_name(self): @waveform_name.setter def waveform_name(self, v): + """ + Set the name of the output waveform for the channel. + + Parameters + ---------- + v : str + """ self.device.write('source{0}:waveform "{1}"'.format(self.channel, v)) @waveform_name.deleter @@ -136,6 +194,10 @@ def waveform_name(self): def enabled(self): """ The output state (on/off) of the channel. + + Returns + ------- + bool """ result = self.device.ask('output{0}:state?'.format(self.channel)) @@ -144,6 +206,13 @@ def enabled(self): @enabled.setter def enabled(self, v): + """ + Set the output state (on/off) of the channel. + + Parameters + ---------- + v : bool + """ self.device.write('output{0}:state {1}'.format(self.channel, int(v))) @property @@ -151,6 +220,10 @@ def enabled(self, v): def amplitude(self): """ The zero-to-peak amplitude of the channel in V. + + Returns + ------- + float """ # Convert peak-to-peak to zero-to-peak. @@ -159,6 +232,13 @@ def amplitude(self): @amplitude.setter @quantity_unwrapped('V') def amplitude(self, v): + """ + Set the zero-to-peak amplitude of the channel in V. + + Parameters + ---------- + v : float + """ # Convert zero-to-peak to peak-to-peak. self.device.write('source{0}:voltage {1:E}'.format(self.channel, 2 * v)) @@ -167,6 +247,13 @@ def set_waveform(self, waveform, markers=None, name=None): Set the waveform on this channel. The waveform data should be in V. + + Parameters + ---------- + waveform : list of float + markers : dict of {int: list of bool}, optional + Marker number to list of marker values. + name : str, optional """ if name is None: @@ -231,6 +318,10 @@ def reset(self): def data_bits(self): """ How many bits of each data point represent the data itself. + + Returns + ------- + int """ return 14 @@ -239,6 +330,10 @@ def data_bits(self): def value_range(self): """ The range of values possible for each data point. + + Returns + ------- + tuple of int """ # The sent values are unsigned. @@ -249,6 +344,10 @@ def value_range(self): def sampling_rate(self): """ The sampling rate of the AWG in Hz. + + Returns + ------- + float """ return float(self.ask('source1:frequency?')) @@ -256,6 +355,13 @@ def sampling_rate(self): @sampling_rate.setter @quantity_unwrapped('Hz') def sampling_rate(self, value): + """ + Set the sampling rate of the AWG in Hz. + + Parameters + ---------- + value : float + """ if value < 1e7 or value > 1.2e9: raise ValueError('Sampling rate must be between 1e7 Hz and 1.2e9 Hz, not {0:n} Hz'.format(value)) @@ -265,6 +371,10 @@ def sampling_rate(self, value): def run_mode(self): """ The run mode of the AWG. One of: continuous, triggered, gated, sequence. + + Returns + ------- + str """ mode = self.ask('awgcontrol:rmode?').lower() @@ -292,6 +402,10 @@ def run_mode(self, value): def waveform_names(self): """ A list of all waveforms in the AWG. + + Returns + ------- + list of str """ num_waveforms = int(self.ask('wlist:size?')) @@ -307,6 +421,17 @@ def waveform_names(self): @Synchronized() def get_waveform(self, name): + """ + Get a waveform from the AWG. + + Parameters + ---------- + name : str + + Returns + ------- + list of float + """ self.status.append('Getting waveform "{0}"'.format(name)) try: @@ -334,6 +459,13 @@ def create_waveform(self, name, data, markers=None): Create a new waveform on the AWG. The waveform data should be on [-1, 1]. + + Parameters + ---------- + name : str + data : list of float + markers : dict of {int: list of bool}, optional + Marker number to list of marker values. """ self.status.append('Creating waveform "{0}"'.format(name)) @@ -378,6 +510,10 @@ def create_waveform(self, name, data, markers=None): def delete_waveform(self, name): """ Remove a waveform on the AWG. + + Parameters + ---------- + name : str """ if name not in self.waveform_names: @@ -389,6 +525,10 @@ def delete_waveform(self, name): def enabled(self): """ The continuous run state (on/off) of the AWG. + + Returns + ------- + bool """ state = self.ask('awgcontrol:rstate?') @@ -403,6 +543,13 @@ def enabled(self): @enabled.setter def enabled(self, v): + """ + Set the continuous run state (on/off) of the AWG. + + Parameters + ---------- + v : bool + """ if v: log.debug('Enabling "{0}".'.format(self.name)) @@ -416,6 +563,10 @@ def enabled(self, v): def waiting_for_trigger(self): """ Whether the AWG is waiting for a trigger. + + Returns + ------- + bool """ return '1' == self.ask('awgcontrol:rstate?') diff --git a/spacq/devices/tektronix/dpo7104.py b/spacq/devices/tektronix/dpo7104.py index 4f0ce48..c9a88c8 100644 --- a/spacq/devices/tektronix/dpo7104.py +++ b/spacq/devices/tektronix/dpo7104.py @@ -48,6 +48,11 @@ def __init__(self, device, channel, *args, **kwargs): def acquisition_window(self): """ The minimum and maximum obtainable values in V. + + Returns + ------- + tuple of floats + (minimum, maximum) """ # 10 divisions total. @@ -61,6 +66,14 @@ def acquisition_window(self): def transform_waveform(self, waveform): """ Transform some curve data onto the true amplitude interval in V, and intermix time values in s. + + Parameters + ---------- + waveform : list of floats + + Returns + ------- + list of floats """ value_min, value_max = self.device.value_range @@ -77,6 +90,10 @@ def transform_waveform(self, waveform): def enabled(self): """ The input state (on/off) of the channel. + + Returns + ------- + bool """ result = self.device.ask('select:ch{0}?'.format(self.channel)) @@ -93,6 +110,10 @@ def waveform(self): A waveform acquired by the scope. Values are returned in the format [(time1, value1), (time2, value2), ...]. + + Returns + ------- + list of (float, float) """ self.device.status.append('Getting waveform for channel {0}'.format(self.channel)) @@ -137,6 +158,10 @@ def scale(self): Vertical scale for the channel, as a quantity in V. Note: This is for a single division, of which there are 10. + + Returns + ------- + float """ return float(self.device.ask('ch{0}:scale?'.format(self.channel))) @@ -151,6 +176,10 @@ def scale(self, value): def offset(self): """ Vertical offset for the channel, as a quantity in V. + + Returns + ------- + float """ return float(self.device.ask('ch{0}:offset?'.format(self.channel))) @@ -212,6 +241,10 @@ def autoset(self): def stopafter(self): """ The acqusition mode. + + Returns + ------- + str """ value = self.ask('acquire:stopafter?').lower() @@ -223,6 +256,13 @@ def stopafter(self): @stopafter.setter def stopafter(self, value): + """ + Set the acquisition mode. + + Parameters + ---------- + value : str + """ if value not in self.allowed_stopafters: raise ValueError('Invalid acquisition mode: {0}'.format(value)) @@ -232,18 +272,33 @@ def stopafter(self, value): def waveform_bytes(self): """ Number of bytes per data point in the acquired waveforms. + + Returns + ------- + int """ return int(self.ask('wfmoutpre:byt_nr?')) @waveform_bytes.setter def waveform_bytes(self, value): + """ + Set the number of bytes per data point in the acquired waveforms. + + Parameters + ---------- + value : int + """ self.write('wfmoutpre:byt_nr {0}'.format(value)) @property def value_range(self): """ Range of values possible for each data point. + + Returns + ------- + tuple of ints """ # The returned values are signed. @@ -256,6 +311,10 @@ def value_range(self): def acquiring(self): """ Whether the device is currently acquiring data. + + Returns + ------- + bool """ result = self.ask('acquire:state?') @@ -263,6 +322,13 @@ def acquiring(self): @acquiring.setter def acquiring(self, value): + """ + Set whether the device is currently acquiring data. + + Parameters + ---------- + value : bool + """ self.write('acquire:state {0}'.format(str(int(value)))) @property @@ -270,6 +336,10 @@ def acquiring(self, value): def sample_rate(self): """ The sample rate in s-1. + + Returns + ------- + float """ return float(self.ask('horizontal:mode:samplerate?')) @@ -277,6 +347,13 @@ def sample_rate(self): @sample_rate.setter @quantity_unwrapped('Hz') def sample_rate(self, value): + """ + Set the sample rate in s-1. + + Parameters + ---------- + value : float + """ self.write('horizontal:mode:samplerate {0}'.format(value)) @property @@ -284,6 +361,10 @@ def sample_rate(self, value): def time_scale(self): """ The length for a waveform. + + Returns + ------- + float """ return float(self.ask('horizontal:divisions?')) * float(self.ask('horizontal:mode:scale?')) @@ -291,12 +372,23 @@ def time_scale(self): @time_scale.setter @quantity_unwrapped('s') def time_scale(self, value): + """ + Set the length for a waveform. + + Parameters + ---------- + value : float + """ self.write('horizontal:mode:scale {0}'.format(value / float(self.ask('horizontal:divisions?')))) @property def data_source(self): """ The source from which to transfer data. + + Returns + ------- + int """ result = self.ask('data:source?') @@ -306,36 +398,69 @@ def data_source(self): @data_source.setter def data_source(self, value): + """ + Set the source from which to transfer data. + + Parameters + ---------- + value : int + """ self.write('data:source ch{0}'.format(value)) @property def data_start(self): """ The first data point to transfer. + + Returns + ------- + int """ return int(self.ask('data:start?')) @data_start.setter def data_start(self, value): + """ + Set the first data point to transfer. + + Parameters + ---------- + value : int + """ self.write('data:start {0}'.format(value)) @property def data_stop(self): """ The last data point to transfer. + + Returns + ------- + int """ return int(self.ask('data:stop?')) @data_stop.setter def data_stop(self, value): + """ + Set the last data point to transfer. + + Parameters + ---------- + value : int + """ self.write('data:stop {0}'.format(value)) @property def record_length(self): """ The number of data points in a waveform. + + Returns + ------- + int """ return int(self.ask('horizontal:mode:recordlength?')) @@ -352,18 +477,33 @@ def acquire(self): def fastframe(self): """ Whether fastframe is enabled. + + Returns + ------- + bool """ return bool(int(self.ask('horizontal:fastframe:state?'))) @fastframe.setter def fastframe(self, value): + """ + Set whether fastframe is enabled. + + Parameters + ---------- + value : bool + """ return self.write('horizontal:fastframe:state {0}'.format(int(value))) @property def fastframe_sum(self): """ The fastframe summary frame. + + Returns + ------- + str, one of 'none', 'average', 'envelope' """ result = self.ask('horizontal:fastframe:sumframe?').lower() @@ -379,6 +519,14 @@ def fastframe_sum(self): @fastframe_sum.setter def fastframe_sum(self, value): + """ + Set the fastframe summary frame. + + Parameters + ---------- + value : str, one of 'none', 'average', 'envelope' + + """ if value not in self.allowed_fastframe_sums: raise ValueError('Invalid summary frame mode: {0}'.format(value)) @@ -388,12 +536,23 @@ def fastframe_sum(self, value): def fastframe_count(self): """ The number of waveforms to acquire in fastframe mode. + + Returns + ------- + int """ return int(self.ask('horizontal:fastframe:count?')) @fastframe_count.setter def fastframe_count(self, value): + """ + Set the number of waveforms to acquire in fastframe mode. + + Parameters + ---------- + value : int + """ if value <= 0: raise ValueError('Must provide a positive integer, not "{0}"'.format(value)) @@ -403,30 +562,56 @@ def fastframe_count(self, value): def fastframe_start(self): """ The first frame to transfer. + + Returns + ------- + int """ return int(self.ask('data:framestart?')) @fastframe_start.setter def fastframe_start(self, value): + """ + Set the first frame to transfer. + + Parameters + ---------- + value : int + """ self.write('data:framestart {0}'.format(value)) @property def fastframe_stop(self): """ The last frame to transfer. + + Returns + ------- + int """ return int(self.ask('data:framestop?')) @fastframe_stop.setter def fastframe_stop(self, value): + """ + Set the last frame to transfer. + + Parameters + ---------- + value : int + """ self.write('data:framestop {0}'.format(value)) @property def acquisitions(self): """ The number of acquisitions made so far on the oscilloscope. + + Returns + ------- + int """ return int(self.ask('acquire:numacq?')) diff --git a/spacq/devices/tools.py b/spacq/devices/tools.py index 30b75ba..c83fab0 100755 --- a/spacq/devices/tools.py +++ b/spacq/devices/tools.py @@ -15,6 +15,14 @@ def str_to_bool(value): """ False and 'False' => False otherwise => True + + Parameters + ---------- + value : str + + Returns + ------- + bool """ return bool(value) and value.lower() != 'false' @@ -23,6 +31,15 @@ def str_to_bool(value): def quantity_wrapped(units, multiplier=1.0): """ A decorator for getters to wrap the plain device value into a quantity with a unit. + + Parameters + ---------- + units : str + multiplier : float, optional + + Returns + ------- + function """ def wrap(f): @@ -38,6 +55,15 @@ def wrapped(self): def quantity_unwrapped(units, multiplier=1.0): """ A decorator for setters to extract the plain device value from the quantity. + + Parameters + ---------- + units : str + multiplier : float, optional + + Returns + ------- + function """ def wrap(f): @@ -56,6 +82,15 @@ def converted_quantity_unwrapped(units, multiplier=1.0): """ A variation of quantity_unwrapped that extracts the value in the units provided, and then applies the multiplier if given. + + Parameters + ---------- + units : str + multiplier : float, optional + + Returns + ------- + function """ def wrap(f): @@ -82,6 +117,16 @@ def dynamic_quantity_wrapped(units_attr_string, multiplier=1.0): is defined by an attribute extracted from the device. Note: Will work on a chain of dotted attributes. + + Parameters + ---------- + units_attr_string : str + The attribute name of the units of the quantity. + multiplier : float, optional + + Returns + ------- + function """ def wrap(f): @@ -101,6 +146,16 @@ def wrapped(self): def dynamic_converted_quantity_unwrapped(units_attr_string, multiplier=1.0): """ A variation of dynamic_quantity_unwrapped that will extract the units from an attribute of the device. + + Parameters + ---------- + units_attr_string : str + The attribute name of the units of the quantity. + multiplier : float, optional + + Returns + ------- + function """ def wrap(f): @@ -146,6 +201,14 @@ def to_block_data(data): As per section 7.7.6 of IEEE Std 488.2-1992. Note: Does not produce indefinitely-formatted block data. + + Parameters + ---------- + data : str + + Returns + ------- + str """ log.debug('Converting to block data: {0!r}'.format(data)) @@ -161,6 +224,14 @@ def from_block_data(block_data): Extracts binary data from 488.2 block data. As per section 7.7.6 of IEEE Std 488.2-1992. + + Parameters + ---------- + block_data : str + + Returns + ------- + str """ log.debug('Converting from block data: {0!r}'.format(block_data)) @@ -222,6 +293,14 @@ class BinaryEncoder(object): def encode(msg): """ Convert a string of hexadecimal digits to a byte string. + + Parameters + ---------- + msg : str + + Returns + ------- + str """ log.debug('Encoding to byte string: {0}'.format(msg)) @@ -241,6 +320,18 @@ def encode(msg): def decode(msg, pair_size=2, pair_up=True): """ Convert a byte string to a string of hexadecimal digits. + + Parameters + ---------- + msg : str + pair_size : int, optional + The number of bytes to group together. + pair_up : bool, optional + Whether to separate the bytes with spaces. + + Returns + ------- + str """ log.debug('Decoding from byte string: {0!r}'.format(msg)) @@ -270,6 +361,14 @@ def decode(msg, pair_size=2, pair_up=True): def length(msg): """ Calculate the number of bytes an unencoded message takes up when encoded. + + Parameters + ---------- + msg : str + + Returns + ------- + int """ log.debug('Finding encoded length: {0}'.format(msg)) diff --git a/spacq/gui/__init__.py b/spacq/gui/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/spacq/gui/action/__init__.py b/spacq/gui/action/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/spacq/gui/action/data_capture.py b/spacq/gui/action/data_capture.py index 3291221..c9cfda7 100755 --- a/spacq/gui/action/data_capture.py +++ b/spacq/gui/action/data_capture.py @@ -21,6 +21,20 @@ class DataCaptureDialog(Dialog, SweepController): """ A progress dialog which runs over iterators, sets the corresponding resources, and captures the measured data. + + Parameters + ---------- + resources : list of list of (str, Resource) + The resources to set. + variables : list of list of OutputVariable + The variables to set. + num_items : int + measurement_resources : list of (str, Resource) + measurement_variables : list of InputVariable + condition_resources : list of list of (str, Resource) + condition_variables : list of list of ConditionVariable + pulse_config : PulseConfiguration + continuous : bool, optional """ max_value_len = 50 # characters @@ -197,6 +211,9 @@ def _resource_exception_handler(self, resource_name, e, write=True): self.abort(fatal=write) def start(self): + """ + Start the sweep. + """ thr = Thread(target=SweepController.run, args=(self,)) thr.daemon = True thr.start() @@ -212,6 +229,9 @@ def dwell(self): return result def end(self): + """ + Ends sweep and closes dialog. + """ try: SweepController.end(self) except AssertionError: @@ -233,6 +253,14 @@ def OnCancel(self, evt=None): self.cancelling = True def OnTimer(self, evt=None): + """ + Updates the status message, progress bar, and elapsed time, and prompts the user to + abort the processing if necessary. + + Parameters + ---------- + evt : wx.Event + """ self.status_message_output.Value = self.status_messages[self.current_f] if self.continuous: self.last_continuous = self.last_continuous_input.Value @@ -282,8 +310,7 @@ def resume(): self.last_checked_time = -1 self.timer.Stop() - YesNoQuestionDialog(self, 'Abort processing?', - abort, resume).Show() + YesNoQuestionDialog(self, 'Abort processing?', abort, resume).Show() return @@ -291,6 +318,11 @@ def resume(): class DataCapturePanel(wx.Panel): """ A panel to start the data capture process, optionally exporting the results to a file. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore """ def __init__(self, parent, global_store, *args, **kwargs): @@ -350,6 +382,14 @@ def __init__(self, parent, global_store, *args, **kwargs): self.SetSizer(panel_box) def OnBeginCapture(self, evt=None): + """ + Starts the data capture process When the user clicks the 'Begin Capture' button. + validates the required resources and devices, and opens a DataCaptureDialog to capture data from the specified resources. + + Parameters + ---------- + evt : wx.Event + """ # Prevent accidental double-clicking. self.start_button.Disable() @@ -390,6 +430,8 @@ def enable_button(): pulse_program = self.global_store.pulse_program + # Validating the pulse program. + if pulse_program is not None: pulse_program = pulse_program.with_resources @@ -443,6 +485,8 @@ def enable_button(): else: pulse_config = None + # Preparing resources. + resources = [] for group in resource_names: group_resources = [] @@ -627,8 +671,8 @@ def enable_button(): self.capture_dialogs += 1 - dlg = DataCaptureDialog(self, resources, output_variables, num_items, measurement_resources, - input_variables, condition_resources, condition_variables, pulse_config, continuous=continuous) + dlg = DataCaptureDialog(self, resources, output_variables, num_items, measurement_resources, input_variables, + condition_resources, condition_variables, pulse_config, continuous=continuous) dlg.SetMinSize((500, -1)) for name in measurement_resource_names: diff --git a/spacq/gui/action/smooth_reset.py b/spacq/gui/action/smooth_reset.py index f49ebd5..3c02fef 100644 --- a/spacq/gui/action/smooth_reset.py +++ b/spacq/gui/action/smooth_reset.py @@ -11,6 +11,12 @@ class SmoothResetPanel(wx.Panel): """ A panel to change variables smoothly to and from preset values. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore + The global store of all devices, resources, and variables. """ def __init__(self, parent, global_store, *args, **kwargs): @@ -54,6 +60,10 @@ def __init__(self, parent, global_store, *args, **kwargs): def choose_variables(self): """ Return all the selected variables, ensuring that their resources are valid. + + Returns + ------- + list of OutputVariable """ all_vars = sift( @@ -82,6 +92,16 @@ def choose_variables(self): return vars def reset(self, sweep_setting): + """ + Reset all the selected variables depending on their settings. + + Parameters + ---------- + sweep_setting : int + 0: from current value to zero + 1: from zero to current value + 2: from current value to const + """ vars = self.choose_variables() if vars is None: return diff --git a/spacq/gui/config/__init__.py b/spacq/gui/config/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/spacq/gui/config/device/resource_tree.py b/spacq/gui/config/device/resource_tree.py index b2c7ce0..bf23964 100644 --- a/spacq/gui/config/device/resource_tree.py +++ b/spacq/gui/config/device/resource_tree.py @@ -16,15 +16,18 @@ class ResourceFetcher(Thread): """ A thread which iterates over a list of items, getting resource values. + + Parameters + ---------- + items : list + List of TreeListCtrl items. + getter : function + Given an item, returns a Resource or None. + callback : function + Is called with the item and the value of the resource. """ def __init__(self, items, getter, callback, *args, **kwargs): - """ - items: List of TreeListCtrl items. - getter: Given an item, returns a Resource or None. - callback: Is called with the item and the value of the resource. - """ - Thread.__init__(self, *args, **kwargs) self.items = items @@ -32,6 +35,9 @@ def __init__(self, items, getter, callback, *args, **kwargs): self.callback = callback def run(self): + """ + Get the values of the resources. + """ try: for item in self.items: resource = self.getter(item) @@ -49,6 +55,11 @@ def run(self): class ItemData(object): """ Useful information about a node to be stored in its PyData. + + Parameters + ---------- + path : tuple + resource : Resource """ def __init__(self, path, resource): @@ -61,6 +72,10 @@ def __init__(self, path, resource): class ResourceTree(TreeListCtrl): """ A tree list to display an hierarchy of subdevices and resources. + + Parameters + ---------- + parent : wx.Window """ def __init__(self, parent, *args, **kwargs): @@ -95,6 +110,15 @@ def __init__(self, parent, *args, **kwargs): def GetChildren(self, item): """ Non-recursive generator for the children of an item. + + Parameters + ---------- + item : TreeListCtrl + + Returns + ------- + generator + a generator of TreeListCtrl items """ if self.HasChildren(item): @@ -108,6 +132,14 @@ def GetChildren(self, item): def GetLeaves(self, item=None): """ Recursively collect the leaves under an item. + + Parameters + ---------- + item : TreeListCtrl, optional + + Returns + ------- + list """ if item is None: @@ -137,6 +169,10 @@ def fell(self): def spawn_fetch_thread(self, items): """ Create a thread to populate the items. + + Parameters + ---------- + items : list """ def fetch(item): @@ -162,6 +198,14 @@ def set(item, value): def build_tree(self, device, resource_labels, root=None, path=None): """ Recursively append all subdevices and resources. + + Parameters + ---------- + device : Device + resource_labels : dict + Maps resource paths to labels. + root : TreeListCtrl, optional + path : tuple, optional """ if root is None: @@ -205,6 +249,12 @@ def build_tree(self, device, resource_labels, root=None, path=None): def set_value(self, item, value, error_callback=None): """ Set the value of a resource, as well as the displayed value. + + Parameters + ---------- + item : wx.TreeListItem + value : str + error_callback : callable, optional """ pydata = self.GetItemPyData(item) @@ -245,6 +295,14 @@ def OnItemExpanded(self, evt): self.spawn_fetch_thread(self.GetChildren(evt.GetItem())) def OnBeginLabelEdit(self, evt): + """ + The `OnBeginLabelEdit` function is used to handle the event when a label in a tree control is about + to be edited, and it performs various checks and actions based on the column being edited. + + Parameters + ---------- + evt : wx.Event + """ # EVT_TREE_END_LABEL_EDIT does not carry this value. self.editing_col = evt.Int @@ -288,6 +346,13 @@ def OnBeginLabelEdit(self, evt): evt.Veto() def OnEndLabelEdit(self, evt): + """ + Update the label or value of a resource. + + Parameters + ---------- + evt : wx.Event + """ if self.editing_col == self.col_label: # Prevent duplicates. value = evt.GetLabel() @@ -323,6 +388,10 @@ def OnActivated(self, evt): class DeviceResourcesPanel(wx.Panel): """ A panel for displaying the subdevices and resources of a device. + + Parameters + ---------- + parent : wx.Window """ def __init__(self, parent, *args, **kwargs): @@ -338,12 +407,28 @@ def __init__(self, parent, *args, **kwargs): self.SetSizer(panel_box) def set_device(self, device, resource_labels): + """ + Set the device to display. + + Parameters + ---------- + device : Device + resource_labels : dict + A dictionary mapping resource paths to labels. + """ if device is None: self.tree.fell() else: self.tree.build_tree(device, resource_labels) def GetValue(self): + """ + Get the labels and values of the resources. + + Returns + ------- + (dictionary mapping resource paths to labels, dictionary mapping labels to values) + """ labels = {} resources = {} @@ -358,6 +443,16 @@ def GetValue(self): return (labels, resources) def SetValue(self, resource_labels, resources): + """ + Set the labels and values of the resources. + + Parameters + ---------- + resource_labels : dict + A dictionary mapping resource paths to labels. + resources : dict + A dictionary mapping labels to values. + """ for path, name in list(resource_labels.items()): for leaf in self.tree.GetLeaves(): pydata = self.tree.GetItemPyData(leaf) diff --git a/spacq/gui/config/devices.py b/spacq/gui/config/devices.py index f152f9e..b51dbd6 100644 --- a/spacq/gui/config/devices.py +++ b/spacq/gui/config/devices.py @@ -16,6 +16,10 @@ class DeviceColumnDefn(ObjectListView.ColumnDefn): """ A column with useful defaults. + + Parameters + ---------- + align : str, optional """ def __init__(self, align='left', *args, **kwargs): @@ -27,6 +31,15 @@ def __init__(self, align='left', *args, **kwargs): class DevicesPanel(wx.Panel): + """ + A panel for editing DeviceConfig objects. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore + dialog_owner : wx.Window + """ col_name = DeviceColumnDefn(title='Name', valueGetter='name', width=200) col_connection = DeviceColumnDefn(title='Connection', width=110, valueGetter=lambda x: '{0}onnected'.format('C' if x.device is not None else 'Disc')) @@ -84,6 +97,13 @@ def __init__(self, parent, global_store, dialog_owner, *args, **kwargs): def update_resources(self, old, new): """ Inform everybody of updated resources. + + Parameters + ---------- + old : DeviceConfig + The old device. + new : DeviceConfig + The new device. """ (appeared, changed, disappeared) = old.diff_resources(new) @@ -105,6 +125,13 @@ def update_resources(self, old, new): return [] def OnCellEditStarting(self, evt): + """ + Open a dialog to edit the device. + + Parameters + ---------- + evt : wx.Event + """ col = evt.objectListView.columns[evt.subItemIndex] dev = evt.rowModel @@ -156,6 +183,13 @@ def ok_callback(dlg): evt.Veto() def OnCellEditFinishing(self, evt): + """ + Update the device name in the global store. + + Parameters + ---------- + evt : wx.Event + """ col = evt.objectListView.columns[evt.subItemIndex] if col == self.col_name: @@ -181,6 +215,10 @@ def OnCellEditFinishing(self, evt): def OnAddDevice(self, evt=None): """ Add a blank variable to the OLV. + + Parameters + ---------- + evt : wx.Event, optional """ # Ensure that we get a unique name. @@ -206,6 +244,10 @@ def OnAddDevice(self, evt=None): def OnRemoveDevices(self, evt=None): """ Remove all selected variables from the OLV. + + Parameters + ---------- + evt : wx.Event, optional """ selected = self.olv.GetSelectedObjects() @@ -228,6 +270,14 @@ def OnRemoveDevices(self, evt=None): class DeviceConfigFrame(wx.Frame): + """ + Frame for configuring devices. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore + """ def __init__(self, parent, global_store, *args, **kwargs): wx.Frame.__init__( self, parent, title='Device Configuration', *args, **kwargs) @@ -261,6 +311,13 @@ def status_poller(self): sleep(0.2) def OnClose(self, evt): + """ + Close the frame. + + Parameters + ---------- + evt : wx.Event + """ info = AboutDialogInfo() info.SetName("Don't close this") info.SetDescription( diff --git a/spacq/gui/config/measurement.py b/spacq/gui/config/measurement.py index 943eb01..9ec5651 100755 --- a/spacq/gui/config/measurement.py +++ b/spacq/gui/config/measurement.py @@ -10,6 +10,12 @@ class MeasurementConfigPanel(wx.Panel): """ Measurement configuration panel. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore + scaling : bool, optional """ def __init__(self, parent, global_store, scaling=True, *args, **kwargs): @@ -112,6 +118,17 @@ def live_view_panel(self): return self.parent.live_view_panel def wrap_with_scaling(self, name, resource): + """ + Wrap the resource with the scaling. + + Parameters + ---------- + name : str + resource : Resource + + Returns + ------- + Resource""" if not self.scaling: return @@ -130,6 +147,9 @@ def transform(x): self.global_store.resources[name] = wrapped_resource def unwrap_with_scaling(self): + """ + Unwrap the resource with the scaling. + """ if not self.scaling: return @@ -166,6 +186,13 @@ def OnResourceNameChange(self, evt=None): self.resource_name_input.BackgroundColour = self.resource_name_input.default_background_color def OnResourceNameInput(self, evt=None): + """ + Updates the name of a resource. + + Parameters + ---------- + evt : wx.Event, optional + """ if self.var.resource_name != self.resource_name_input.Value: # Ensure that the resource is unwrapped before releasing it. self.unwrap_with_scaling() @@ -190,6 +217,13 @@ def OnMeasurementNameChange(self, evt=None): self.measurement_name_input.BackgroundColour = self.measurement_name_input.default_background_color def OnMeasurementNameInput(self, evt=None): + """ + Updates the name of a measurement variable and handles any conflicts with existing variable names. + + Parameters + ---------- + evt : wx.Event, optional + """ if self.var.name != self.measurement_name_input.Value: # Attempt to add a new entry first. var_new_name = self.measurement_name_input.Value @@ -208,6 +242,13 @@ def OnMeasurementNameInput(self, evt=None): self.set_title() def OnScaling(self, evt=None): + """ + Opens a dialog box to allow the user to adjust scaling settings and saves the selected settings. + + Parameters + ---------- + evt : wx.Event, optional + """ def ok_callback(dlg): self.scaling_settings = dlg.GetValue() @@ -216,6 +257,14 @@ def ok_callback(dlg): dlg.Show() def msg_resource(self, name, value=None): + """ + Message handler for resource addition and removal. + + Parameters + ---------- + name : str + value : Resource, optional + """ resource_name = self.var.resource_name if name == resource_name: diff --git a/spacq/gui/config/pulse.py b/spacq/gui/config/pulse.py index 44e67b9..bd7bb51 100644 --- a/spacq/gui/config/pulse.py +++ b/spacq/gui/config/pulse.py @@ -21,6 +21,17 @@ def SetBackgroundColour(self, colour): def pos_int_converter(x): + """ + Convert a string to a positive integer, or raise ValueError if not possible. + + Parameters + ---------- + x : str + + Returns + ------- + int + """ try: result = int(x) @@ -32,6 +43,17 @@ def pos_int_converter(x): raise ValueError('Expected positive integer') def quantity_converter(x, symbols='s', dimensions='time', non_negative=True): + """ + Convert a string to a Quantity, or raise ValueError if not possible. + + Parameters + ---------- + x : str + symbols : str + dimensions : str, optional + Expected dimensions of the quantity, default 'time'. + non_negative : bool, optional + """ try: q = Quantity(x) q.assert_dimensions(symbols) @@ -47,6 +69,12 @@ def quantity_converter(x, symbols='s', dimensions='time', non_negative=True): class ParameterPanel(ScrolledPanel): """ A generic panel to display parameters of a particular type. + + Parameters + ---------- + parent : wx.Window + global_store : dict + prog: Program """ attributes = False @@ -58,6 +86,14 @@ class ParameterPanel(ScrolledPanel): def extract_variables(self, prog): """ By default, extract the variables which pertain to the current type. + + Parameters + ---------- + prog : Program + + Returns + ------- + list of str """ return [k for k, v in list(prog.variables.items()) if v == self.type] @@ -65,6 +101,14 @@ def extract_variables(self, prog): def extract_parameters(self, prog): """ By default, extract the parameters which pertain to the current type. + + Parameters + ---------- + prog : Program + + Returns + ------- + list of str """ variables = self.extract_variables(prog) @@ -75,6 +119,10 @@ def extract_parameters(self, prog): def num_cols(self): """ Number of columns per row. + + Returns + ------- + int """ # Label and input field. @@ -98,6 +146,10 @@ def num_cols(self): def input_col(self): """ The 0-based position of the growable input column. + + Returns + ------- + int """ if self.use_resource_labels: @@ -110,6 +162,14 @@ def input_col(self): def get_value(self, parameter): """ Get the value of a parameter as a string, or raise KeyError if not available. + + Parameters + ---------- + parameter : str + + Returns + ------- + str """ return str(self.values[parameter]) @@ -117,6 +177,14 @@ def get_value(self, parameter): def get_resource_label(self, parameter): """ Get the resource label for a parameter, or empty string if not available. + + Parameters + ---------- + parameter : str + + Returns + ------- + str """ try: @@ -150,6 +218,10 @@ def add_headings(self): def add_resource_label(self, parameter): """ Add a resource label input. + + Parameters + ---------- + parameter : str """ resource_input = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER) @@ -168,6 +240,13 @@ def add_resource_label(self, parameter): def add_row(self, parameter, input_type='text', increment_row=True): """ Add a parameter to the sizer and display the value if it is available. + + Parameters + ---------- + parameter : str + input_type : str, optional + 'text' or 'file' + increment_row : bool, optional """ self.cur_col = 0 @@ -270,6 +349,12 @@ def set_resource_label(self, parameter, value, resource): self.resources[parameter] = resource def del_resource_label(self, parameter): + """ + Delete the resource label for a parameter. + + Parameters + ---------- + parameter : str""" try: label = self.resource_labels[parameter] except KeyError: @@ -286,6 +371,14 @@ def OnChange(self, parameter, evt): evt.EventObject.BackgroundColour = evt.EventObject.default_background_color def OnInput(self, parameter, evt): + """ + Handle the input of a parameter. + + Parameters + ---------- + parameter : str + The parameter to which the input is attached. + evt : wx.Event""" try: value = self.converter(parameter, evt.String) except ValueError as e: @@ -305,6 +398,15 @@ def OnResourceChange(self, parameter, evt): evt.EventObject.BackgroundColour = evt.EventObject.default_background_color def OnResourceInput(self, parameter, evt): + """ + Handle the input of a resource label. + + Parameters + ---------- + parameter : str + The parameter to which the resource label is attached. + evt : wx.Event + """ label = evt.String try: @@ -331,12 +433,26 @@ def OnResourceInput(self, parameter, evt): class AcqMarkerPanel(ParameterPanel): + """ + A panel for editing acquisition marker parameters. + """ type = 'acq_marker' name = 'Acquisition' attributes = True hide_variables = True def converter(self, parameter, x): + """ + Converts the input to a valid value for the parameter. + + Parameters + ---------- + parameter : tuple + x : str + + Returns + ------- + str""" x = ParameterPanel.converter(self, parameter, x) if parameter[1] == 'marker_num': @@ -389,6 +505,13 @@ def OnTimesAverageChange(self, evt=None): self.times_average_input.BackgroundColour = self.times_average_input.default_background_color def OnTimesAverageInput(self, evt=None): + """ + Convert the given string to a positive integer and set the program's times to average. + + Parameters + ---------- + evt : wx.Event + """ try: value = pos_int_converter(self.times_average_input.Value) except ValueError as e: @@ -404,6 +527,13 @@ def OnDelayChange(self, evt=None): self.delay_input.BackgroundColour = self.delay_input.default_background_color def OnDelayInput(self, evt=None): + """ + Convert the given string to a time and set the program's acquisition delay. + + Parameters + ---------- + evt : wx.Event + """ try: value = quantity_converter(self.delay_input.Value, 's', 'time') except ValueError as e: @@ -417,22 +547,52 @@ def OnDelayInput(self, evt=None): class DelayPanel(ParameterPanel): + """ + A panel for editing delays. + """ type = 'delay' name = 'Delays' use_resource_labels = True def converter(self, parameter, x): + """ + Convert the given string to a time. + + Parameters + ---------- + parameter : tuple + x : str + + Returns + ------- + Quantity + """ x = ParameterPanel.converter(self, parameter, x) return quantity_converter(x) class IntPanel(ParameterPanel): + """ + A panel for editing integers. + """ type = 'int' name = 'Integers' use_resource_labels = True def converter(self, parameter, x): + """ + Convert the given string to an integer. + + Parameters + ---------- + parameter : tuple + x : str + + Returns + ------- + int + """ x = ParameterPanel.converter(self, parameter, x) try: @@ -442,6 +602,9 @@ def converter(self, parameter, x): class OutputPanel(ParameterPanel): + """ + A panel for editing output channels. + """ type = 'output' name = 'Outputs' @@ -457,6 +620,17 @@ def input_col(self): return self.num_cols - 2 def get_value(self, parameter): + """ + Get the value of the given parameter. + + Parameters + ---------- + parameter : tuple + + Returns + ------- + str + """ result = self.prog.output_channels[parameter[0]] if result is not None: @@ -465,6 +639,13 @@ def get_value(self, parameter): raise KeyError(parameter[0]) def add_row(self, parameter): + """ + Add a row to the panel for the given parameter. + + Parameters + ---------- + parameter : tuple + """ ParameterPanel.add_row(self, parameter, increment_row=False) view_button = wx.Button(self, label='View') @@ -543,6 +724,12 @@ def OnFrequencyChange(self, evt=None): self.freq_input.BackgroundColour = self.freq_input.default_background_color def OnFrequencyInput(self, evt=None): + """ + Handles the user pressing enter in the frequency input box. + + Parameters + ---------- + evt : wx.Event""" try: value = quantity_converter(self.freq_input.Value, 'Hz', 'frequency') except ValueError as e: @@ -571,6 +758,13 @@ def OnOscilloscopeInput(self, evt=None): self.oscilloscope_input.BackgroundColour = OK_BACKGROUND_COLOR def OnView(self, parameter, evt=None): + """ + Displays the waveform for the given parameter. + + Parameters + ---------- + parameter : tuple + evt : wx.Event, optional""" def show_frame(waveform, markers, frequency): view_frame = WaveformFrame(self, parameter[0]) view_frame.SetValue(waveform, markers, frequency) @@ -601,18 +795,40 @@ def show_waveform(): class PulsePanel(ParameterPanel): + """ + A panel for pulse parameters. + """ type = 'pulse' name = 'Pulses' attributes = True use_resource_labels = True def add_resource_label(self, parameter): + """ + Adds a resource label to a parameter panel. + + Parameters + ---------- + parameter : tuple + """ if parameter[1] == 'shape': self.cur_col += 1 else: ParameterPanel.add_resource_label(self, parameter) def add_row(self, parameter): + """ + Adds a row to a parameter panel. + + Parameters + ---------- + parameter : tuple + The parameter tuple. + + Returns + ------- + None + """ kwargs = {} if parameter[1] == 'shape': kwargs['input_type'] = 'file' @@ -620,6 +836,20 @@ def add_row(self, parameter): return ParameterPanel.add_row(self, parameter, **kwargs) def converter(self, parameter, x): + """ + Takes a parameter and a value, and based on the parameter type, it converts the value to a different unit or returns it as is. + + Parameters + ---------- + parameter : tuple + The parameter tuple. + x : str + The value to convert. + + Returns + ------- + str + """ x = ParameterPanel.converter(self, parameter, x) if parameter[1] == 'amplitude': @@ -633,6 +863,11 @@ def converter(self, parameter, x): class PulseProgramPanel(wx.Panel): """ A panel to display and change all the parameters of a program. + + Parameters + ---------- + parent : wx.Window + global_store : dict """ panel_types = {'acq_marker': AcqMarkerPanel, 'delay': DelayPanel, 'int': IntPanel, @@ -656,6 +891,13 @@ def __init__(self, parent, global_store, *args, **kwargs): self.SetSizerAndFit(panel_box) def create_parameter_panels(self, prog): + """ + Create a panel for each type of parameter in the program. + + Parameters + ---------- + prog : Program + """ types = set(prog.variables.values()) for type in sorted(types): @@ -680,6 +922,15 @@ def OnClose(self): class PulseProgramFrame(wx.Frame): + """ + A frame to display and change all the parameters of a program. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore + close_callback : callable + """ default_title = 'Pulse program' def __init__(self, parent, global_store, close_callback, *args, **kwargs): @@ -723,11 +974,25 @@ def __init__(self, parent, global_store, close_callback, *args, **kwargs): self.load_program(self.global_store.pulse_program) def load_program(self, prog): + """ + Load a pulse program. + + Parameters + ---------- + prog : Program + """ self.Title = '{0} - {1}'.format(prog.filename, self.default_title) self.pulse_panel.OnOpen(prog) def OnMenuFileOpen(self, evt=None): + """ + Open a pulse program. + + Parameters + ---------- + evt : wx.Event, optional + """ wildcard = determine_wildcard('pulse', 'Pulse program') dlg = wx.FileDialog(parent=self, message='Load...', wildcard=wildcard, style=wx.FD_OPEN) @@ -750,6 +1015,13 @@ def OnMenuFileOpen(self, evt=None): self.global_store.pulse_program = prog def OnMenuFileClose(self, evt=None): + """ + Close the current program. + + Parameters + ---------- + evt : wx.CommandEvent, optional + """ if self.global_store.pulse_program is None: return diff --git a/spacq/gui/config/scaling.py b/spacq/gui/config/scaling.py index c7943f6..940f093 100644 --- a/spacq/gui/config/scaling.py +++ b/spacq/gui/config/scaling.py @@ -24,6 +24,14 @@ def __init__(self): def transform(self, x): """ Perform a transform according to the scaling. + + Parameters + ---------- + x : float or Quantity + + Returns + ------- + Quantity """ if self.offset == 0: @@ -35,6 +43,15 @@ def transform(self, x): class ScalingSettingsDialog(Dialog): + """ + A dialog for setting scaling parameters. + + Parameters + ---------- + parent : wx.Window + ok_callback : function + Called when the OK button is pressed. + """ def __init__(self, parent, ok_callback, *args, **kwargs): Dialog.__init__(self, parent, title='Scaling settings') @@ -82,6 +99,13 @@ def __init__(self, parent, ok_callback, *args, **kwargs): self.SetSizerAndFit(dialog_box) def GetValue(self): + """ + Get the value of the scaling settings. + + Returns + ------- + ScalingSettings + """ result = ScalingSettings() result.linear_scale = self.linear_scale_input.GetValue() @@ -91,6 +115,13 @@ def GetValue(self): return result def SetValue(self, value): + """ + Set the value of the scaling settings. + + Parameters + ---------- + value : ScalingSettings + """ self.linear_scale_input.SetValue(value.linear_scale) self.exponential_scale_input.SetValue(value.exponential_scale) self.offset_input.SetValue(value.offset) diff --git a/spacq/gui/config/variables.py b/spacq/gui/config/variables.py index 0782782..5b7435c 100755 --- a/spacq/gui/config/variables.py +++ b/spacq/gui/config/variables.py @@ -17,6 +17,12 @@ class VariableColumnDefn(ObjectListView.ColumnDefn): """ A column with useful defaults. + + Parameters + ---------- + width : int, optional + align : str, optional + groupKeyGetter : str, optional """ def __init__(self, width=90, align='centre', groupKeyGetter='order', *args, **kwargs): @@ -29,6 +35,13 @@ def __init__(self, width=90, align='centre', groupKeyGetter='order', *args, **kw class LinSpaceConfigPanel(wx.Panel): + """ + A panel for editing a Variable object. + + Parameters + ---------- + parent : wx.Window + """ def __init__(self, parent, *args, **kwargs): wx.Panel.__init__(self, parent, *args, **kwargs) @@ -61,6 +74,13 @@ def __init__(self, parent, *args, **kwargs): self.SetSizerAndFit(panel_box) def GetValue(self): + """ + Get the values from the input. + + Returns + ------- + LinSpaceConfig + """ # Ensure the values are sane. try: initial = float(self.initial_input.Value) @@ -80,6 +100,13 @@ def SetValue(self, config): class ArbitraryConfigPanel(wx.Panel): + """ + A panel for editing a Variable object. + + Parameters + ---------- + parent : wx.Window + """ def __init__(self, parent, *args, **kwargs): wx.Panel.__init__(self, parent, *args, **kwargs) @@ -100,6 +127,13 @@ def __init__(self, parent, *args, **kwargs): self.SetSizerAndFit(panel_box) def GetValue(self): + """ + Get the values from the input. + + Returns + ------- + ArbitraryConfig + """ raw_values = self.values_input.Value.split(',') # Ensure the values are sane. @@ -118,6 +152,13 @@ def SetValue(self, config): class FileConfigPanel(wx.Panel): + """ + A panel for editing a Variable object. + + Parameters + ---------- + parent : wx.Window + """ def __init__(self, parent, *args, **kwargs): wx.Panel.__init__(self, parent, *args, **kwargs) @@ -173,6 +214,13 @@ def __init__(self, parent, *args, **kwargs): # TODO: return to finishing this up or what not # From math_setup for data explorer function for callback def OnAxisSelection(self, evt=None): + """ + Callback for when a variable is selected from the list. + + Parameters + ---------- + evt : wx.Event, optional + """ # Get what list index was selected if self.variable_list.Selection == wx.NOT_FOUND: resultIndex = None @@ -199,6 +247,13 @@ def OnAxisSelection(self, evt=None): # loads csv and adds headers and data to self.object def OnMenuFileOpen(self, evt=None): + """ + Load a CSV file. + + Parameters + ---------- + evt : wx.Event, optional + """ try: result = load_csv(self.parent) except IOError as e: @@ -233,6 +288,13 @@ def OnMenuFileOpen(self, evt=None): # Regular Get and Set that finally set variables def GetValue(self): + """ + Get the current configuration. + + Returns + ------- + ArbitraryConfig + """ raw_values = self.values_input # Ensure the values are sane. @@ -249,6 +311,14 @@ def SetValue(self, config): class ConditionEditor(Dialog): + """ + Dialog for editing a condition. + + Parameters + ---------- + parent : wx.Window + ok_callback : callable + """ def __init__(self, parent, ok_callback, *args, **kwargs): kwargs['style'] = kwargs.get( 'style', wx.DEFAULT_DIALOG_STYLE) | wx.RESIZE_BORDER @@ -344,6 +414,13 @@ def OnOk(self, evt=None): self.Destroy() def SetValue(self, condition): + """ + Sets the values of the editor to match the given Condition. + + Parameters + ---------- + condition : Condition + """ self.arg_type_setters[0][condition.type1].Value = True self.arg_type_setters[1][condition.type2].Value = True self.args[0].Value = str(condition.arg1) @@ -351,6 +428,13 @@ def SetValue(self, condition): self.op_menu.SetStringSelection(condition.op_symbol) def GetValue(self): + """ + Returns a Condition object. + + Returns + ------- + Condition + """ cond_args = [] arg_types = [] for i, type in enumerate(self.arg_type_setters): @@ -378,6 +462,14 @@ def GetValue(self): class ConditionVariableEditor(Dialog): + """ + A dialog for editing a condition variable. + + Parameters + ---------- + parent : wx.Window + ok_callback : function + """ col_conditions = VariableColumnDefn(title='Condition', valueGetter=lambda x: str(x), isSpaceFilling=True, align='left') @@ -433,6 +525,13 @@ def __init__(self, parent, ok_callback, *args, **kwargs): self.SetSizerAndFit(dialog_box) def GetValue(self): + """ + Get the resource_names and conditions from the listctrl + + Returns + ------- + (list of str, list of Condition) + """ conditions = self.condition_olv.GetObjects() # Get the resource_names from the conditions. @@ -456,6 +555,10 @@ def OnOk(self, evt=None): def OnAddCondition(self, evt=None): """ Add a condition to the listctrl + + Parameters + ---------- + evt : wx.Event, optional """ def ok_callback(dlg): @@ -476,6 +579,10 @@ def ok_callback(dlg): def OnRemoveConditions(self, evt=None): """ Remove all selected conditions from the OLV. + + Parameters + ---------- + evt : wx.Event, optional """ selected = self.condition_olv.GetSelectedObjects() @@ -484,6 +591,13 @@ def OnRemoveConditions(self, evt=None): self.condition_olv.RemoveObjects(selected) def OnCellEditStarting(self, evt): + """ + Start up the condition editor when a cell is double clicked. + + Parameters + ---------- + evt : wx.Event + """ condition = evt.rowModel # Ignore frivolous requests. @@ -514,6 +628,14 @@ def ok_callback(dlg): class OutputVariableEditor(Dialog): + """ + Dialog for editing an output variable. + + Parameters + ---------- + parent : wx.Window + ok_callback : callable + """ def __init__(self, parent, ok_callback, *args, **kwargs): kwargs['style'] = kwargs.get( 'style', wx.DEFAULT_DIALOG_STYLE) | wx.RESIZE_BORDER @@ -607,6 +729,15 @@ def __init__(self, parent, ok_callback, *args, **kwargs): self.SetSizerAndFit(dialog_box) def GetValue(self): + """ + Get the value of the editor. + + Returns + ------- + (Config, int, bool, bool, bool, str, str) + (config, smooth_steps, smooth_from, smooth_to, smooth_transition, type, units) + + """ if self.type_float.Value: type = 'float' units = None @@ -625,6 +756,23 @@ def GetValue(self): self.smooth_transition_checkbox.Value, type, units) def SetValue(self, config, smooth_steps, smooth_from, smooth_to, smooth_transition, type, units): + """ + Set the value of the editor. + + Parameters + ---------- + config : Config + smooth_steps : int + the number of steps to smooth over + smooth_from : bool + whether to smooth from a constant + smooth_to : bool + whether to smooth to a constant + smooth_transition : bool + whether to smooth the transition + type : str + units : str + """ config_type = self.config_panel_types.index(config.__class__) self.config_notebook.ChangeSelection(config_type) self.config_notebook.CurrentPage.SetValue(config) @@ -647,6 +795,14 @@ def OnOk(self, evt=None): class VariablesPanel(wx.Panel): + """ + Panel for editing variables. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore + """ col_name = VariableColumnDefn(checkStateGetter='enabled', title='Name', valueGetter='name', width=150, align='left') col_order = VariableColumnDefn(title='#', valueGetter='order', width=40) @@ -719,6 +875,10 @@ def __init__(self, parent, global_store, *args, **kwargs): def max_order(self): """ Find the highest-used order in the OLV. + + Returns + ------- + int """ try: @@ -727,6 +887,14 @@ def max_order(self): return 0 def OnCellEditStarting(self, evt): + """ + Handle the start of a cell edit. + + Parameters + ---------- + evt : wx.Event + + """ col = evt.objectListView.columns[evt.subItemIndex] var = evt.rowModel @@ -769,6 +937,13 @@ def ok_callback(dlg): evt.Veto() def OnCellEditFinishing(self, evt): + """ + Handles the editing of cells in a table. + + Parameters + ---------- + evt : wx.Event + """ col = evt.objectListView.columns[evt.subItemIndex] if col == self.col_name: @@ -804,6 +979,13 @@ def OnCellEditFinishing(self, evt): pass # Assumed not an int was given in this cell def OnCellEditFinished(self, evt): + """ + Update the OLV after a cell edit. + + Parameters + ---------- + evt : wx.Event + """ col = evt.objectListView.columns[evt.subItemIndex] if col == self.col_order: @@ -813,6 +995,10 @@ def OnCellEditFinished(self, evt): def OnSave(self, evt=None): """ Save all the rows in the OLV. + + Parameters + ---------- + evt : wx.Event, optional """ try: @@ -825,6 +1011,10 @@ def OnSave(self, evt=None): def OnLoad(self, evt=None): """ Load some rows to the OLV. + + Parameters + ---------- + evt : wx.Event, optional """ try: @@ -856,6 +1046,10 @@ def OnLoad(self, evt=None): def OnAddVariable(self, evt=None): """ Add a blank variable to the OLV. + + Parameters + ---------- + evt : wx.Event, optional """ # Ensure that we get a unique name. @@ -882,6 +1076,10 @@ def OnAddVariable(self, evt=None): def OnAddConditionVariable(self, evt=None): """ Add a blank conditional variable to the OLV. + + Parameters + ---------- + evt : wx.Event, optional """ with self.global_store.variables.lock: @@ -907,6 +1105,10 @@ def OnAddConditionVariable(self, evt=None): def OnRemoveVariables(self, evt=None): """ Remove all selected variables from the OLV. + + Parameters + ---------- + evt : wx.Event, optional """ selected = self.olv.GetSelectedObjects() @@ -925,6 +1127,12 @@ class GuiVariable(object): describing how the values should be edited. If the variable doesn't have the attribute, then this class creates that attribute and assigns it a value of 'N/A'. + + Parameters + ---------- + var : Variable + vartype : str + 'condition' or 'output' """ def __init__(self, var, vartype): diff --git a/spacq/gui/config/virtual_variables.py b/spacq/gui/config/virtual_variables.py index 5a54bfb..3c711ff 100644 --- a/spacq/gui/config/virtual_variables.py +++ b/spacq/gui/config/virtual_variables.py @@ -5,7 +5,17 @@ An interface for defining virtual swept variables and writing to real resources. """ +# The `MultipleVariableConfigPanel` class is a panel that allows the user to configure multiple +# virtual variables by specifying their names, initial values, final values, step sizes, and orders. class MultipleVariableConfigPanel(scrolled.ScrolledPanel): + """ + A panel that allows the user to configure multiple virtual variables by specifying their names, + initial values, final values, step sizes, and orders. + + Parameters + ---------- + parent : wx.Window + """ def __init__(self, parent, *args, **kwargs): scrolled.ScrolledPanel.__init__(self, parent, -1, style=wx.HSCROLL, *args, **kwargs) @@ -83,6 +93,13 @@ def __init__(self, parent, *args, **kwargs): self.SetupScrolling(scroll_y = False) def OnUpdate(self, evt=None): + """ + Adds or removes text controls based on the value of EnableCount. + + Parameters + ---------- + evt : wx.Event, optional + """ EnableCount = self.var_count.Value # Adding more than initially setup with @@ -126,6 +143,14 @@ def OnUpdate(self, evt=None): # self.SetSizerAndFit(self.panel_box) def GetValue(self): + """ + Returns the values of the variables as lists. + + Returns + ------- + (list of str, list of float, list of float, list of float, list of int) + (names, starts, ends, steps, orders) + """ try: starts = [float(x.Value) for x in self.start_value] except ValueError: @@ -140,26 +165,15 @@ def GetValue(self): orders = [x.Value for x in self.order_value] return names, starts, ends, steps, orders - - - def GetValue(self): - try: - starts = [float(x.Value) for x in self.start_value] - except ValueError: - raise ValueError('Invalid initial value.') - try: - ends = [float(x.Value) for x in self.end_value] - except ValueError: - raise ValueError('Invalid initial value.') - - names = [x.Value for x in self.name_value] - steps = [x.Value for x in self.step_value] - orders = [x.Value for x in self.order_value] - - return names, starts, ends, steps, orders - - + class DependentVariableConfigPanel(scrolled.ScrolledPanel): + """ + A panel for configuring the dependent variables. + + Parameters + ---------- + parent : wx.Window + """ def __init__(self, parent, *args, **kwargs): scrolled.ScrolledPanel.__init__(self, parent, -1, style=wx.VSCROLL, *args, **kwargs) @@ -219,6 +233,13 @@ def __init__(self, parent, *args, **kwargs): self.SetupScrolling(scroll_x = False) def OnUpdate(self, evt=None): + """ + Adds entries to a list based on the value of `EnableCount` and updates the layout of the GUI. + + Parameters + ---------- + evt : wx.Event, optional + """ EnableCount = self.dependent_count.Value # Add entries to store @@ -261,6 +282,14 @@ def OnUpdate(self, evt=None): self.enable[i] = False def GetValue(self): + """ + Returns the values of the dependent variables + + Returns + ------- + (list of str, list of str) + (names, expressions) + """ names = [x.Value for x in self.name_value] expressions = [x.Value for x in self.expression_value] diff --git a/spacq/gui/display/plot/colormapped.py b/spacq/gui/display/plot/colormapped.py index bc3baa4..011355f 100644 --- a/spacq/gui/display/plot/colormapped.py +++ b/spacq/gui/display/plot/colormapped.py @@ -12,6 +12,12 @@ class ColormappedPlot(ChacoPlot): """ A colormapped plot. + + Parameters + ---------- + parent : wx.Window + x_bounds : tuple + y_bounds : tuple """ def __init__(self, parent, x_bounds, y_bounds, *args, **kwargs): @@ -30,6 +36,10 @@ def __init__(self, parent, x_bounds, y_bounds, *args, **kwargs): def plot_obj(self): """ The actual plot object. + + Returns + ------- + chaco.api.Plot """ return list(self.plots.values())[0][0] @@ -67,6 +77,10 @@ def control(self): def color_data(self): """ Plotted values. + + Returns + ------- + numpy.ndarray """ return self.data.get_data('color') @@ -79,6 +93,10 @@ def color_data(self, values): def low_setting(self): """ Lowest color value. + + Returns + ------- + float """ return self.plot_obj.color_mapper.range.low @@ -91,6 +109,10 @@ def low_setting(self, value): def high_setting(self): """ Highest color value. + + Returns + ------- + float """ return self.plot_obj.color_mapper.range.high diff --git a/spacq/gui/display/plot/live/list.py b/spacq/gui/display/plot/live/list.py index 46d71c0..813926c 100644 --- a/spacq/gui/display/plot/live/list.py +++ b/spacq/gui/display/plot/live/list.py @@ -43,6 +43,11 @@ def __init__(self): class PlotSettingsDialog(Dialog): """ Set up the live view plot. + + Parameters + ---------- + parent : wx.Window + ok_callback : function """ def __init__(self, parent, ok_callback, *args, **kwargs): @@ -90,6 +95,13 @@ def OnOk(self, evt=None): self.Destroy() def GetValue(self): + """ + Return the current settings. + + Returns + ------- + PlotSettings + """ plot_settings = PlotSettings() plot_settings.enabled = self.enabled_checkbox.Value plot_settings.delay = Quantity(self.delay_input.GetValue(), 's') @@ -104,6 +116,11 @@ def SetValue(self, plot_settings): class ListLiveViewPanel(wx.Panel): """ A panel to display a live view plot of a list resource. + + Parameters + ---------- + parent : wx object + global_store : dict """ def __init__(self, parent, global_store, *args, **kwargs): @@ -214,6 +231,13 @@ def resource(self): @resource.setter def resource(self, value): + """ + Set the resource to acquire from. + + Parameters + ---------- + value : Resource + """ # Ignore unreadable resources. if value is not None and not value.readable: value = None @@ -235,6 +259,13 @@ def resource(self, value): @property def measurement_resource_name(self): + """ + Get the measurement resource name. + + Returns + ------- + str + """ if self._measurement_resource_name is None: return '' else: @@ -242,6 +273,13 @@ def measurement_resource_name(self): @measurement_resource_name.setter def measurement_resource_name(self, value): + """ + Set the measurement resource name. + + Parameters + ---------- + value : str + """ if value: self._measurement_resource_name = value try: @@ -283,6 +321,10 @@ def update_plot(self): def add_values(self, values): """ Update the plot with a new list of values. + + Parameters + ---------- + values : list of (float, float) """ if not self.plot_settings.enabled: @@ -321,6 +363,10 @@ def close(self): def onSave(self, evt=None): """ save the latest trace to a manually named csv + + Parameters + ---------- + evt : wx.Event, optional """ outArray = numpy.column_stack((self._times,self._values)) @@ -335,6 +381,10 @@ def onSave(self, evt=None): def OnRun(self, evt=None): """ Let the acquisition thread run. + + Parameters + ---------- + evt : wx.Event, optional """ self.run_button.Disable() @@ -349,6 +399,10 @@ def OnRun(self, evt=None): def OnPause(self, evt=None): """ Block the acquisition thread. + + Parameters + ---------- + evt : wx.Event, optional """ if not self.running: @@ -367,6 +421,10 @@ def OnReset(self, evt=None): def OnPlotSettings(self, evt=None): """ Open the plot settings dialog. + + Parameters + ---------- + evt : wx.Event, optional """ def ok_callback(dlg): @@ -381,22 +439,51 @@ def msg_resource(self, name, value=None): self.resource = value def msg_data_capture_start(self, name): + """ + Start capturing data. + + Parameters + ---------- + name : str + """ if name == self.measurement_resource_name: if self.enabled: self.capturing_data = True def msg_data_capture_data(self, name, value): + """ + Add data to the plot. + + Parameters + ---------- + name : str + value : list of (float, float) tuples + """ if name == self.measurement_resource_name: if self.capturing_data: self.add_values(value) def msg_data_capture_stop(self, name): + """ + Stop capturing data. + + Parameters + ---------- + name : str""" if name == self.measurement_resource_name: if self.capturing_data: self.capturing_data = False class ListMeasurementFrame(wx.Frame): + """ + Frame for the list measurement. + + Parameters + ---------- + parent : wx.Window + global_store : dict + """ def __init__(self, parent, global_store, *args, **kwargs): wx.Frame.__init__(self, parent, *args, **kwargs) @@ -417,6 +504,13 @@ def __init__(self, parent, global_store, *args, **kwargs): self.Bind(wx.EVT_CLOSE, self.OnClose) def OnClose(self, evt): + """ + Perform cleanup. + + Parameters + ---------- + evt : wx.Event + """ if self.live_view_panel.capturing_data: msg = 'Cannot close, as a sweep is currently in progress.' MessageDialog(self, msg, 'Sweep in progress').Show() diff --git a/spacq/gui/display/plot/live/list_3d.py b/spacq/gui/display/plot/live/list_3d.py index d876c4b..4f7c1e6 100644 --- a/spacq/gui/display/plot/live/list_3d.py +++ b/spacq/gui/display/plot/live/list_3d.py @@ -33,6 +33,11 @@ def __init__(self): class PlotSettingsDialog(Dialog): """ Set up the live view plot. + + Parameters + ---------- + parent : wx.Window + ok_callback : function """ def __init__(self, parent, ok_callback, *args, **kwargs): @@ -80,6 +85,13 @@ def OnOk(self, evt=None): self.Destroy() def GetValue(self): + """ + Get the settings from the dialog. + + Returns + ------- + PlotSettings + """ plot_settings = PlotSettings() plot_settings.enabled = self.enabled_checkbox.Value plot_settings.num_lines = self.lines_input.Value @@ -94,6 +106,11 @@ def SetValue(self, plot_settings): class ListLiveViewPanel(wx.Panel): """ A panel to display a live view plot of a list resource. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore """ def __init__(self, parent, global_store, *args, **kwargs): @@ -159,6 +176,13 @@ def __init__(self, parent, global_store, *args, **kwargs): @property def measurement_resource_name(self): + """ + Get the measurement resource name. + + Returns + ------- + str + """ if self._measurement_resource_name is None: return '' else: @@ -166,6 +190,13 @@ def measurement_resource_name(self): @measurement_resource_name.setter def measurement_resource_name(self, value): + """ + Set the measurement resource name. + + Parameters + ---------- + value : str + """ if value: self._measurement_resource_name = value try: @@ -201,6 +232,10 @@ def update_plot(self): def add_values(self, values): """ Update the plot with a new list of values. + + Parameters + ---------- + values : list of (float, float) """ if not self.plot_settings.enabled: @@ -252,6 +287,10 @@ def OnReset(self, evt=None): def OnPlotSettings(self, evt=None): """ Open the plot settings dialog. + + Parameters + ---------- + evt : wx.Event, optional """ def ok_callback(dlg): @@ -262,22 +301,52 @@ def ok_callback(dlg): dlg.Show() def msg_data_capture_start(self, name): + """ + Start capturing data. + + Parameters + ---------- + name : str + """ if name == self.measurement_resource_name: if self.enabled: self.capturing_data = True def msg_data_capture_data(self, name, value): + """ + Captures data values for a specific measurement resource name if data capturing is enabled. + + Parameters + ---------- + name : str + value : list + """ if name == self.measurement_resource_name: if self.capturing_data: self.add_values(value) def msg_data_capture_stop(self, name): + """ + Stop capturing data. + + Parameters + ---------- + name : str + """ if name == self.measurement_resource_name: if self.capturing_data: self.capturing_data = False class ListMeasurementFrame(wx.Frame): + """ + Frame for a list measurement. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore + """ def __init__(self, parent, global_store, *args, **kwargs): wx.Frame.__init__(self, parent, *args, **kwargs) @@ -298,6 +367,13 @@ def __init__(self, parent, global_store, *args, **kwargs): self.Bind(wx.EVT_CLOSE, self.OnClose) def OnClose(self, evt): + """ + Close the frame. + + Parameters + ---------- + evt : wx.Event + """ if self.live_view_panel.capturing_data: msg = 'Cannot close, as a sweep is currently in progress.' MessageDialog(self, msg, 'Sweep in progress').Show() diff --git a/spacq/gui/display/plot/live/scalar.py b/spacq/gui/display/plot/live/scalar.py index a6fed3a..fc593ff 100755 --- a/spacq/gui/display/plot/live/scalar.py +++ b/spacq/gui/display/plot/live/scalar.py @@ -50,6 +50,11 @@ def __init__(self): class PlotSettingsDialog(Dialog): """ Set up the live view plot. + + Parameters + ---------- + parent : wx.Window + ok_callback : callable """ def __init__(self, parent, ok_callback, *args, **kwargs): @@ -162,6 +167,12 @@ def OnOk(self, evt=None): self.Destroy() def GetValue(self): + """ + Get the values of the controls in the dialog. + + Returns + ------- + PlotSettings""" plot_settings = PlotSettings() plot_settings.enabled = self.enabled_checkbox.Value plot_settings.num_points = self.points_input.Value @@ -177,6 +188,13 @@ def GetValue(self): return plot_settings def SetValue(self, plot_settings): + """ + Set the values of the controls in the dialog to the values in the plot settings object. + + Parameters + ---------- + plot_settings : PlotSettings + """ self.enabled_checkbox.Value = plot_settings.enabled self.points_input.Value = plot_settings.num_points self.delay_input.SetValue(plot_settings.delay.value) @@ -192,6 +210,11 @@ def SetValue(self, plot_settings): class ScalarLiveViewPanel(wx.Panel): """ A panel to display a live view plot of a scalar resource. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore """ def __init__(self, parent, global_store, *args, **kwargs): @@ -297,6 +320,13 @@ def resource(self): @resource.setter def resource(self, value): + """ + Set the resource to acquire from. + + Parameters + ---------- + value : Resource + """ # Ignore unreadable resources. if value is not None and not value.readable: value = None @@ -318,6 +348,13 @@ def resource(self, value): @property def measurement_resource_name(self): + """ + Get the measurement resource name. + + Returns + ------- + str + """ if self._measurement_resource_name is None: return '' else: @@ -325,6 +362,13 @@ def measurement_resource_name(self): @measurement_resource_name.setter def measurement_resource_name(self, value): + """ + Set the measurement resource name. + + Parameters + ---------- + value : str + """ if value: self._measurement_resource_name = value try: @@ -387,6 +431,10 @@ def update_plot(self): def add_value(self, value): """ Update the plot with a new value. + + Parameters + ---------- + value : float """ if not self.plot_settings.enabled: @@ -449,6 +497,10 @@ def close(self): def OnRun(self, evt=None): """ Let the acquisition thread run. + + Parameters + ---------- + evt : wx.Event, optional """ self.run_button.Disable() @@ -463,6 +515,10 @@ def OnRun(self, evt=None): def OnPause(self, evt=None): """ Block the acquisition thread. + + Parameters + ---------- + evt : wx.Event, optional """ if not self.running: @@ -481,6 +537,10 @@ def OnReset(self, evt=None): def OnPlotSettings(self, evt=None): """ Open the plot settings dialog. + + Parameters + ---------- + evt : wx.Event, optional """ def ok_callback(dlg): @@ -525,6 +585,13 @@ def msg_resource(self, name, value=None): self.resource = value def msg_data_capture_start(self, name): + """ + Start capturing data. + + Parameters + ---------- + name : str + """ if name == self.measurement_resource_name: if self.enabled: self.capturing_data = True @@ -537,11 +604,26 @@ def msg_data_capture_start(self, name): self.resource = None def msg_data_capture_data(self, name, value): + """ + Handle new data from the data capture system. + + Parameters + ---------- + name : str + value : float + """ if name == self.measurement_resource_name: if self.capturing_data: self.add_value(value) def msg_data_capture_stop(self, name): + """ + Stop capturing data. + + Parameters + ---------- + name : str + """ if name == self.measurement_resource_name: if self.capturing_data: self.capturing_data = False @@ -555,6 +637,14 @@ def msg_data_capture_stop(self, name): class ScalarMeasurementFrame(wx.Frame): + """ + Frame for scalar measurements. + + Parameters + ---------- + parent : wx.Window + global_store : GlobalStore + """ def __init__(self, parent, global_store, *args, **kwargs): wx.Frame.__init__(self, parent, *args, **kwargs) @@ -575,6 +665,13 @@ def __init__(self, parent, global_store, *args, **kwargs): self.Bind(wx.EVT_CLOSE, self.OnClose) def OnClose(self, evt): + """ + Perform cleanup. + + Parameters + ---------- + evt : wx.Event + """ if self.live_view_panel.capturing_data: msg = 'Cannot close, as a sweep is currently in progress.' MessageDialog(self, msg, 'Sweep in progress').Show() diff --git a/spacq/gui/display/plot/plotmath/derivative.py b/spacq/gui/display/plot/plotmath/derivative.py index b5d77e0..a8b8952 100644 --- a/spacq/gui/display/plot/plotmath/derivative.py +++ b/spacq/gui/display/plot/plotmath/derivative.py @@ -3,6 +3,15 @@ from numpy import concatenate class DerivativeMathSetupDialog(MathSetupDialog_Derivative): + """ + Dialog for setting up a derivative plot. + + Parameters + ---------- + parent : wx.Window + headings : list of str + data : numpy.ndarray + """ dheading = [] ddata = [] diff --git a/spacq/gui/display/plot/plotmath/function.py b/spacq/gui/display/plot/plotmath/function.py index 2ae7ae3..c1568ea 100644 --- a/spacq/gui/display/plot/plotmath/function.py +++ b/spacq/gui/display/plot/plotmath/function.py @@ -5,6 +5,15 @@ from numpy import * class FunctionMathSetupDialog(MathSetupDialog_Function): + """ + A dialog for setting up a function of one variable. + + Parameters + ---------- + parent : wx.Window + headings : list of str + data : numpy.ndarray + """ dheading = [] ddata = [] @@ -33,6 +42,15 @@ def calculate(self): class FunctionMathSetupDialog2arg(MathSetupDialog_Function): + """ + A dialog for setting up a function of two variables. + + Parameters + ---------- + parent : wx.Window + headings : list of str + data : numpy.ndarray + """ dheading = [] ddata = [] diff --git a/spacq/gui/display/plot/static/colormapped.py b/spacq/gui/display/plot/static/colormapped.py index bfac12c..9e069df 100644 --- a/spacq/gui/display/plot/static/colormapped.py +++ b/spacq/gui/display/plot/static/colormapped.py @@ -7,6 +7,19 @@ from .common.plot_setup import PlotSetupDialog class ColormappedPlotPanel(wx.Panel): + """ + Panel for a colormapped plot. + + Parameters + ---------- + parent : wx.Window + color_data : numpy.ndarray + The data to be plotted. + x_bounds : tuple of float + y_bounds : tuple of float + x_label : str + y_label : str + """ def __init__(self, parent, color_data, x_bounds, y_bounds, x_label, y_label, *args, **kwargs): wx.Panel.__init__(self, parent, *args, **kwargs) @@ -25,6 +38,19 @@ def __init__(self, parent, color_data, x_bounds, y_bounds, x_label, y_label, class ColormappedPlotFrame(wx.Frame): + """ + Frame for a colormapped plot. + + Parameters + ---------- + parent : wx.Window + color_data : numpy.ndarray + The data to be plotted. + x_bounds : tuple of float + y_bounds : tuple of float + x_label : str + y_label : str + """ bounds_format = '{0:.4e}' def __init__(self, parent, color_data, x_bounds, y_bounds, x_label, y_label, @@ -64,6 +90,13 @@ def __init__(self, parent, color_data, x_bounds, y_bounds, x_label, y_label, self.SetSizerAndFit(frame_box) def OnMinValue(self, evt=None): + """ + Handle the user entering a new minimum value. + + Parameters + ---------- + evt : wx.Event, optional + """ value = self.minimum_value_input.Value try: value = float(value) @@ -77,6 +110,13 @@ def OnMinValue(self, evt=None): self.minimum_value_input.Value = self.bounds_format.format(self.panel.plot.low_setting) def OnMaxValue(self, evt=None): + """ + Handle the user entering a new maximum value. + + Parameters + ---------- + evt : wx.Event, optional + """ value = self.maximum_value_input.Value try: value = float(value) @@ -91,6 +131,16 @@ def OnMaxValue(self, evt=None): class ColormappedPlotSetupDialog(PlotSetupDialog): + """ + Dialog for setting up a colormapped plot. + + Parameters + ---------- + parent : wx.Window + headings : list of str + The headings of the data columns. + data : numpy.ndarray + """ def __init__(self, parent, headings, data, *args, **kwargs): #Limit the number of grid points on each axis: self.max_mesh = [401, 401] #default value passed to parent constructor. Pass [-1,-1] to remove feature from all colorplots @@ -102,6 +152,14 @@ def __init__(self, parent, headings, data, *args, **kwargs): self.data = data def make_plot(self): + """ + Make the plot. + + Returns + ------- + bool + True if the plot was made, False otherwise. + """ try: x_data, y_data, z_data = [self.data[:,axis].astype(float) for axis in self.axes] except ValueError as e: diff --git a/spacq/gui/display/plot/static/surface.py b/spacq/gui/display/plot/static/surface.py index 03847f2..acb4cf0 100644 --- a/spacq/gui/display/plot/static/surface.py +++ b/spacq/gui/display/plot/static/surface.py @@ -10,6 +10,21 @@ class SurfacePlotPanel(wx.Panel): + """ + Plot a surface. + + Parameters + ---------- + parent : wx.Window + surface_data : numpy.ndarray + x_bounds : tuple of float + y_bounds : tuple of float + x_label : str + y_label : str + z_label : str + style : str + 'surface' or 'waveform' + """ def __init__(self, parent, surface_data, x_bounds, y_bounds, x_label, y_label, z_label, style, *args, **kwargs): wx.Panel.__init__(self, parent, *args, **kwargs) @@ -28,6 +43,20 @@ def __init__(self, parent, surface_data, x_bounds, y_bounds, x_label, y_label, z class SurfacePlotFrame(wx.Frame): + """ + Plot a surface. + + Parameters + ---------- + parent : wx.Window + surface_data : tuple of (numpy.ndarray, tuple of float, tuple of float) + a tuple of (z, x_bounds, y_bounds) + x_label : str + y_label : str + z_label : str + style : str + 'surface' or 'waveform' + """ def __init__(self, parent, surface_data, x_bounds, y_bounds, x_label, y_label, z_label, style, *args, **kwargs): wx.Frame.__init__(self, parent, *args, **kwargs) @@ -51,6 +80,15 @@ def OnClose(self, evt): class SurfacePlotSetupDialog(PlotSetupDialog): + """ + Plot a surface. + + Parameters + ---------- + parent : wx.Window + headings : list of str + data : numpy.ndarray + """ def __init__(self, parent, headings, data, *args, **kwargs): PlotSetupDialog.__init__(self, parent, headings, ['x', 'y', 'z'], *args, **kwargs) @@ -60,6 +98,14 @@ def __init__(self, parent, headings, data, *args, **kwargs): self.data = data def make_plot(self): + """ + Plot a surface. + + Returns + ------- + bool + Whether the plot was successful. + """ try: x_data, y_data, z_data = [self.data[:,axis].astype(float) for axis in self.axes] except ValueError as e: @@ -83,6 +129,15 @@ def make_plot(self): class WaveformsPlotSetupDialog(PlotSetupDialog): + """ + Plot a surface of waveforms. + + Parameters + ---------- + parent : wx.Window + headings : list of str + data : numpy.ndarray + """ def __init__(self, parent, headings, data, *args, **kwargs): PlotSetupDialog.__init__(self, parent, headings, ['z'], *args, **kwargs) @@ -92,6 +147,14 @@ def __init__(self, parent, headings, data, *args, **kwargs): self.data = data def make_plot(self): + """ + Plot a surface of waveforms. + + Returns + ------- + bool + Whether the plot was successful. + """ axis = self.axes[0] lp = ListParser() diff --git a/spacq/gui/display/plot/static/two_dimensional.py b/spacq/gui/display/plot/static/two_dimensional.py index a662953..2849d74 100644 --- a/spacq/gui/display/plot/static/two_dimensional.py +++ b/spacq/gui/display/plot/static/two_dimensional.py @@ -6,6 +6,17 @@ class TwoDimensionalPlotPanel(wx.Panel): + """ + Panel for a two-dimensional plot. + + Parameters + ---------- + parent : wx.Window + x_data : numpy.ndarray + y_data : numpy.ndarray + x_label : str + y_label : str + """ def __init__(self, parent, x_data, y_data, x_label, y_label, *args, **kwargs): wx.Panel.__init__(self, parent, *args, **kwargs) @@ -23,6 +34,17 @@ def __init__(self, parent, x_data, y_data, x_label, y_label, *args, **kwargs): class TwoDimensionalPlotFrame(wx.Frame): + """ + Frame for a two-dimensional plot. + + Parameters + ---------- + parent : wx.Window + x_data : numpy.ndarray + y_data : numpy.ndarray + x_label : str + y_label : str + """ def __init__(self, parent, x_data, y_data, x_label, y_label, *args, **kwargs): wx.Frame.__init__(self, parent, *args, **kwargs) @@ -38,6 +60,15 @@ def __init__(self, parent, x_data, y_data, x_label, y_label, *args, **kwargs): class TwoDimensionalPlotSetupDialog(PlotSetupDialog): + """ + Dialog for setting up a two-dimensional plot. + + Parameters + ---------- + parent : wx.Window + headings : list of str + data : numpy.ndarray + """ def __init__(self, parent, headings, data, *args, **kwargs): PlotSetupDialog.__init__(self, parent, headings, ['x', 'y'], *args, **kwargs) @@ -47,6 +78,14 @@ def __init__(self, parent, headings, data, *args, **kwargs): self.data = data def make_plot(self): + """ + Make the plot. + + Returns + ------- + bool + True if the plot was made, False otherwise. + """ try: x_data, y_data = [self.data[:,axis].astype(float) for axis in self.axes] except ValueError as e: diff --git a/spacq/gui/display/plot/surface.py b/spacq/gui/display/plot/surface.py index 95ab462..6d808dd 100644 --- a/spacq/gui/display/plot/surface.py +++ b/spacq/gui/display/plot/surface.py @@ -12,6 +12,12 @@ class SurfacePlot(object): """ A surface plot. + + Parameters + ---------- + parent : wx.Window + style : str + 'surface' or 'waveform' """ alpha = 0.8 @@ -49,6 +55,11 @@ def close(self): def set_surface_data(self, data): """ Set the surface data based on the data tuple. + + Parameters + ---------- + data : tuple + (surface_data, x_bounds, y_bounds) """ if self.surface is not None: @@ -81,6 +92,10 @@ def set_surface_data(self, data): def x_label(self): """ The x axis label. + + Returns + ------- + str """ return self.axes.get_xlabel() @@ -92,6 +107,10 @@ def x_label(self, value): def y_label(self): """ The y axis label. + + Returns + ------- + str """ return self.axes.get_ylabel() @@ -103,6 +122,10 @@ def y_label(self, value): def z_label(self): """ The z axis label. + + Returns + ------- + str """ return self.axes.get_zlabel() diff --git a/spacq/gui/display/plot/two_dimensional.py b/spacq/gui/display/plot/two_dimensional.py index 3f5d4db..5e4cef2 100644 --- a/spacq/gui/display/plot/two_dimensional.py +++ b/spacq/gui/display/plot/two_dimensional.py @@ -12,6 +12,11 @@ class TwoDimensionalPlot(ChacoPlot): """ A 2D plot. + + Parameters + ---------- + parent : wx.Window + color : str, optional """ auto_color_idx = 0 diff --git a/spacq/gui/display/table/filter.py b/spacq/gui/display/table/filter.py index b27bec7..f32f9e3 100644 --- a/spacq/gui/display/table/filter.py +++ b/spacq/gui/display/table/filter.py @@ -9,6 +9,15 @@ class FilterEditDialog(Dialog): + """ + Dialog for editing a filter. + + Parameters + ---------- + parent : wx.Window + headings : list of str + ok_callback : function + """ def __init__(self, parent, headings, ok_callback, *args, **kwargs): kwargs['style'] = kwargs.get( 'style', wx.DEFAULT_DIALOG_STYLE) | wx.RESIZE_BORDER @@ -58,6 +67,13 @@ def SetValue(self, values): (self.column_input.StringSelection, self.function_input.Value) = values def OnOk(self, evt=None): + """ + Callback for the OK button. + + Parameters + ---------- + evt : wx.Event, optional + """ try: self.ok_callback(self) except ValueError as e: @@ -68,6 +84,19 @@ def OnOk(self, evt=None): class FilterListDialog(Dialog): + """ + Dialog for editing a list of filters. + + Parameters + ---------- + parent : wx.Window + table : Table + table to filter + close_callback : function + filters : dict, optional + filter_columns : dict, optional + If filters is not None, this must also be provided. + """ def __init__(self, parent, table, close_callback, filters=None, filter_columns=None, *args, **kwargs): kwargs['style'] = kwargs.get( @@ -113,6 +142,15 @@ def __init__(self, parent, table, close_callback, filters=None, filter_columns=N def create_filter(self, f_text, col): """ Create a filter out of text. + + Parameters + ---------- + f_text : str + col : str + + Returns + ------- + function """ col_idx = self.table.headings.index(col) @@ -123,6 +161,10 @@ def create_filter(self, f_text, col): def meta_filter(self): """ Create a meta-filter out of all the filters. + + Returns + ------- + function """ filters = [self.create_filter(f, col) for f, col in @@ -131,6 +173,15 @@ def meta_filter(self): return lambda i, x: all([f(i, x) for f in filters]) def edit_ok_callback(self, dlg, selection=None): + """ + Callback for the filter edit dialog. + + Parameters + ---------- + dlg : FilterEditDialog + selection : str, optional + If not None, the filter with this name will be removed. + """ col, f = dlg.GetValue() name = '{0}: {1}'.format(col, f) @@ -164,6 +215,13 @@ def OnAddFilter(self, evt=None): self.edit_ok_callback).Show() def OnEditFilter(self, evt=None): + """ + Edit a filter. + + Parameters + ---------- + evt : wx.Event, optional + """ selection = self.filter_list.StringSelection if not selection: @@ -175,6 +233,15 @@ def OnEditFilter(self, evt=None): dlg.Show() def OnRemoveFilter(self, evt=None, selection=None): + """ + Remove a filter. + + Parameters + ---------- + evt : wx.Event, optional + selection : str, optional + The filter to remove. + """ if selection is None: selection = self.filter_list.StringSelection diff --git a/spacq/gui/display/table/generic.py b/spacq/gui/display/table/generic.py index 7a2e3ac..efca942 100644 --- a/spacq/gui/display/table/generic.py +++ b/spacq/gui/display/table/generic.py @@ -23,6 +23,10 @@ def find_type(value): Determine the type of a column based on a single value. The type is one of: scalar, list, string. + + Parameters + ---------- + parent : wx.Window """ try: @@ -59,6 +63,13 @@ def reset(self): self.types = [] def refresh_with_values(self, data): + """ + Refresh the display with new data. + + Parameters + ---------- + data: A 2D NumPy array. + """ self.ItemCount = len(data) if self.ItemCount > 0: @@ -74,11 +85,15 @@ def apply_filter(self, f, afresh=False): """ Set the data to be the old data, along with the application of a filter. - f is a function of two parameters: the index of the row and the row itself. - f must return True if the row is to be kept and False otherwise. + Parameters + ---------- + f: A function of two parameters. + the index of the row and the row itself. + f must return True if the row is to be kept and False otherwise. - If afresh is True, all old filtered data is discarded. - Otherwise, a new filter can be quickly applied. + afresh: bool, optional + If True, all old filtered data is discarded. + Otherwise, a new filter can be quickly applied. """ if afresh: @@ -94,6 +109,19 @@ def apply_filter(self, f, afresh=False): self.refresh_with_values(self.filtered_data) def GetValue(self, types=None): + """ + Get the headings, data, and types. + + Parameters + ---------- + types: A list of strings, or None. + If None, all types are returned. + + Returns + ------- + (list of str, 2D NumPy array, list of str) + (headings, data, types) + """ # Get all types by default. if types is None: types = set(self.types) @@ -112,6 +140,10 @@ def GetValue(self, types=None): def SetValue(self, headings, data): """ + Set the headings and data to be displayed. + + Parameters + ---------- headings: A list of strings. data: A 2D NumPy array. """ @@ -138,6 +170,15 @@ def SetValue(self, headings, data): def OnGetItemText(self, item, col): """ Return cell value for LC_VIRTUAL. + + Parameters + ---------- + item : int + col : int + + Returns + ------- + str """ return self.display_data[item,col] @@ -146,6 +187,10 @@ def OnGetItemText(self, item, col): class TabularDisplayPanel(wx.Panel): """ A panel to display arbitrary tabular data. + + Parameters + ---------- + parent : wx.Window """ def __init__(self, parent, *args, **kwargs): @@ -168,7 +213,11 @@ def from_csv_data(self, has_header, values): """ Import the given CSV data into the table. - If has_header is True, the first row is treated specially. + Parameters + ---------- + has_header : bool + If True, the first row is treated specially. + values : list of lists """ if has_header: @@ -191,6 +240,13 @@ def SetValue(self, headings, values): class TabularDisplayFrame(wx.Frame): + """ + A frame to display arbitrary tabular data. + + Parameters + ---------- + parent : wx.Window + """ def __init__(self, parent, *args, **kwargs): wx.Frame.__init__(self, parent, *args, **kwargs) diff --git a/spacq/gui/display/waveform.py b/spacq/gui/display/waveform.py index cb8a327..8a27ddc 100644 --- a/spacq/gui/display/waveform.py +++ b/spacq/gui/display/waveform.py @@ -10,6 +10,13 @@ class WaveformDisplay(TwoDimensionalPlot): + """ + A plot for displaying a waveform. + + Parameters + ---------- + parent : wx.Window + """ marker_height = 50 def __init__(self, parent, *args, **kwargs): @@ -28,6 +35,14 @@ def control(self): return Window(self.parent, component=self.vplot_container).control def add_marker(self, num, data): + """ + Add a marker to the plot. + + Parameters + ---------- + num : int + data : array + """ marker_plot = TwoDimensionalPlot(self, height=self.marker_height, resizable='h') marker_plot.padding_left = self.padding_left @@ -42,6 +57,13 @@ def add_marker(self, num, data): class WaveformPanel(wx.Panel): + """ + A panel for displaying a waveform. + + Parameters + ---------- + parent : wx.Window + """ def __init__(self, parent, *args, **kwargs): wx.Panel.__init__(self, parent, *args, **kwargs) @@ -55,6 +77,16 @@ def __init__(self, parent, *args, **kwargs): self.SetSizer(panel_box) def SetValue(self, waveform, marker_data, frequency): + """ + Set the value of the waveform. + + Parameters + ---------- + waveform : array + marker_data : dict + Keys are marker numbers, values are arrays. + frequency : Quantity + """ max_time = len(waveform) / frequency.value # Find the order of magnitude (to within 3 orders, to keep it at n, u, m, etc). magnitude = 3 * floor(floor(log10(max_time)) / 3) @@ -72,6 +104,14 @@ def SetValue(self, waveform, marker_data, frequency): class WaveformFrame(wx.Frame): + """ + A frame for displaying a waveform. + + Parameters + ---------- + parent : wx.Window + output_name : str + """ def __init__(self, parent, output_name, *args, **kwargs): wx.Frame.__init__(self, parent, title=output_name, *args, **kwargs) diff --git a/spacq/gui/objectlistview/CellEditor.py b/spacq/gui/objectlistview/CellEditor.py index ca8b966..151ec52 100644 --- a/spacq/gui/objectlistview/CellEditor.py +++ b/spacq/gui/objectlistview/CellEditor.py @@ -68,6 +68,10 @@ def CellEditorRegistry(): """ Return the registry that is managing type to creator functions + + Returns + ------- + EditorRegistry """ global _cellEditorRegistrySingleton @@ -86,12 +90,10 @@ class EditorRegistry: """ def __init__(self): - self.typeToFunctionMap = {} # Standard types and their creator functions - self.typeToFunctionMap[str] = self._MakeStringEditor - self.typeToFunctionMap[six.text_type] = self._MakeStringEditor - self.typeToFunctionMap[bool] = self._MakeBoolEditor + self.typeToFunctionMap = {str: self._MakeStringEditor, six.text_type: self._MakeStringEditor, + bool: self._MakeBoolEditor} if six.PY2: self.typeToFunctionMap[int] = self._MakeIntegerEditor @@ -210,7 +212,15 @@ def SetValue(self, value): class BaseCellTextEditor(wx.TextCtrl): - """This is a base text editor for text-like editors used in an ObjectListView""" + """ + This is a base text editor for text-like editors used in an ObjectListView + + Parameters + ---------- + olv : ObjectListView + subItemIndex : int + The index of the column that is being edited + """ def __init__(self, olv, subItemIndex, **kwargs): style = wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB @@ -244,7 +254,13 @@ def GetValue(self): return None def SetValue(self, value): - "Put a new value into the editor" + """ + Put a new value into the editor + + Parameters + ---------- + value : object + """ if isinstance(value, int): value = repr(value) super(IntEditor, self).SetValue(value) @@ -265,7 +281,13 @@ def GetValue(self): return None def SetValue(self, value): - "Put a new value into the editor" + """ + Put a new value into the editor + + Parameters + ---------- + value : object + """ if isinstance(value, (int, float)): value = repr(value) super(LongEditor, self).SetValue(value) @@ -390,7 +412,13 @@ def SetValue(self, value): super(DateTimeEditor, self).SetValue(value) def GetValue(self): - "Get the value from the editor" + """ + Get the value from the editor + + Returns + ------- + datetime.datetime + """ s = super(DateTimeEditor, self).GetValue().strip() return self._ParseDateTime(s) @@ -430,7 +458,13 @@ def _ParseDateTime(self, s): class NumericValidator(wx.PyValidator): - """This validator only accepts numeric keys""" + """ + This validator only accepts numeric keys + + Parameters + ---------- + acceptableChars : str of ints, optional + """ def __init__(self, acceptableChars="0123456789+-"): wx.Validator.__init__(self) @@ -479,11 +513,14 @@ class DateEditor(DatePickerCtrl): """ def __init__(self, *args, **kwargs): - #kwargs["size"] = (0,0) + # kwargs["size"] = (0,0) super(DateEditor, self).__init__(*args, **kwargs) self.SetValue(None) def SetValue(self, value): + """ + Set the date of the editor + """ if value: dt = wx.DateTime() dt.Set(value.day, value.month - 1, value.year) @@ -492,7 +529,13 @@ def SetValue(self, value): super(DateEditor, self).SetValue(dt) def GetValue(self): - "Get the value from the editor" + """ + Get the value from the editor + + Returns + ------- + datetime.date + """ dt = super(DateEditor, self).GetValue() if dt.IsValid(): if 'phoenix' in wx.PlatformInfo: @@ -506,7 +549,6 @@ def GetValue(self): class TimeEditor(BaseCellTextEditor): - """A text editor that expects and return time values""" # Acceptable formats: '23:59', '11:59pm', '11pm' @@ -524,7 +566,13 @@ def SetValue(self, value): super(TimeEditor, self).SetValue(value) def GetValue(self): - "Get the value from the editor" + """ + Get the value from the editor + + Returns + ------- + datetime.time + """ s = super(TimeEditor, self).GetValue().strip() fmts = self.STD_TIME_FORMATS[:] if self.formatString not in fmts: @@ -546,6 +594,16 @@ def MakeAutoCompleteTextBox(olv, columnIndex, maxObjectsToConsider=10000): """ Return a TextCtrl that lets the user choose from all existing values in this column. Do not call for large lists + + Parameters + ---------- + olv : ObjectListView + columnIndex : int + maxObjectsToConsider : int, optional + + Returns + ------- + wx.TextCtrl """ col = olv.columns[columnIndex] # THINK: We could make this time based, i.e. it escapes after 1 second. @@ -562,6 +620,16 @@ def MakeAutoCompleteComboBox(olv, columnIndex, maxObjectsToConsider=10000): """ Return a ComboBox that lets the user choose from all existing values in this column. Do not call for large lists + + Parameters + ---------- + olv : ObjectListView + columnIndex : int + maxObjectsToConsider : int, optional + + Returns + ------- + wx.ComboBox """ col = olv.columns[columnIndex] maxObjectsToConsider = min(maxObjectsToConsider, olv.GetItemCount()) @@ -582,6 +650,10 @@ class AutoCompleteHelper(object): This class operates on a text control or combobox, and automatically completes the text typed by the user from a list of entries in a given list. + Parameters + ---------- + control : wx.TextCtrl or wx.ComboBox + possibleValues : list of str, optional """ def __init__(self, control, possibleValues=None): @@ -595,6 +667,13 @@ def __init__(self, control, possibleValues=None): self.lowerCasePossibleValues = [x.lower() for x in self.possibleValues] def _OnTextEvent(self, evt): + """ + Handle the EVT_TEXT event + + Parameters + ---------- + evt : wx.Event + """ evt.Skip() # After the SetValue() we want to ignore this event. If we get this event # and the value hasn't been modified, we know it was a SetValue() call. diff --git a/spacq/gui/objectlistview/Filter.py b/spacq/gui/objectlistview/Filter.py index a28256e..656a731 100644 --- a/spacq/gui/objectlistview/Filter.py +++ b/spacq/gui/objectlistview/Filter.py @@ -34,8 +34,17 @@ def Predicate(predicate): """ Display only those objects that match the given predicate - Example:: + Example + ------- self.olv.SetFilter(Filter.Predicate(lambda x: x.IsOverdue())) + + Parameters + ---------- + predicate : function + + Returns + ------- + function """ return lambda modelObjects: [x for x in modelObjects if predicate(x)] @@ -44,8 +53,17 @@ def Head(num): """ Display at most the first N of the model objects - Example:: + Example + ------- self.olv.SetFilter(Filter.Head(1000)) + + Parameters + ---------- + num : int + + Returns + ------- + function """ return lambda modelObjects: modelObjects[:num] @@ -54,8 +72,17 @@ def Tail(num): """ Display at most the last N of the model objects - Example:: + Example + ------- self.olv.SetFilter(Filter.Tail(1000)) + + Parameters + ---------- + num : int + + Returns + ------- + function """ return lambda modelObjects: modelObjects[-num:] @@ -83,6 +110,14 @@ def __init__(self, objectListView, columns=(), text=""): def __call__(self, modelObjects): """ Return the model objects that contain our text in one of the columns to consider + + Parameters + ---------- + modelObjects : list of object + + Returns + ------- + list of object """ if not self.text: return modelObjects @@ -106,6 +141,10 @@ def _containsText(modelObject): def SetText(self, text): """ Set the text that this filter will match. Set this to None or "" to disable the filter. + + Parameters + ---------- + text : str """ self.text = text @@ -127,12 +166,24 @@ def __init__(self, *filters): Create a filter that performs all the given filters. The order of the filters is important. + + Parameters + ---------- + filters : list of Filter """ self.filters = filters def __call__(self, modelObjects): """ Return the model objects that match all of our filters + + Parameters + ---------- + modelObjects : list of object + + Returns + ------- + list of object """ for filter in self.filters: modelObjects = filter(modelObjects) diff --git a/spacq/gui/objectlistview/ListCtrlPrinter.py b/spacq/gui/objectlistview/ListCtrlPrinter.py index fa53f88..e297ae1 100644 --- a/spacq/gui/objectlistview/ListCtrlPrinter.py +++ b/spacq/gui/objectlistview/ListCtrlPrinter.py @@ -112,6 +112,9 @@ class ListCtrlPrinter(object): """ An ListCtrlPrinter creates a pretty report from an ObjectListView/ListCtrl. + Parameters + ---------- + listCtrl : ObjectListView or wx.ListCtrl, optional """ def __init__(self, listCtrl=None, title="ListCtrl Printing"): @@ -129,6 +132,10 @@ def GetPageFooter(self): """ Return a 3-tuple of the texts that will be shown in left, center, and right cells of the page footer + + Return + ------ + tuple of str """ return self.engine.pageFooter @@ -137,6 +144,12 @@ def SetPageFooter(self, leftText="", centerText="", rightText=""): Set the texts that will be shown in various cells of the page footer. leftText can be a string or a 3-tuple of strings. + + Parameters + ---------- + leftText : str or tuple of str, optional + centerText : str, optional + rightText : str, optional """ if isinstance(leftText, (tuple, list)): self.engine.pageFooter = leftText @@ -153,6 +166,12 @@ def GetPageHeader(self): def SetPageHeader(self, leftText="", centerText="", rightText=""): """ Set the texts that will be shown in various cells of the page header + + Parameters + ---------- + leftText : str, optional + centerText : str, optional + rightText : str, optional """ if isinstance(leftText, (tuple, list)): self.engine.pageHeader = leftText @@ -174,18 +193,30 @@ def GetReportFormat(self): def SetReportFormat(self, fmt): """ Set the ReportFormat object that controls the appearance of this printout + + Parameters + ---------- + fmt : ReportFormat """ self.engine.reportFormat = fmt def GetWatermark(self, txt): """ Get the text that will be printed as a watermark on the report + + Parameters + ---------- + txt : str """ return self.engine.watermark def SetWatermark(self, txt): """ Set the text that will be printed as a watermark on the report + + Parameters + ---------- + txt : str """ self.engine.watermark = txt @@ -201,6 +232,11 @@ def SetWatermark(self, txt): def AddListCtrl(self, listCtrl, title=None): """ Add the given list to those that will be printed by this report. + + Parameters + ---------- + listCtrl : ObjectListView or wx.ListCtrl + title : str, optional """ self.engine.AddListCtrl(listCtrl, title) @@ -216,6 +252,10 @@ def Clear(self): def PageSetup(self, parent=None): """ Show a Page Setup dialog that will change the configuration of this printout + + Parameters + ---------- + parent : wx.Window, optional """ self.printout.PageSetup(parent) @@ -230,12 +270,23 @@ def PrintPreview( 800)): """ Show a Print Preview of this report + + Parameters + ---------- + parent : wx.Window, optional + title : str, optional + bounds : 4-tuple of int, optional + The (x, y, width, height) of the preview window """ self.printout.PrintPreview(parent, title, bounds) def Print(self, parent=None): """ Print this report to the selected printer + + Parameters + ---------- + parent : wx.Window, optional """ self.printout.DoPrint(parent) @@ -248,6 +299,13 @@ def CalculateTotalPages(self, dc, bounds): Do the work of calculating how many pages this report will occupy? This is expensive because it basically prints the whole report. + + Parameters + ---------- + dc : wx.DC + The device context that will be used for printing + bounds : 4-tuple of int + The (x, y, width, height) of the page """ return self.engine.CalculateTotalPages(dc, bounds) @@ -260,6 +318,14 @@ def StartPrinting(self): def PrintPage(self, dc, pageNumber, bounds): """ Print the given page on the given device context. + + Parameters + ---------- + dc : wx.DC + The device context that will be used for printing + pageNumber : int + bounds : 4-tuple of int + The (x, y, width, height) of the page """ self.engine.PrintPage(dc, pageNumber, bounds) @@ -278,7 +344,6 @@ class ReportEngine(object): the datetime be formatted? This must be a valid format string for the strftime() method. Default: "%x %X" - """ def __init__(self): @@ -308,6 +373,14 @@ def __init__(self): def GetNamedFormat(self, name): """ Return the given format + + Parameters + ---------- + name : str + + Returns + ------- + ReportFormat """ return self.reportFormat.GetNamedFormat(name) @@ -316,12 +389,20 @@ def GetTotalPages(self): Return the total number of pages that this report will produce. CalculateTotalPages() must be called before this is accurate. + + Return + ------ + int """ return self.totalPages def GetSubstitutionInfo(self): """ Return a dictionary that can be used for substituting values into strings + + Return + ------ + dict """ dateString = datetime.datetime.now().strftime(self.dateFormat) info = { @@ -339,6 +420,17 @@ def CalculateTotalPages(self, dc, bounds): Do the work of calculating how many pages this report will occupy? This is expensive because it basically prints the whole report. + + Parameters + ---------- + dc : wx.DC + The device context that will be used for printing + bounds : 4-tuple of int + The (x, y, width, height) of the page + + Return + ------ + int """ self.StartPrinting() self.totalPages = 1 @@ -354,6 +446,10 @@ def CalculateTotalPages(self, dc, bounds): def AddBlock(self, block): """ Add the given block at the current insertion point + + Parameters + ---------- + block : Block """ self.blocks.insert(self.blockInsertionIndex, block) self.blockInsertionIndex += 1 @@ -362,6 +458,11 @@ def AddBlock(self, block): def AddListCtrl(self, listCtrl, title=None): """ Add the given list to those that will be printed by this report. + + Parameters + ---------- + listCtrl : ObjectListView or wx.ListCtrl + title : str, optional """ if listCtrl.InReportView(): self.listCtrls.append([listCtrl, title]) @@ -400,6 +501,10 @@ def StartPrinting(self): def AddRunningBlock(self, block): """ A running block is printed on every page until it is removed + + Parameters + ---------- + block : Block """ self.runningBlocks.append(block) block.engine = self @@ -407,12 +512,29 @@ def AddRunningBlock(self, block): def RemoveRunningBlock(self, block): """ A running block is printed on every page until it is removed + + Parameters + ---------- + block : Block """ self.runningBlocks.remove(block) def PrintPage(self, dc, pageNumber, bounds): """ Print the given page on the given device context. + + Parameters + ---------- + dc : wx.DC + The device context that will be used for printing + pageNumber : int + bounds : 4-tuple of int + The (x, y, width, height) of the page + + Return + ------ + bool + True if there is still more to print """ # If the request page isn't next in order, we have to restart # the printing process and advance until we reach the desired page. @@ -430,6 +552,19 @@ def PrintOnePage(self, dc, pageNumber, bounds): Print the current page on the given device context. Return true if there is still more to print. + + Parameters + ---------- + dc : wx.DC + The device context that will be used for printing + pageNumber : int + bounds : 4-tuple of int + The (x, y, width, height) of the page + + Return + ------ + bool + True if there is still more to print """ # Initialize state self.currentPage = pageNumber @@ -454,6 +589,11 @@ def PrintOnePage(self, dc, pageNumber, bounds): def SubtractDecorations(self, dc): """ # Subtract the area used from the work area + + Parameters + ---------- + dc : wx.DC + The device context that will be used for printing """ fmt = self.GetNamedFormat("Page") self.workBounds = fmt.SubtractDecorations(dc, self.workBounds) @@ -461,6 +601,13 @@ def SubtractDecorations(self, dc): def DrawPageDecorations(self, dc, over): """ Draw the page decorations + + Parameters + ---------- + dc : wx.DC + The device context that will be used for printing + over : bool + True if the decorations should be drawn over the text """ if not self.shouldDrawBlocks: return @@ -495,6 +642,12 @@ class ListCtrlPrintout(wx.Printout): """ An ListCtrlPrintout is the interface between the wx printing system and ListCtrlPrinter. + + Parameters + ---------- + olvPrinter : ListCtrlPrinter + margins : 2-tuple of wx.Point, optional + The (top-left, bottom-right) margins of the page """ def __init__(self, olvPrinter, margins=None): @@ -516,6 +669,14 @@ def __init__(self, olvPrinter, margins=None): def HasPage(self, page): """ Return true if this printout has the given page number + + Parameters + ---------- + page : int + + Return + ------ + bool """ return page <= self.totalPages @@ -528,6 +689,10 @@ def GetPageInfo(self): def GetPrintPreview(self): """ Get a wxPrintPreview of this report + + Return + ------ + wx.PrintPreview """ data = wx.PrintDialogData(self.printData) forViewing = ListCtrlPrintout(self.olvPrinter, self.margins) @@ -541,6 +706,10 @@ def GetPrintPreview(self): def PageSetup(self, parent): """ Show a Page Setup dialog that will change the configuration of this printout + + Parameters + ---------- + parent : wx.Window """ data = wx.PageSetupDialogData() data.SetPrintData(self.printData) @@ -560,6 +729,13 @@ def PageSetup(self, parent): def PrintPreview(self, parent, title, bounds): """ Show a Print Preview of this report + + Parameters + ---------- + parent : wx.Window + title : str + bounds : 4-tuple of int + The (x, y, width, height) of the preview window """ self.preview = self.GetPrintPreview() @@ -578,6 +754,10 @@ def PrintPreview(self, parent, title, bounds): def DoPrint(self, parent): """ Send the report to the configured printer + + Parameters + ---------- + parent : wx.Window """ try: pdd = wx.PrintDialogData(self.printData) @@ -609,6 +789,16 @@ def OnPreparePrinting(self): def OnBeginDocument(self, start, end): """ Begin printing one copy of the document. Return False to cancel the job + + Parameters + ---------- + start : int + end : int + + Return + ------ + bool + If False, the print job will be cancelled """ return super(ListCtrlPrintout, self).OnBeginDocument(start, end) @@ -624,6 +814,10 @@ def OnEndPrinting(self): def OnPrintPage(self, page): """ Do the work of printing the given page number. + + Parameters + ---------- + page : int """ # We bounce this back to the printer facade dc = self.GetDC() @@ -634,6 +828,11 @@ def SetScaleAndBounds(self, dc): """ Calculate the scale required for our printout to match what appears on screen, and the bounds that will be effective at that scale and margins + + Parameters + ---------- + dc : wx.DC + The device context that will be used for printing """ # This code comes from Robin Dunn's "wxPython In Action." # Without that, I would never have figured this out. @@ -695,8 +894,7 @@ class ReportFormat(object): def __init__(self): """ """ - # Initialize the formats that control the various portions of the - # report + # Initialize the formats that control the various portions of the report self.Page = BlockFormat() self.PageHeader = BlockFormat() self.ListHeader = BlockFormat() @@ -721,6 +919,10 @@ def __init__(self): def GetNamedFormat(self, name): """ Return the format used in to format a block with the given name. + + Parameters + ---------- + name : str """ return getattr(self, name) @@ -732,6 +934,15 @@ def WatermarkFormat(self, font=None, color=None, angle=30, over=False): Change the format of the watermark printed on this report. The actual text of the water mark is set by `ListCtrlPrinter.Watermark` property. + + Parameters + ---------- + font : wx.Font, optional + color : wx.Colour, optional + angle : int, optional + The angle of the watermark text, in degrees + over : bool, optional + If True, the watermark will be printed over the text of the report """ defaultFaceName = "Stencil" self.Watermark.Font = font or wx.FFont( @@ -751,6 +962,15 @@ def WatermarkFormat(self, font=None, color=None, angle=30, over=False): def Minimal(headerFontName="Arial", rowFontName="Times New Roman"): """ Return a minimal format for a report + + Parameters + ---------- + headerFontName : str, optional + rowFontName : str, optional + + Returns + ------- + ReportFormat """ fmt = ReportFormat() fmt.IsShrinkToFit = False @@ -807,6 +1027,15 @@ def Minimal(headerFontName="Arial", rowFontName="Times New Roman"): def Normal(headerFontName="Gill Sans", rowFontName="Times New Roman"): """ Return a reasonable default format for a report + + Parameters + ---------- + headerFontName : str, optional + rowFontName : str, optional + + Returns + ------- + ReportFormat """ fmt = ReportFormat() fmt.IsShrinkToFit = True @@ -866,6 +1095,15 @@ def Normal(headerFontName="Gill Sans", rowFontName="Times New Roman"): def TooMuch(headerFontName="Chiller", rowFontName="Gill Sans"): """ Return a reasonable default format for a report + + Parameters + ---------- + headerFontName : str, optional + rowFontName : str, optional + + Returns + ------- + ReportFormat """ fmt = ReportFormat() fmt.IsShrinkToFit = False @@ -1003,42 +1241,73 @@ def __init__(self): def GetFont(self): """ Return the font used by this format + + Return + ------ + wx.Font """ return self.font def SetFont(self, font): """ Set the font used by this format + + Parameters + ---------- + font : wx.Font """ self.font = font def GetTextAlignment(self): """ Return the alignment of text in this format + + Return + ------ + int """ return self.textAlignment def SetTextAlignment(self, alignment): """ Set the alignment of text in this format + + Parameters + ---------- + alignment : int + One of wx.ALIGN_LEFT, wx.ALIGN_CENTER, or wx.ALIGN_RIGHT """ self.textAlignment = alignment def GetTextColor(self): """ Return the color of text in this format + + Return + ------ + wx.Colour """ return self.textColor def SetTextColor(self, color): """ Set the color of text in this format + + Parameters + ---------- + color : wx.Colour """ self.textColor = color def GetPadding(self): """ Get the padding around this format + + Parameters + ---------- + padding : int or 4-tuple of int + either a single numeric (indicating the values on all sides) + or a collection of paddings (left, top, right, bottom) """ return self.padding @@ -1046,14 +1315,22 @@ def SetPadding(self, padding): """ Set the padding around this format - Padding is either a single numeric (indicating the values on all sides) - or a collection of paddings [left, top, right, bottom] + Parameters + ---------- + padding : int or 4-tuple of int + either a single numeric (indicating the values on all sides) + or a collection of paddings (left, top, right, bottom) """ self.padding = self._MakePadding(padding) def GetCellPadding(self): """ Get the padding around cells in this format + + Return + ------ + 4-tuple of int + (left, top, right, bottom) """ return self.cellPadding @@ -1061,20 +1338,31 @@ def SetCellPadding(self, padding): """ Set the padding around cells in this format - Padding is either a single numeric (indicating the values on all sides) - or a collection of paddings [left, top, right, bottom] + Parameters + ---------- + padding : int or 4-tuple of int + either a single numeric (indicating the values on all sides) + or a collection of paddings (left, top, right, bottom) """ self.cellPadding = self._MakePadding(padding) def GetGridPen(self): """ Return the pen used to draw a grid in this format + + Return + ------ + wx.Pen """ return self.gridPen def SetGridPen(self, pen): """ Set the pen used to draw a grid in this format + + Parameters + ---------- + pen : wx.Pen """ self.gridPen = pen if self.gridPen: @@ -1083,6 +1371,20 @@ def SetGridPen(self, pen): self.gridPen.SetJoin(wx.JOIN_MITER) def _MakePadding(self, padding): + """ + Return a 4-tuple of padding values, if it is an int, pad the 4-tuple out with zeros + + Parameters + ---------- + padding : int or 4-tuple of int + either a single numeric (indicating the values on all sides) + or a collection of paddings (left, top, right, bottom) + + Return + ------ + 4-tuple of int + (left, top, right, bottom) + """ try: if len(padding) < 4: return (tuple(padding) + (0, 0, 0, 0))[:4] @@ -1094,24 +1396,40 @@ def _MakePadding(self, padding): def GetAlwaysCenter(self): """ Return if the text controlled by this format should always be centered? + + Return + ------ + bool """ return self.alwaysCenter def SetAlwaysCenter(self, value): """ Remember if the text controlled by this format should always be centered? + + Parameters + ---------- + value : bool """ self.alwaysCenter = value def GetCanWrap(self): """ Return if the text controlled by this format can wrap to cover more than one line? + + Return + ------ + bool """ return self.canWrap def SetCanWrap(self, value): """ Remember if the text controlled by this format can wrap to cover more than one line? + + Parameters + ---------- + value : bool """ self.canWrap = value @@ -1154,6 +1472,10 @@ def CalculateCellPadding(self): def Add(self, decoration): """ Add the given decoration to those adorning blocks with this format + + Parameters + ---------- + decoration : Decoration """ self.decorations.append(decoration) @@ -1169,6 +1491,17 @@ def Line( Add a line to our decorations. If a pen is given, we use a straight Line decoration, otherwise we use a coloured rectangle + + Parameters + ---------- + side : int, optional + One of wx.TOP, wx.BOTTOM, wx.LEFT, wx.RIGHT + color : wx.Colour, optional + width : int, optional + toColor : wx.Colour, optional + space : int, optional + pen : wx.Pen, optional + """ if pen: self.Add(LineDecoration(side, pen, space)) @@ -1185,6 +1518,12 @@ def Line( def Background(self, color=wx.BLUE, toColor=None, space=0): """ Add a coloured background to the block + + Parameters + ---------- + color : wx.Colour, optional + toColor : wx.Colour, optional + space : int, optional """ self.Add( RectangleDecoration( @@ -1195,6 +1534,11 @@ def Background(self, color=wx.BLUE, toColor=None, space=0): def Frame(self, pen=None, space=0): """ Add a rectangle around this block + + Parameters + ---------- + pen : wx.Pen, optional + space : int, optional """ self.Add(RectangleDecoration(pen=pen, space=space)) @@ -1204,6 +1548,16 @@ def Frame(self, pen=None, space=0): def SubtractPadding(self, bounds): """ Subtract any padding used by this format from the given bounds + + Parameters + ---------- + bounds : 4-tuple of int + (left, top, right, bottom) + + Return + ------ + 4-tuple of int + (left, top, right, bottom) """ if self.padding is None: return bounds @@ -1213,6 +1567,17 @@ def SubtractPadding(self, bounds): def SubtractDecorations(self, dc, bounds): """ Subtract any space used by our decorations from the given bounds + + Parameters + ---------- + dc : wx.DC + bounds : 4-tuple of int + (left, top, right, bottom) + + Return + ------ + 4-tuple of int + (left, top, right, bottom) """ for x in self.decorations: bounds = x.SubtractFrom(dc, bounds) @@ -1221,6 +1586,16 @@ def SubtractDecorations(self, dc, bounds): def DrawDecorations(self, dc, bounds, block, over): """ Draw our decorations on the given block + + Parameters + ---------- + dc : wx.DC + The device context to use for drawing + bounds : 4-tuple of int + (left, top, right, bottom) + block : Block + over : bool + If True, draw decorations over the text of the block """ for x in self.decorations: if x.IsDrawOver() == over: @@ -1234,6 +1609,10 @@ class Block(object): """ A Block is a portion of a report that will stack vertically with other Block. A report consists of several Blocks. + + Parameters + ---------- + engine : ReportEngine, optional """ def __init__(self, engine=None): @@ -1246,24 +1625,48 @@ def __init__(self, engine=None): def GetFont(self): """ Return Font that should be used to draw text in this block + + Return + ------ + wx.Font """ return self.GetFormat().GetFont() def GetTextColor(self): """ Return Colour that should be used to draw text in this block + + Return + ------ + wx.Colour """ return self.GetFormat().GetTextColor() def GetFormat(self): """ Return the BlockFormat object that controls the formatting of this block + + Return + ------ + BlockFormat """ return self.engine.GetNamedFormat(self.__class__.__name__[:-5]) def GetReducedBlockBounds(self, dc, bounds=None): """ Return the bounds of this block once padding and decoration have taken their toll. + + Parameters + ---------- + dc : wx.DC + The device context to use for calculations + bounds : 4-tuple of int, optional + (left, top, right, bottom) + + Return + ------ + 4-tuple of int + (left, top, right, bottom) """ bounds = bounds or list(self.GetWorkBounds()) fmt = self.GetFormat() @@ -1274,24 +1677,41 @@ def GetReducedBlockBounds(self, dc, bounds=None): def GetWorkBounds(self): """ Return the boundaries of the work area for this block + + Return + ------ + 4-tuple of int + (left, top, right, bottom) """ return self.engine.workBounds def IsColumnHeadingsOnEachPage(self): """ Should the column headers be report at the top of each new page? + + Return + ------ + bool """ return self.engine.reportFormat.IsColumnHeadingsOnEachPage def IncludeImages(self): """ Should the images from the ListCtrl be printed in the report? + + Return + ------ + bool """ return self.engine.reportFormat.IncludeImages def IsShrinkToFit(self): """ Should row blocks be shrunk to fit within the width of a page? + + Return + ------ + bool """ return self.engine.reportFormat.IsShrinkToFit @@ -1300,6 +1720,10 @@ def IsUseSubstitution(self): Should the text values printed by this block have substitutions performed before being printed? This allows, for example, footers to have '%(currentPage)d of %(totalPages)d' + + Return + ------ + bool """ return True @@ -1309,6 +1733,15 @@ def IsUseSubstitution(self): def CalculateExtrasHeight(self, dc): """ Return the height of the padding and decorations themselves + + Parameters + ---------- + dc : wx.DC + The device context to use for calculations + + Return + ------ + int """ return 0 - RectUtils.Height( self.GetReducedBlockBounds( @@ -1318,6 +1751,15 @@ def CalculateExtrasHeight(self, dc): def CalculateExtrasWidth(self, dc): """ Return the width of the padding and decorations themselves + + Parameters + ---------- + dc : wx.DC + The device context to use for calculations + + Return + ------ + int """ return 0 - RectUtils.Width( self.GetReducedBlockBounds( @@ -1327,12 +1769,34 @@ def CalculateExtrasWidth(self, dc): def CalculateHeight(self, dc): """ Return the heights of this block in pixels + + Parameters + ---------- + dc : wx.DC + The device context to use for calculations + + Return + ------ + int """ return -1 def CalculateTextHeight(self, dc, txt, bounds=None, font=None): """ Return the height of the given txt in pixels + + Parameters + ---------- + dc : wx.DC + The device context to use for calculations + txt : str + bounds : 4-tuple of int, optional + (left, top, right, bottom) + font : wx.Font, optional + + Return + ------ + int """ bounds = bounds or self.GetReducedBlockBounds(dc) font = font or self.GetFont() @@ -1351,6 +1815,14 @@ def CalculateTextHeight(self, dc, txt, bounds=None, font=None): def CanFit(self, height): """ Can this block fit into the remaining work area on the page? + + Parameters + ---------- + height : int + + Return + ------ + bool """ return height <= RectUtils.Height(self.GetWorkBounds()) @@ -1361,7 +1833,15 @@ def Print(self, dc): """ Print this Block. - Return True if the Block has finished printing + Parameters + ---------- + dc : wx.DC + The device context to use for printing + + Return + ------ + bool + True if the block has finished printing """ if not self.ShouldPrint(): return True @@ -1381,6 +1861,10 @@ def Print(self, dc): def ShouldPrint(self): """ Should this block be printed? + + Return + ------ + bool """ # If this block does not have a format, it is simply skipped return self.GetFormat() is not None @@ -1388,6 +1872,16 @@ def ShouldPrint(self): def CalculateBounds(self, dc): """ Calculate the bounds of this block + + Parameters + ---------- + dc : wx.DC + The device context to use for calculations + + Return + ------ + 4-tuple of int + (left, top, right, bottom) """ height = self.CalculateHeight(dc) bounds = list(self.GetWorkBounds()) @@ -1397,12 +1891,23 @@ def CalculateBounds(self, dc): def ChangeWorkBoundsBy(self, amt): """ Move the top of our work bounds down by the given amount + + Parameters + ---------- + amt : int """ RectUtils.MoveTopBy(self.engine.workBounds, amt) def Draw(self, dc, bounds): """ Draw this block and its decorations allowing for any padding + + Parameters + ---------- + dc : wx.DC + The device context to use for drawing + bounds : 4-tuple of int + (left, top, right, bottom) """ fmt = self.GetFormat() decorationBounds = fmt.SubtractPadding(bounds) @@ -1414,18 +1919,39 @@ def Draw(self, dc, bounds): def PreDraw(self, dc, bounds): """ Executed before any drawing is done + + Parameters + ---------- + dc : wx.DC + The device context to use for drawing + bounds : 4-tuple of int + (left, top, right, bottom) """ pass def DrawSelf(self, dc, bounds): """ Do the actual work of rendering this block. + + Parameters + ---------- + dc : wx.DC + The device context to use for drawing + bounds : 4-tuple of int + (left, top, right, bottom) """ pass def PostDraw(self, dc, bounds): """ Executed after drawing has completed + + Parameters + ---------- + dc : wx.DC + The device context to use for drawing + bounds : 4-tuple of int + (left, top, right, bottom) """ pass @@ -1447,20 +1973,46 @@ def DrawText( This is the workhorse text drawing method for our reporting engine. - The *font*, *alignment*, and *color* attributes are applied to the drawn text. - - If *image* is not None, it will be drawn to the left of the text. All text is indented - by the width of the image, even if the text is multi-line. - - If *imageIndex* is 0 or more and *listCtrl* is not None, the corresponding image from - the ListCtrl's small image list will be drawn to the left of the text. - - If *canWrap* is True, the text will be wrapped to fit within the given bounds. If it is False, - then the first line of *txt* will be truncated at the edge of the given *bounds*. + Parameters + ---------- + dc : wx.DC + The device context to use for drawing + txt : str + bounds : 4-tuple of int + (left, top, right, bottom) + font : wx.Font, optional + alignment : int, optional + One of wx.ALIGN_LEFT, wx.ALIGN_CENTER, or wx.ALIGN_RIGHT + valignment : int, optional + One of wx.ALIGN_TOP, wx.ALIGN_CENTER, or wx.ALIGN_BOTTOM + image : wx.Bitmap, optional + If not None, this image will be drawn to the left of the text + and the text will be indented by the width of the image + color : wx.Colour, optional + canWrap : bool, optional + If True, the text will be wrapped to fit within the given bounds + If False, then the first line of *txt* will be truncated at the edge of the given *bounds* + imageIndex : int, optional + If 0 or more and *listCtrl* is not None, the corresponding image from + the ListCtrl's small image list will be drawn to the left of the text + listCtrl : wx.ListCtrl, optional """ GAP_BETWEEN_IMAGE_AND_TEXT = 4 def _CalcBitmapPosition(r, height): + """ + Return the y position of the given bitmap given the alignment and the height of the bitmap + + Parameters + ---------- + r : 4-tuple of int + (left, top, right, bottom) + height : int + + Return + ------ + int + """ if valignment == wx.ALIGN_TOP: return RectUtils.Top(r) elif valignment == wx.ALIGN_CENTER: diff --git a/spacq/gui/tool/__init__.py b/spacq/gui/tool/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/spacq/gui/tool/box.py b/spacq/gui/tool/box.py index 7602f17..c67423f 100644 --- a/spacq/gui/tool/box.py +++ b/spacq/gui/tool/box.py @@ -11,6 +11,15 @@ def determine_wildcard(extension=None, file_type=None): """ Assemble a wildcard string of the form: [[file_type ](*.extension)|*.extension|] + + Parameters + ---------- + extension : str, optional + file_type : str, optional + + Returns + ------- + The wildcard string. """ all_files = 'All files|*' @@ -35,6 +44,16 @@ def determine_wildcard(extension=None, file_type=None): def load_pickled(parent, extension=None, file_type=None): """ Unpickle data from a file based on a file dialog. + + Parameters + ---------- + parent : wx.Window + extension : str, optional + file_type : str, optional + + Returns + ------- + The unpickled data. """ wildcard = determine_wildcard(extension, file_type) @@ -51,9 +70,17 @@ def load_pickled(parent, extension=None, file_type=None): # Wrap all problems. raise IOError('Could not load data.', e) + def save_pickled(parent, values, extension=None, file_type=None): """ Pickle data to a file based on a file dialog. + + Parameters + ---------- + parent : wx.Window + values : object + extension : str, optional + file_type : str, optional """ wildcard = determine_wildcard(extension, file_type) @@ -82,6 +109,18 @@ def load_csv(parent, extension='csv', file_type='CSV'): ZParrott: has_header functions partially in that it removes a blank first row, but hte has_header boolean then fails in subsequent dependicies where it has meaning of having a column title or not. + + Parameters + ---------- + parent : wx.Window + extension : str, optional + file_type : str, optional + + Returns + ------- + Whether the first row is a header + The data + The filename """ wildcard = determine_wildcard(extension, file_type) @@ -110,9 +149,19 @@ def load_csv(parent, extension='csv', file_type='CSV'): # Wrap all problems. raise IOError('Could not load data.', e) + def save_csv(parent, values, headers=None, extension='csv', file_type='CSV'): """ Save data to a CSV file based on a file dialog. + + Parameters + ---------- + parent : wx.Window + values : list of lists + headers : list of str, optional + The column headers. + extension : str, optional + file_type : str, optional """ wildcard = determine_wildcard(extension, file_type) @@ -166,6 +215,16 @@ def OnShow(self, evt): class MessageDialog(Dialog): """ A simple error message dialog. + + Parameters + ---------- + parent : wx.Window + message : str + title : str, optional + unclosable : bool, optional + Whether the dialog can be closed by the user. + monospace : bool, optional + Whether to use a monospace font. """ def __init__(self, parent, message, title='', unclosable=False, monospace=False, @@ -198,6 +257,17 @@ def __init__(self, parent, message, title='', unclosable=False, monospace=False, class YesNoQuestionDialog(Dialog): """ A yes/no question dialog. + + Parameters + ---------- + parent : wx.Window + prompt : str + The question to ask. + yes_callback : callable, optional + The function to call when the user clicks "Yes". + no_callback : callable, optional + The function to call when the user clicks "No". + title : str, optional """ def __init__(self, parent, prompt, yes_callback=None, no_callback=None, title='', diff --git a/spacq/interface/__init__.py b/spacq/interface/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/spacq/interface/pulse/__init__.py b/spacq/interface/pulse/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/spacq/interface/pulse/parser.py b/spacq/interface/pulse/parser.py index dbea705..e4ad2f7 100644 --- a/spacq/interface/pulse/parser.py +++ b/spacq/interface/pulse/parser.py @@ -30,6 +30,19 @@ class PulseSyntaxError(PulseError): def read_quantity(s, loc, toks): """ Attempt to create a Quantity object. + + Parameters + ---------- + s : str + The original string being parsed. + loc : int + The location of the error. + toks : list + The tokens parsed. + + Returns + ------- + The parsed quantity. """ try: @@ -44,6 +57,10 @@ def Parser(raw=False): If raw is True, returns the pyparsing parser object. Otherwise, returns a function which takes a string and returns an AST. + + Returns + ------- + The parser. """ old_whitespace = ParserElement.DEFAULT_WHITE_CHARS diff --git a/spacq/interface/pulse/program.py b/spacq/interface/pulse/program.py index 2355ac9..9933efe 100644 --- a/spacq/interface/pulse/program.py +++ b/spacq/interface/pulse/program.py @@ -13,6 +13,12 @@ class Program(object): """ A prepared, compiled pulse program. + + Parameters + ---------- + env : Environment + ast : Block + The abstract syntax tree to use. """ filename = '' @@ -21,6 +27,16 @@ class Program(object): def from_string(cls, s): """ Create a program from a string. + + Parameters + ---------- + cls : Program + s : str + The program text. + + Returns + ------- + The loaded program. """ env = Environment() @@ -32,6 +48,17 @@ def from_string(cls, s): def from_file(cls, path): """ Load a program from a file. + + Parameters + ---------- + cls : Program + path : str + The path to the file. + + Returns + ------- + The loaded program. + """ with open(path) as f: @@ -107,6 +134,10 @@ def set_value(self, parameter, value): def generate_waveforms(self, dry_run=False): """ Generate the waveforms, given that the values are all filled in. + + Returns + ------- + A dictionary of waveforms, keyed by name. """ self._env.stage = self._env.stages.waveforms @@ -126,6 +157,10 @@ def with_resources(self): Produce a copy object, with a cloned Environment, and with all resources which exist mutated to point to the corresponding values. Note: Because the Resource objects must be shared between copies, there may only ever exist one copy at a time. + + Returns + ------- + A copy of the program. """ result = copy(self) diff --git a/spacq/interface/pulse/tool/box.py b/spacq/interface/pulse/tool/box.py index 83d2dc4..3641955 100644 --- a/spacq/interface/pulse/tool/box.py +++ b/spacq/interface/pulse/tool/box.py @@ -11,10 +11,11 @@ def find_location(s, loc): """ Find where loc (linear index) in s. - Returns: - line number - column number - line itself + Returns + ------- + line number + column number + line itself Note: Tabs are not handled specially. """ @@ -43,8 +44,8 @@ def format_error(msg, row=None, col=None, line=None): if row is None or col is None or line is None: return 'error: {0}'.format(msg) else: - return 'error: {0} at column {1} on line {2}:\n{3}{4}\n{5}^'.format(msg, - col, row, ' ' * 2, line, ' ' * (col + 1)) + return 'error: {0} at column {1} on line {2}:\n{3}{4}\n{5}^'.format(msg, col, row, ' ' * 2, + line, ' ' * (col + 1)) def load_values(f): diff --git a/spacq/interface/pulse/tree.py b/spacq/interface/pulse/tree.py index 97b9f20..424188a 100644 --- a/spacq/interface/pulse/tree.py +++ b/spacq/interface/pulse/tree.py @@ -17,6 +17,10 @@ def draw_thing(thing, depth): """ Draws something at a given depth. + + Returns + ------- + A string which is the drawing. """ if isinstance(thing, ASTNode): @@ -144,6 +148,12 @@ def post_stage(self): def set_value(self, target, value): """ Set a value if the types work out. TypeError otherwise. + + Parameters + ---------- + target : tuple + The target variable or attribute. + value : object """ # Type checking. @@ -201,6 +211,13 @@ def traverse_tree(self, root): self.post_stage() def format_errors(self): + """ + Format errors for printing. + + Returns + ------- + List of formatted errors. + """ result = [] # Sort by line number, then column number, and ignore duplicates. @@ -215,6 +232,9 @@ def format_errors(self): class ASTNode(object): + """ + Abstract base class for AST nodes. + """ names = [] is_list = False @@ -255,10 +275,22 @@ def location(self): class Acquire(ASTNode): + """ + Acquire node. + """ def __repr__(self): return 'acquire' def visit(self, env): + """ + If the environment is in the declarations stage, add the acquisition marker. + If the environment is in the commands stage, verify that acquisition has not already been requested. + If the environment is in the waveforms stage, set the acquisition marker and output then generate the waveform. + + Parameters + ---------- + env : Environment + """ if env.stage == env.stages.declarations: if len(env.stack) != 1: env.add_error('Acquisition not at top level', self.location) @@ -277,6 +309,9 @@ def visit(self, env): class Assignment(ASTNode): + """ + Assignment node. + """ names = ['target', 'value'] def __repr__(self): @@ -294,6 +329,14 @@ def assign_value(self, env, target, value): env.add_error(str(e), self.location) def visit(self, env): + """ + If the environment is in the declarations stage, add the variable. + If the environment is in the values stage, set the value. + + Parameters + ---------- + env : Environment + """ if env.stage == env.stages.declarations: if isinstance(self.target, ASTNode): return self.target.visit(env) @@ -321,6 +364,9 @@ def visit(self, env): class Attribute(ASTNode): + """ + Attribute node. + """ names = ['variable', 'name'] def __repr__(self): @@ -330,6 +376,18 @@ def draw(self, depth): return 'Attribute\n' + draw_thing(self.variable, depth + 1) + draw_thing(self.name, depth + 1) def visit(self, env): + """ + Return the attribute. + if the environment is in the values stage and the attribute is not recognized, add an error. + + Parameters + ---------- + env : Environment + + Returns + ------- + A tuple of the attribute. + """ result = (self.variable, self.name) if env.stage == env.stages.values: @@ -340,6 +398,9 @@ def visit(self, env): class Block(ASTNode): + """ + Block node. + """ is_list = True def __repr__(self): @@ -351,6 +412,13 @@ def draw(self, depth=0): return draw_thing(self, depth) def visit(self, env): + """ + Visit each item in the block. + + Parameters + ---------- + env : Environment + """ env.stack.append(self) for item in self.items: item.visit(env) @@ -358,6 +426,9 @@ def visit(self, env): class Declaration(ASTNode): + """ + Declaration node. + """ names = ['type', 'variables'] def __repr__(self): @@ -372,6 +443,14 @@ def draw(self, depth): return ''.join(result) def visit(self, env): + """ + If the environment is in the declarations stage, visit each variable then check for re-declarations and add the variable. + Else, visit each variable. + + Parameters + ---------- + env : Environment + """ if env.stage == env.stages.declarations: if len(env.stack) != 1: env.add_error('Declaration not at top level', self.location) @@ -396,6 +475,9 @@ def visit(self, env): class Delay(ASTNode): + """ + Delay node. + """ names = ['length'] def __repr__(self): @@ -405,6 +487,14 @@ def draw(self, depth): return 'Delay\n' + draw_thing(self.length, depth + 1) def visit(self, env): + """ + If the environment is in the commands stage, check that the variable is a delay. + If the environment is in the waveforms stage, set the delay then generate the waveform. + + Parameters + ---------- + env : Environment + """ if env.stage == env.stages.commands: if isinstance(self.length, str): try: @@ -427,6 +517,9 @@ def visit(self, env): class Dictionary(ASTNode): + """ + Dictionary node. + """ is_list = True def __repr__(self): @@ -437,6 +530,9 @@ def visit(self, env): class DictionaryItem(ASTNode): + """ + Dictionary item node. + """ names = ['key', 'value'] def __repr__(self): @@ -450,6 +546,9 @@ def visit(self, env): class Loop(ASTNode): + """ + Loop node. + """ names = ['times', 'block'] def __repr__(self): @@ -459,6 +558,15 @@ def draw(self, depth): return 'Loop\n' + draw_thing(self.times, depth + 1) + draw_thing(self.block, depth + 1) def visit(self, env): + """ + If the environment is in the commands stage, check that the variable is an int. + If the environment is in the waveforms stage, visit the block the specified number of times. + Else, visit the block. + + Parameters + ---------- + env : Environment + """ if env.stage == env.stages.commands: if isinstance(self.times, str): try: @@ -484,12 +592,23 @@ def visit(self, env): class ParallelPulses(ASTNode): + """ + Parallel pulses node. + """ is_list = True def __repr__(self): return '{0}'.format(' '.join(repr(item) for item in self.items)) def visit(self, env): + """ + Visit each item in the block. + If the environment is in the waveforms stage, generate the waveform. + + Parameters + ---------- + env : Environment + """ env.stack.append(self) for item in self.items: item.visit(env) @@ -504,6 +623,9 @@ def visit(self, env): class Pulse(ASTNode): + """ + Pulse node. + """ names = ['sequence', 'target'] def __repr__(self): @@ -513,6 +635,14 @@ def draw(self, depth): return 'Pulse\n' + draw_thing(self.sequence, depth + 1) + draw_thing(self.target, depth + 1) def visit(self, env): + """ + If the environment is in the commands stage, check that the variable is recognized. + Visit the sequence. + + Parameters + ---------- + env : Environment + """ if env.stage == env.stages.commands: if self.target not in env.generators: env.add_error('Undefined output "{0}"'.format(self.target), self.location) @@ -523,12 +653,23 @@ def visit(self, env): class PulseSequence(ASTNode): + """ + Pulse sequence node. + """ is_list = True def __repr__(self): return '({0})'.format(', '.join(repr(item) for item in self.items)) def visit(self, env): + """ + If the environment is in the commands stage, check that the variable is a pulse or a delay. + If the environment is in the waveforms stage, visit each item in the sequence. + + Parameters + ---------- + env : Environment + """ if env.stage == env.stages.commands: for item in self.items: if isinstance(item, Delay): @@ -590,6 +731,9 @@ def visit(self, env): class Variable(ASTNode): + """ + Variable node. + """ names = ['name'] def __repr__(self): diff --git a/spacq/interface/resources.py b/spacq/interface/resources.py index bef1640..0a5e305 100755 --- a/spacq/interface/resources.py +++ b/spacq/interface/resources.py @@ -32,16 +32,18 @@ class NotWritable(Exception): class Resource(object): """ A generic resource which can potentially be read from or written to. + + Parameters + ---------- + obj : object, optional + getter : function or str, optional + setter : function or str, optional + converter : function, optional + """ def __init__(self, obj=None, getter=None, setter=None, converter=None, allowed_values=None): """ - obj: The device to which the resource belongs. - getter: The method used to get the value. - setter: The method used to set the value. - converter: A function which returns a valid value for the resource, given a string. - allowed_values: A set of all values which are valid for the resource. - The getter and setter can be actual methods, or just attribute/property name strings. """ @@ -85,6 +87,17 @@ def verify_dimensions(self, value, exception=True, from_string=False): Ensure that the type and dimensions of the value are as expected. If from_string is True, the value is expected to be a unit symbol string. + + Parameters + ---------- + value : object + exception : bool, optional + Whether to raise an exception if the value is not valid. + from_string : bool, optional + + Returns + ------- + Whether the value is valid. """ if from_string: @@ -114,7 +127,11 @@ def verify_dimensions(self, value, exception=True, from_string=False): @property def value(self): """ - The value of the resource. + Gets the value of the resource. + + Returns + ------- + The value. """ if self.getter is None: @@ -141,6 +158,13 @@ def value(self): @value.setter def value(self, v): + """ + Set the value of a resource, applying any necessary filters and validations. + + Parameters + ---------- + v : object + """ if self.setter is None: raise NotWritable('Resource not writable.') @@ -168,6 +192,14 @@ def value(self, v): def convert(self, value): """ Either use the specified converter, treat as a quantity, or do nothing. + + Parameters + ---------- + value : object + + Returns + ------- + The converted value. """ if self.converter is not None: @@ -191,6 +223,14 @@ def writable(self): def _find_wrapper_by_name(self, name): """ Return the last index of the given wrapper. + + Parameters + ---------- + name : str + + Returns + ------- + The index of the wrapper. """ for i, (n, _, _) in reversed(list(enumerate(self.wrappers))): @@ -202,8 +242,15 @@ def _find_wrapper_by_name(self, name): def is_wrapped_by(self, name): """ Determine whether the given wrapper already wraps this Resource. - """ + Parameters + ---------- + name : str + + Returns + ------- + Whether the given wrapper is present. + """ try: self._find_wrapper_by_name(name) except ValueError: @@ -215,9 +262,15 @@ def wrapped(self, name, getter_filter=None, setter_filter=None): """ Produce a Resource which is a wrapper around this Resource. - name: The name of the wrapper to add. - getter_filter: Function of one argument through which to pass any obtained values. - setter_filter: Function of one argument through which to pass values when setting. + Parameters + ---------- + name : str + getter_filter : function, optional + setter_filter : function, optional + + Returns + ------- + The wrapped Resource. """ result = copy(self) @@ -230,10 +283,15 @@ def wrapped(self, name, getter_filter=None, setter_filter=None): def unwrapped(self, name): """ Produce a Resource with the last instance of the given wrapper removed. - - name: The name of the wrapper to remove. + + Parameters + ---------- + name : str + + Returns + ------- + The unwrapped Resource. """ - result = copy(self) idx = self._find_wrapper_by_name(name) @@ -244,6 +302,14 @@ def unwrapped(self, name): def sweep(self, value_from, value_to, steps, delay=0.1, exception_callback=None): """ Sweep the Resource slowly over a linear space. + + Parameters + ---------- + value_from : object + value_to : object + steps : int + delay : float, optional + exception_callback : function, optional """ # Check for dimension mismatches. @@ -275,6 +341,15 @@ class AcquisitionThread(Thread): Once every delay, call the callback with a fresh value from the resource. An optional running lock can block execution until it is released elsewhere. + + Parameters + ---------- + delay : Quantity + callback : function + resource : Resource, optional + The resource to read from. If not specified, the callback will be called with no arguments. + running_lock : Lock, optional + A lock to block execution until it is released elsewhere. """ def __init__(self, delay, callback, resource=None, running_lock=None): @@ -294,6 +369,9 @@ def __init__(self, delay, callback, resource=None, running_lock=None): self.done = False def run(self): + """ + Run the thread. + """ while not self.done: # If something goes wrong, sleep the maximum. delay = self.delay.value diff --git a/spacq/interface/units.py b/spacq/interface/units.py index 6344e54..a546917 100755 --- a/spacq/interface/units.py +++ b/spacq/interface/units.py @@ -50,7 +50,7 @@ class SIValues(object): prefixes_ = dict([(v, k) for (k, v) in list(prefixes.items())]) # SI base units. Note the g instead of kg. - units = set(['A', 'cd', 'g', 'K', 'm', 'mol', 's']) + units = {'A', 'cd', 'g', 'K', 'm', 'mol', 's'} # SI derived units. Add more as necessary. units.update(['Hz', 'J', 'N', 'T', 'V', 'G']) @@ -67,7 +67,14 @@ def parse_units(string): Determine the multipliers and strip the prefixes. Use "*" and "**" to combine units. - eg. ' mN.m.ks-2' -> 'N*m*s**-2', 3 + Returns + ------- + The units in pq-acceptable notation. + + Example + -------- + >>> Quantity.parse_units(' mN.m.ks-2') + ('N*m*s**-2', 3) """ symbols = [x.strip() for x in string.split('.')] @@ -118,6 +125,16 @@ def parse_units(string): def from_string(string): """ Separate the value from the units. + + Returns + ------- + The value of the quantity. + The units of the quantity. + + Example + -------- + >>> Quantity.from_string('100 ms') + (100.0, 'ms') """ for i in range(len(string), 0, -1): @@ -191,14 +208,21 @@ def original_value(self): """ The magnitude of the quantity that matches the units. """ - return self._q.magnitude / (10 ** self.original_multiplier) def assert_dimensions(self, other, exception=True): """ - Whether the dimensions match. - If exception is True and we would have returned False, raise an exception. + + Parameters + ---------- + other : set + The dimensions to compare to. + exception : bool, optional + + Returns + ------- + Whether the dimensions match. """ if isinstance(other, str): diff --git a/spacq/interface/waveform.py b/spacq/interface/waveform.py index d1fc713..9852f86 100644 --- a/spacq/interface/waveform.py +++ b/spacq/interface/waveform.py @@ -15,6 +15,13 @@ class Generator(object): """ A generator for arbitrary waveforms. + + Parameters + ---------- + frequency : float + The sampling frequency. + dry_run : bool, optional + If True, do not generate a waveform. Useful for verifying the generating code. """ # Generation should fail if the number of points exceeds this value. @@ -39,6 +46,10 @@ def __init__(self, frequency, dry_run=False): def waveform(self): """ The waveform and marker data for the generated waveform. + + Returns + ------- + A Waveform tuple. """ try: @@ -57,6 +68,19 @@ def waveform(self): return Waveform(resulting_wave, marker_data) def check_length(self, additional): + """ + Checks if the resulting length of a waveform after adding additional points exceeds + the maximum length and raises a ValueError if it does. + + Parameters + ---------- + additional : int + The number of additional points to be added to the waveform. + + Raises + ------ + ValueError if the resulting length of the waveform exceeds the maximum length. + """ resulting_length = self.length + additional if resulting_length > self.max_length: @@ -71,6 +95,16 @@ def append(self, values): def _get_marker(self, num, length): """ Get the marker values for all data points in the waveform. + + Parameters + ---------- + num : int + The marker channel number. + length : int + + Returns + ------- + A list of marker values. """ result = [] @@ -95,6 +129,14 @@ def last_value(): def _parse_time(self, value): """ Convert a time value to a number of samples based on the frequency. + + Parameters + ---------- + value : Quantity + + Returns + ------- + The number of samples. """ log.debug('Parsing time "{0!r}" with frequency {1!r}'.format(value, self.frequency)) @@ -108,6 +150,16 @@ def _scale_waveform(self, data, amplitude=None, duration=None): Shorten or elongate a waveform in both axes. Due to the discrete nature of these waveforms, interpolation is used when changing duration. + + Parameters + ---------- + data : list + amplitude : float, optional + duration : Quantity, optional + + Returns + ------- + The scaled waveform data. """ if not data: @@ -135,6 +187,10 @@ def _scale_waveform(self, data, amplitude=None, duration=None): def set_next(self, value): """ Set the next point to have the given amplitude. + + Parameters + ---------- + value : float """ self.check_length(1) @@ -143,6 +199,12 @@ def set_next(self, value): def delay(self, value, less_points=1): """ Extend the last value of the waveform to last the length of the delay. + + Parameters + ---------- + value : Quantit + less_points : int, optional + The number of points to subtract from the delay length. """ delay_length = self._parse_time(value) - less_points @@ -159,6 +221,11 @@ def delay(self, value, less_points=1): def square(self, amplitude, length): """ Generate a square pulse. + + Parameters + ---------- + amplitude : float + length : Quantity """ try: @@ -173,6 +240,12 @@ def square(self, amplitude, length): def pulse(self, values, amplitude, duration): """ Literal amplitude values. + + Parameters + ---------- + values : list + amplitude : float + duration : Quantity """ data = self._scale_waveform(values, amplitude, duration) @@ -183,6 +256,12 @@ def pulse(self, values, amplitude, duration): def marker(self, num, value): """ Set the value of a marker starting from the current position. + + Parameters + ---------- + num : int + The marker channel number. + value : bool """ if self.dry_run: diff --git a/spacq/iteration/__init__.py b/spacq/iteration/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/spacq/iteration/sweep.py b/spacq/iteration/sweep.py index 610435d..2386f67 100755 --- a/spacq/iteration/sweep.py +++ b/spacq/iteration/sweep.py @@ -8,6 +8,13 @@ def update_current_f(f): + """ + Decorator to update the current function name. + + Parameters + ---------- + f : function + """ @wraps(f) def wrapped(self): self.current_f = f.__name__ @@ -22,6 +29,14 @@ def wrapped(self): class PulseConfiguration(object): """ The configuration necessary to execute a pulse program with a device. + + Parameters + ---------- + program : PulseProgram + channels : dict + A dictionary of output names and channel numbers + awg : object + oscilloscope : object """ # All the directly-used attributes. @@ -32,6 +47,20 @@ class PulseConfiguration(object): @staticmethod def verify_device(name, device, attributes): + """ + Verify that a device has the necessary attributes. + + Parameters + ---------- + name : str + device : object + attributes : list + + Raises + ------ + TypeError if the device is none or does not have the necessary attributes + + """ if device is None: raise TypeError('No "{0}" device configured'.format(name)) @@ -62,7 +91,22 @@ class SweepController(object): init -> next -> transition -> write -> dwell -> pulse -> read -> condition -> ramp_down -> end ^ ^ |_____________^ | | | |____________________________________________________________| | - |__________________________________________________________________________________| + |__________________________________________________________________________________| + + Parameters + ---------- + resources : list of tuples + A list of tuples containing the name and the resource object to be swept + variables : list of lists + num_items : int + measurement_resources : list of tuples + A list of tuples containing the name and the resource object to be measured + measurement_variables : list of lists + condition_resources : list of tuples, optional + A list of tuples containing the name and the resource object to be used for conditional waiting + condition_variables : list of lists, optional + pulse_config : PulseConfiguration, optional + continuous : bool, optional """ @@ -112,8 +156,10 @@ def __init__(self, resources, variables, num_items, measurement_resources, measu def compute_order_periods(self): """ - This function computes the number of elements iterated before each order changes. + Compute the number of elements iterated before each order changes and creates a + dictionary of order periods. """ + periods = [] orders = [] @@ -153,6 +199,14 @@ def compute_order_periods(self): def create_iterator(self, pos): """ Create an iterator for an order of variables. + + Parameters + ---------- + pos : int + + Returns + ------- + iterator """ return zip(*(iter(var) for var in self.variables[pos])) @@ -160,6 +214,15 @@ def create_iterator(self, pos): def ramp(self, resources, values_from, values_to, steps): """ Slowly sweep the resources. + + Parameters + ---------- + resources : list of tuples + A list of tuples containing the name and the resource object to be swept + values_from : list + values_to : list + steps : list + The number of steps to take between the starting value and ending value for each resource being swept """ thrs = [] @@ -185,6 +248,12 @@ def ramp(self, resources, values_from, values_to, steps): def write_resource(self, name, resource, value): """ Write a value to a resource and handle exceptions. + + Parameters + ---------- + name : str + resource : object + value : object """ try: @@ -197,6 +266,12 @@ def write_resource(self, name, resource, value): def read_resource(self, name, resource, save_callback): """ Read a value from a resource and handle exceptions. + + Parameters + ---------- + name : str + resource : object + save_callback : function """ try: @@ -210,7 +285,14 @@ def read_resource(self, name, resource, save_callback): def run(self, next_f=None): """ - Run the sweep. + Run the sweep by executing a sequence of functions until there are no more functions to + execute. + + Parameters + ---------- + next_f : function + The next function to execute in the loop. If next_f is not provided, the + initial function (self.init) is used as the starting point """ try: @@ -256,6 +338,10 @@ def run(self, next_f=None): def init(self): """ Initialize values and possibly devices. + + Returns + ------- + Start next step """ self.iterators = None @@ -284,7 +370,11 @@ def init(self): @update_current_f def next_values(self): """ - Get the next set of values from the iterators. + Get the next set of values from the iterators. + + Returns + ------- + Start transition step """ self.item += 1 @@ -321,6 +411,10 @@ def next_values(self): def transition(self): """ Perform a transition for variables, as required. + + Returns + ------- + Start write step """ if self.last_values is None: @@ -372,6 +466,10 @@ def transition(self): def write(self): """ Write the next values to their resources. + + Returns + ------- + Start dwelling """ thrs = [] @@ -396,6 +494,10 @@ def write(self): def dwell(self): """ Wait for all changed variables. + + Returns + ------- + Start read step if no pulse program, pulse otherwise """ delay = max( @@ -411,6 +513,10 @@ def dwell(self): def pulse(self): """ Run through the pulse program. + + Returns + ------- + Start read step """ if self.pulse_config.channels: @@ -488,6 +594,10 @@ def pulse(self): def read(self): """ Take measurements. + + Returns + ------- + Start condition step """ measurements = [None] * len(self.measurement_resources) @@ -523,10 +633,14 @@ def save_callback(value, i=i): @update_current_f def condition(self): """ - Stalls an order's loop (after the order's variables have been exhausted) - with repeated measurements until conditions are true. - Once conditions are true, then the sweep controller moves on to the next order - and continues as usual. + Stalls an order's loop (after the order's variables have been exhausted) with repeated measurements until conditions are true. + Once conditions are true, then the sweep controller moves on to the next order and continues as usual. + + Returns + ------- + Ramp down if conditions are true and all variables are exhausted + Go to next value if conditions are true and not all variables are exhausted + Dwell if conditions are false """ boolean = True @@ -569,6 +683,10 @@ def condition(self): def conditional_dwell(self): """ Dwell for the max time defined by the conditions in the current order. + + Returns + ------- + Start read process. """ sleep(self.conditional_wait) return self.read @@ -577,6 +695,10 @@ def conditional_dwell(self): def ramp_down(self): """ Sweep from the last values to const. + + Returns + ------- + Start the init step if continuous and not last_continuous. """ if not self.current_values: @@ -618,6 +740,9 @@ def end(self): self.close_callback() def pause(self): + """ + Pause the sweep. + """ log.debug('Pausing.') self.paused = True @@ -625,6 +750,9 @@ def pause(self): log.debug('Paused.') def unpause(self): + """ + Unpause the sweep. + """ log.debug('Unpausing.') with self.pause_lock: diff --git a/spacq/iteration/variables.py b/spacq/iteration/variables.py index 4ccaa98..bed320f 100755 --- a/spacq/iteration/variables.py +++ b/spacq/iteration/variables.py @@ -9,9 +9,14 @@ def sort_output_variables(variables): """ Sort and group the variables based on their order. - The returned values are: - variables sorted and grouped by their order - number of items in the Cartesian product of the orders + Parameters + ---------- + variables : list of OutputVariable + + Returns + ------- + variables sorted and grouped by their order + number of items in the Cartesian product of the orders """ # Ignore disabled variables entirely! @@ -43,14 +48,19 @@ def sort_output_variables(variables): return grouped, num_items + def sort_condition_variables(variables): """ Sort and group condition variables based on their order. This function is similar to sort_output_variables. - The returned value is: - variables sorted and grouped by their order + Parameters + ---------- + variables : list of ConditionVariable + Returns + ------- + variables sorted and grouped by their order """ # Ignore disabled variables entirely! @@ -65,9 +75,14 @@ def sort_condition_variables(variables): return grouped + class Variable(object): """ An abstract superclass for all variables. + Parameters + ---------- + name : str + enabled : bool """ def __init__(self, name, enabled=False): @@ -78,6 +93,13 @@ def __init__(self, name, enabled=False): class ConditionVariable(Variable): """ A condition variable. Used to define conditions to make loops in the sweep controller indefinite. + + Parameters + ---------- + order : int + resource_names : list of str + conditions : list of Condition + wait : str """ def __init__(self, order, resource_names=None, conditions=[], wait = '100 ms', *args, **kwargs): @@ -92,6 +114,10 @@ def evaluate_conditions(self, condition_resources=None): """ Checks the conditions where condition_resources contains the resources required to evaluate the conditions. + + Parameters + ---------- + condition_resources : list of 2-tuples (name, resource obj) """ # We take OR of all the conditions. boolean = False @@ -117,12 +143,21 @@ def wait(self, value): def __str__(self): return '['+', '.join(map(str,self.conditions))+']' + class Condition(object): """ A class used to represent a condition. + + Parameters + ---------- + type1 : str + type2 : str + arg1 : str + op_symbol : str + arg2 : str """ - allowed_types = set(['string', 'float', 'integer', 'quantity', 'resource name','resource']) + allowed_types = {'string', 'float', 'integer', 'quantity', 'resource name', 'resource'} def __init__(self, type1, type2, arg1, op_symbol, arg2): for type in [type1, type2]: @@ -137,7 +172,15 @@ def __init__(self, type1, type2, arg1, op_symbol, arg2): def evaluate(self, resources=None): """ - Evaluate a condition. 'resources' comes as a list of 2-tuples (name, resource obj). + Evaluate a condition. + + Parameters + ---------- + resources : list of 2-tuples (name, resource obj) + + Returns + ------- + True if the condition is satisfied, False otherwise. """ op = {'>':operator.gt, '==':operator.eq, '!=':operator.ne, '<':operator.lt} @@ -164,17 +207,17 @@ def evaluate(self, resources=None): return boolean - - def __str__(self): return '{0} {1} {2}'.format(self.arg1,self.op_symbol,self.arg2) - - class InputVariable(Variable): """ An input (measurement) variable. + + Parameters + ---------- + resource_name : str """ def __init__(self, resource_name='', *args, **kwargs): Variable.__init__(self, *args, **kwargs) @@ -185,6 +228,17 @@ def __init__(self, resource_name='', *args, **kwargs): class OutputVariable(Variable): """ An abstract superclass for output variables. + + Parameters + ---------- + order : int + config : Config + wait : str + The time to wait between each iteration. + const : float + The constant value to set the variable to. + use_const : bool + resource_name : str """ # Maximum number of initial values to display in string form. @@ -230,10 +284,13 @@ def wait(self, value): self._wait = wait - def with_type(self, value): """ Set to the correct type, and wrap with the correct units. + + Parameters + ---------- + value : float """ if self.type == 'integer': @@ -287,6 +344,12 @@ def __str__(self): class LinSpaceConfig(object): """ Linear space variable configuration. + + Parameters + ---------- + initial : float + final : float + steps : int """ def __init__(self, initial=0.0, final=0.0, steps=1): diff --git a/spacq/iteration/virtual_variables.py b/spacq/iteration/virtual_variables.py index 566098f..b79d565 100644 --- a/spacq/iteration/virtual_variables.py +++ b/spacq/iteration/virtual_variables.py @@ -26,7 +26,15 @@ def wrapped(self): # currently in config/variables.py like linspaceConfig class virtLinSpaceConfig(object): """ - Like LinSpaceConfig but with order... + Like LinSpaceConfig but with order. + + Parameters + ---------- + name : str + initial : float + final : float + steps : int + order : int """ def __init__(self, name='var', initial=0.0, final=0.0, steps=1, order=1): self.name = name @@ -58,26 +66,43 @@ def __iter__(self): def __len__(self): return self.steps + class DependentConfig(object): """ - Like LinSpaceConfig but with order... + Like LinSpaceConfig but with order. + + Parameters + ---------- + name : str + expression : str """ def __init__(self, name='var', expression='1'): self.name = name self.expression = expression - def DependentFunctionMath(self, virt_headings, virt_values): + """ + This function takes the expression and evaluates it with the virtual values. + + Parameters + ---------- + virt_headings : list + virt_values : list + + Returns + ------- + The result of the expression. + """ editExpression = self.expression - for i,heading in enumerate(virt_headings): + for i, heading in enumerate(virt_headings): # shouldnt be issue because disabled are always on tail? - editExpression = editExpression.replace(heading,'virt_values[:,{0}]'.format(i)) + editExpression = editExpression.replace(heading, 'virt_values[:,{0}]'.format(i)) # if nothing gets entered for a enabled variable if editExpression is None or editExpression == '': - result = numpy.zeros((1,len(virt_values)))[0] + result = numpy.zeros((1, len(virt_values)))[0] else: try: # Allows for constant input @@ -93,8 +118,17 @@ def DependentFunctionMath(self, virt_headings, virt_values): return result + # something like SweepController: class virtSweepController(object): + """ + Parameters + ---------- + variables : list + The list of virtual variables. + num_items : int + + """ def __init__(self, variables, num_items): # Sorted by order at this point @@ -111,7 +145,7 @@ def __init__(self, variables, num_items): self.names.append(var.name) # for writing to csv - self.value_history = numpy.zeros([self.num_items,self.var_count]) + self.value_history = numpy.zeros([self.num_items, self.var_count]) # Count for iterations of needed outputs self.item = -1 @@ -120,7 +154,6 @@ def __init__(self, variables, num_items): self.orders = [vars[0].order for vars in self.variables] self.orders.reverse() - def compute_order_periods(self): """ This function computes the number of elements iterated before each order changes. @@ -161,7 +194,6 @@ def create_iterator(self, pos): # maybe some renaming def sweepTable(self): - """ Initialize values and possibly devices. """ @@ -218,20 +250,24 @@ def sweepTable(self): # fills in value_history counter = 0 for pos in self.full_indices[0:]: - for i, (var,value) in enumerate(zip(self.variables[pos],self.current_values[pos])): + for i, (var, value) in enumerate(zip(self.variables[pos], self.current_values[pos])): self.value_history[self.item][counter] = value counter += 1 - # copeid from iteration/variables.py def sort_output_variables(variables): """ Sort and group the variables based on their order. - The returned values are: - variables sorted and grouped by their order - number of items in the Cartesian product of the orders + Parameters + ---------- + variables : list + + Returns + ------- + List of variables sorted and grouped by their order + Number of items in the Cartesian product of the orders """ # Ignore disabled variables entirely! diff --git a/spacq/tests/__init__.py b/spacq/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/spacq/tests/tool/__init__.py b/spacq/tests/tool/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/spacq/tool/__init__.py b/spacq/tool/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/spacq/tool/box.py b/spacq/tool/box.py index fff3d2b..77baa03 100644 --- a/spacq/tool/box.py +++ b/spacq/tool/box.py @@ -12,6 +12,15 @@ def flatten(iterable): """ Flatten an iterable by one level. + + Parameters + ---------- + iterable : iterable + + Example + ------- + >>> list(flatten([[1, 2], [3, 4]])) + [1, 2, 3, 4] """ return chain.from_iterable(iterable) @@ -20,21 +29,61 @@ def flatten(iterable): def sift(items, cls): """ Filter out items which are not instances of cls. + + Parameters + ---------- + items : iterable + cls : type + The class to filter by. + + Example + ------- + >>> list(sift([1, 2, 'a', 'b'], str)) + ['a', 'b'] """ return [item for item in items if isinstance(item, cls)] + def get_mask(x,y, tx, ty): - dx = (tx[-1] - tx[0])/(tx.size -1) - dy = (ty[-1] - ty[0])/(ty.size -1) + """ + The function calculates a mask based on the distance between two sets of coordinates and returns it. + + Parameters + ---------- + x : array + The x-coordinates of the data points. + y : array + The y-coordinates of the data points. + tx : array + The x-coordinates of the grid. + ty : array + The y-coordinates of the grid. + + Returns + ------- + A 2D array representing a mask for the given set of x and y coordinates and a set of tx and ty coordinates. + + Example + ------- + >>> x = linspace(0, 10, 11) + >>> y = linspace(0, 10, 11) + >>> tx = linspace(0, 10, 21) + >>> ty = linspace(0, 10, 21) + >>> mask = get_mask(x, y, tx, ty) + >>> mask.shape + (21, 21) + """ + dx = (tx[-1] - tx[0]) / (tx.size - 1) + dy = (ty[-1] - ty[0]) / (ty.size - 1) - d2 = dx**2 + dy**2 + d2 = dx ** 2 + dy ** 2 - xgrid = meshgrid(x,tx) - ygrid = meshgrid(y,ty) + xgrid = meshgrid(x, tx) + ygrid = meshgrid(y, ty) - xdist = (xgrid[0] - xgrid[1])**2 - ydist = (ygrid[0] - ygrid[1])**2 + xdist = (xgrid[0] - xgrid[1]) ** 2 + ydist = (ygrid[0] - ygrid[1]) ** 2 mask = ones((tx.shape[0], ty.shape[0])) @@ -42,7 +91,7 @@ def get_mask(x,y, tx, ty): for j in range (mask.shape[1]): mask[i,j] = npmin(xdist[i] + ydist[j]) - mask = (mask < d2)*1 + mask = mask < d2 mask = where(mask, mask, nan) return mask.T @@ -53,18 +102,48 @@ def triples_to_mesh(x, y, z, max_mesh=[-1,-1], has_mask=False): """ Convert 3 equal-sized lists of co-ordinates into an interpolated 2D mesh of z-values. - Returns a tuple of: - the mesh - the x bounds - the y bounds - the z bounds + Parameters + ---------- + x : array + The x-coordinates of the data points. + y : array + The y-coordinates of the data points. + z : array + The z-coordinates of the data points. + max_mesh : array + The maximum size of the mesh to be returned. If the value is negative, the mesh will be + returned with the same size as the data points. + has_mask : bool + Whether or not to apply a mask to the data. + + Returns + ------- + the mesh + the x bounds + the y bounds + the z bounds + + Example + ------- + >>> x = linspace(0, 10, 11) + >>> y = linspace(0, 10, 11) + >>> z = linspace(0, 10, 11) + >>> mesh, x_bounds, y_bounds, z_bounds = triples_to_mesh(x, y, z) + >>> mesh.shape + (11, 11) + >>> x_bounds + (0.0, 10.0) + >>> y_bounds + (0.0, 10.0) + >>> z_bounds + (0.0, 10.0) """ x_values, y_values = sort(unique(x)), sort(unique(y)) - if (all (item > 0 for item in max_mesh)): - display_len_x = min (len(x_values), max_mesh[0]) - display_len_y = min (len(y_values), max_mesh[1]) + if all(item > 0 for item in max_mesh): + display_len_x = min(len(x_values), max_mesh[0]) + display_len_y = min(len(y_values), max_mesh[1]) else: display_len_x = len(x_values) display_len_y = len(y_values) @@ -76,43 +155,72 @@ def triples_to_mesh(x, y, z, max_mesh=[-1,-1], has_mask=False): target_z = griddata((x, y), z, (target_x, target_y), method='cubic') - if (has_mask): - mask = get_mask (x, y, x_space, y_space) + if has_mask: + mask = get_mask(x, y, x_space, y_space) target_z = target_z * mask return (target_z, (x_values[0], x_values[-1]), (y_values[0], y_values[-1]), (min(z), max(z))) + def triples_to_mesh_y(x, y, z, max_mesh=[-1,-1]): """ Convert 3 equal-sized lists of co-ordinates into an interpolated mesh of z-values; with interpolation along the y-axis only. The x-data must be of the form - [x0,x0,x0...x1,x1,x1...,xn,xn,xn...xn] with each value xi repeaded the same number of times. - Otherwiese unexpected behaviour follows. - - Returns a tuple of: - the mesh - the x bounds - the y bounds - the z bounds + [x0, x0, x0, ..., x1, x1, x1, ..., xn, xn, xn, ..., xn] with each value xi repeated the same number of times. + Otherwise unexpected behavior follows. + + Parameters + ---------- + x : array + The x-coordinates of the data points. + y : array + The y-coordinates of the data points. + z : array + The z-coordinates of the data points. + max_mesh : array + The maximum size of the mesh to be returned. If the value is negative, the mesh will be + returned with the same size as the data points. + + Returns + ------- + the mesh + the x bounds + the y bounds + the z bounds + + Example + ------- + >>> x = linspace(0, 10, 11) + >>> y = linspace(0, 10, 11) + >>> z = x * y + >>> mesh, x_bounds, y_bounds, z_bounds = triples_to_mesh_y(x, y, z) + >>> mesh.shape + (11, 11) + >>> x_bounds + (0.0, 10.0) + >>> y_bounds + (0.0, 10.0) + >>> z_bounds + (0.0, 100.0) """ x_values, y_values = sort(unique(x)), sort(unique(y)) display_len_x = len(x_values) - if (max_mesh[1]>0): + if (max_mesh[1] > 0): display_len_y = min (len(y_values), max_mesh[1]) else: display_len_y = len(y_values) x_space = x_values y_space = linspace(y_values[0], y_values[-1], display_len_y) - xperiod = float(len(x)) / len(x_values) + x_period = float(len(x)) / len(x_values) target_z = zeros([display_len_x, display_len_y]) for i, xi in enumerate(x_space): - yrange = arange(i*xperiod, (i+1)*xperiod-1).tolist() - fy = interp1d (y[yrange], z[yrange], kind='cubic', bounds_error=False) + y_range = arange(i * x_period, (i + 1) * x_period - 1).tolist() + fy = interp1d (y[y_range], z[y_range], kind='cubic', bounds_error=False) tempy = fy(y_space) target_z[i] = tempy @@ -128,6 +236,8 @@ class Enum(set): """ An enumerated type. + Example + ------- >>> e = Enum(['a', 'b', 'c']) >>> e.a 'a' @@ -146,15 +256,15 @@ def __getattribute__(self, name): class PubDict(dict): """ A locking, publishing dictionary. + + Parameters + ---------- + lock: A re-entrant lock which supports context management. + send: Message-sending method of a PubSub publisher. + topic: The topic on which to send messages. """ def __init__(self, lock, send, topic, *args, **kwargs): - """ - lock: A re-entrant lock which supports context management. - send: Message-sending method of a PubSub publisher. - topic: The topic on which to send messages. - """ - dict.__init__(self, *args, **kwargs) self.lock = lock