class Block(Declarative): name = d_(Unicode()) label = d_(Unicode()) compact_label = d_(Unicode()) factory = d_(Callable()) context_name_map = Typed(dict) blocks = Property() parameters = Property() hide = d_(List()) def initialize(self): super().initialize() for p in self.parameters: if p.name in self.hide: p.visible = False def get_children(self, child_type): return [c for c in self.children if isinstance(c, child_type)] def _get_blocks(self): return self.get_children(Block) def _get_parameters(self): return self.get_children(Parameter)
class BaseOutput(PSIContribution): name = d_(Str()).tag(metadata=True) label = d_(Str()).tag(metadata=True) target_name = d_(Str()).tag(metadata=True) target = d_(Typed(Declarative).tag(metadata=True), writable=False) channel = Property().tag(metadata=True) engine = Property().tag(metadata=True) def _default_label(self): return self.name def _get_engine(self): if self.channel is None: return None else: return self.channel.engine def _get_channel(self): from .channel import Channel target = self.target while True: if target is None: return None elif isinstance(target, Channel): return target else: target = target.target def is_ready(self): raise NotImplementedError
class Dummy(Model): _private = Int() computed = Int().tag(store=False) id = Int() enabled = Bool() string = Bool() list_of_int = List(int) list_of_str = List(str) list_of_any = List() list_of_tuple = List(Tuple()) list_of_tuple_of_float = List(Tuple(float)) tuple_of_any = Tuple() tuple_of_number = Tuple((float, int)) tuple_of_int_or_model = Tuple((int, Model)) tuple_of_forwarded = Tuple(ForwardTyped(lambda: NotYetDefined)) set_of_any = Tuple() set_of_number = Set(float) set_of_model = Set(AbstractModel) dict_of_any = Dict() dict_of_str_any = Dict(str) dict_of_str_int = Dict(str, int) typed_int = Typed(int) typed_dict = Typed(dict) instance_of_model = Instance(AbstractModel) forwarded_instance = ForwardInstance(lambda: NotYetDefined) coerced_int = Coerced(int) prop = Property(lambda self: True) tagged_prop = Property(lambda self: 0).tag(store=True)
class NIDAQHardwareAOChannel4461(NIDAQHardwareAOChannel): ''' Special channel that automatically compensates for filter delay of PXI 4461 card. ''' #: Filter delay lookup table for different sampling rates. The first column #: is the lower bound (exclusive) of the sampling rate (in samples/sec) for #: the filter delay (second column, in samples). The upper bound of the #: range (inclusive) for the sampling rate is denoted by the next row. #: e.g., if FILTER_DELAY[i, 0] < fs <= FILTER_DELAY[i+1, 0] is True, then #: the filter delay is FILTER_DELAY[i, 1]. FILTER_DELAY = np.array([ ( 1.0e3, 36.6), ( 1.6e3, 36.8), ( 3.2e3, 37.4), ( 6.4e3, 38.5), ( 12.8e3, 40.8), ( 25.6e3, 43.2), ( 51.2e3, 48.0), (102.4e3, 32.0), ]) filter_delay = Property().tag(metadata=True) filter_delay_samples = Property().tag(metadata=True) def _get_filter_delay_samples(self): i = np.flatnonzero(self.fs > self.FILTER_DELAY[:, 0])[-1] return self.FILTER_DELAY[i, 1] def _get_filter_delay(self): return self.filter_delay_samples / self.fs
class Channel(PSIContribution): #: Globally-unique name of channel used for identification name = d_(Unicode()).tag(metadata=True) #: Label of channel used in GUI label = d_(Unicode()).tag(metadata=True) #: Is channel active during experiment? active = Property() # SI unit (e.g., V) unit = d_(Unicode()).tag(metadata=True) # Number of samples to acquire before task ends. Typically will be set to # 0 to indicate continuous acquisition. samples = d_(Int(0)).tag(metadata=True) # Used to properly configure data storage. dtype = d_(Unicode()).tag(metadata=True) # Parent engine (automatically derived by Enaml hierarchy) engine = Property() # Calibration of channel calibration = d_(Typed(Calibration, factory=UnityCalibration)) calibration.tag(metadata=True) # Can the user modify the channel calibration? calibration_user_editable = d_(Bool(False)) # Is channel active during experiment? active = Property() filter_delay = d_(Float(0).tag(metadata=True)) def _default_calibration(self): return UnityCalibration() def __init__(self, *args, **kwargs): # This is a hack due to the fact that name is defined as a Declarative # member and each Mixin will overwrite whether or not the name is # tagged. super().__init__(*args, **kwargs) self.members()['name'].tag(metadata=True) def _get_engine(self): return self.parent def _set_engine(self, engine): self.set_parent(engine) def configure(self): pass def _get_active(self): raise NotImplementedError def __str__(self): return self.label
class Synchronized(PSIContribution): outputs = Property() engines = Property() def _get_outputs(self): return self.children def _get_engines(self): return set(o.engine for o in self.outputs)
class _Clipboard(Atom): """ The _Clipboard class provides a wrapper around the PyQt clipboard. """ # --- Members definitions ------------------------------------------------- #: The instance on the clipboard (if any). instance = Property() #: Set if the clipboard contains an instance. has_instance = Property() #: The type of the instance on the clipboard (if any). instance_type = Property() # --- Instance property methods ------------------------------------------- @instance.getter def _instance_getter(self): """ The instance getter. """ md = PyMimeData.coerce(QtGui.QApplication.clipboard().mimeData()) if md is None: return None return md.instance() @instance.setter def _instance_setter(self, data): """ The instance setter. """ QtGui.QApplication.clipboard().setMimeData(PyMimeData(data)) @has_instance.getter def _has_instance_getter(self): """ The has_instance getter. """ clipboard = QtGui.QApplication.clipboard() return clipboard.mimeData().hasFormat(PyMimeData.MIME_TYPE) @instance_type.getter def _instance_type_getter(self): """ The instance_type getter. """ md = PyMimeData.coerce(QtGui.QApplication.clipboard().mimeData()) if md is None: return None return md.instance_type()
def test_enforce_read_only_cached_property(): """Check a cached property has to be read-only.""" def get(self): pass def set(self, value): pass with pytest.raises(ValueError): Property(get, set, cached=True) with pytest.raises(ValueError): p = Property(cached=True) p.setter(set)
class IInterface(BaseInterface): """Base class to use when writing an interface interface. The interface should not re-use member names used by the task or parent interfaces to avoid issue when walking. """ #: A reference to the parent interface to which this interface is linked. parent = Typed(BaseInterface) #: Direct access to the task, which acts as a root parent. task = Property(cached=True) @task.getter def _get_task(self): return self.parent.task def _post_setattr_parent(self, old, new): """Reset the task property and update the interface anchor. """ if new: self.interface_id = (type(self).__name__, self.parent.interface_id[1] + (self.parent.interface_id[0], )) else: self.interface_id = (type(self).__name__, ) task_member = self.get_member(str('task')) # Python 2, Atom 0.x compat task_member.reset(self)
class SingleInstrPref(Atom): """ """ title = Str().tag(pref=True) check_corrupt = Bool().tag(pref=True) corrupt_time = Float(5).tag(pref=True) fast_refresh = Bool().tag(pref=True) fast_refresh_time = Float(1).tag(pref=True) refresh_time = Float(60).tag(pref=True) preferences = Property() _can_check_corrupt = Bool() _has_fast_refresh = Bool() def __init__(self, model_type): super(SingleInstrPref, self).__init__() self._can_check_corrupt = \ bool(model_type._check_driver_state.__func__ is not SingleInstrPanel._check_driver_state.__func__) self._has_fast_refresh = \ bool(model_type.fast_refresh_members.default_value_mode[1]) @preferences.getter def preferences(self): return { name: str(getattr(self, name)) for name in tagged_members(self, meta='pref') }
class IIRFilter(ContinuousInput): # Allows user to deactivate the filter entirely during configuration if # desired. Ideally we could just remove it from the graph, but it seems a # bit tricky to do so as some other components may be looking for the # output of this block. passthrough = d_(Bool(False)).tag(metadata=True) N = d_(Int(1)).tag(metadata=True) btype = d_(Enum('bandpass', 'lowpass', 'highpass', 'bandstop')).tag(metadata=True) ftype = d_(Enum('butter', 'cheby1', 'cheby2', 'ellip', 'bessel')).tag(metadata=True) f_highpass = d_(Float()).tag(metadata=True) f_lowpass = d_(Float()).tag(metadata=True) Wn = Property().tag(metadata=True) def _get_Wn(self): if self.btype == 'lowpass': return self.f_lowpass elif self.btype == 'highpass': return self.f_highpass else: return (self.f_highpass, self.f_lowpass) def configure_callback(self): cb = super().configure_callback() if self.passthrough: return cb return pipeline.iirfilter(self.fs, self.N, self.Wn, None, None, self.btype, self.ftype, cb).send
def test_property_mode_args_validation(mode, func): """Test that a delegator properly validate the arguments when setting mode. """ with pytest.raises(TypeError) as excinfo: getattr(Property(), func)(getattr(mode, 'Property'), 1) assert 'callable or None' in excinfo.exconly()
class IInterface(BaseInterface): """Base class to use when writing an interface interface. The interface should not re-use member names used by the task or parent interfaces to avoid issue when walking. """ #: A reference to the parent interface to which this interface is linked. parent = Typed(BaseInterface) #: Direct access to the task, which acts as a root parent. task = Property(cached=True) @task.getter def _get_task(self): return self.parent.task def _post_setattr_parent(self, old, new): """Reset the task property and update the interface anchor. """ pack, _ = self.__module__.split('.', 1) i_id = pack + '.' + type(self).__name__ if new: self.interface_id = self.parent.interface_id + ':' + i_id else: self.interface_id = i_id task_member = self.get_member('task') task_member.reset(self)
class AbstractWidgetItemGroup(Control): #: Triggered when clicked clicked = d_(Event(), writable=False) #: Triggered when double clicked double_clicked = d_(Event(), writable=False) #: Triggered when the row, column, or item is entered entered = d_(Event(), writable=False) #: Triggered when the row, column, or item is pressed pressed = d_(Event(), writable=False) #: Triggered when the row, column, or item's selection changes selection_changed = d_(Event(bool), writable=False) def _get_items(self): return [c for c in self.children if isinstance(c, AbstractWidgetItem)] #: Internal item reference _items = Property(lambda self: self._get_items(), cached=True) def child_added(self, child): """ Reset the item cache when a child is added """ super(AbstractWidgetItemGroup, self).child_added(child) self.get_member('_items').reset(self) def child_removed(self, child): """ Reset the item cache when a child is removed """ super(AbstractWidgetItemGroup, self).child_removed(child) self.get_member('_items').reset(self)
class ModelManager(Atom): """ A descriptor so you can use this somewhat like Django's models. Assuming your using motor. Examples -------- MyModel.objects.find_one({'_id':'someid}) """ #: Stores instances of each class so we can easily reuse them if desired _instances = {} @classmethod def instance(cls): if cls not in ModelManager._instances: ModelManager._instances[cls] = cls() return ModelManager._instances[cls] def _get_database(self): db = WebApplication.instance().database if db is None: raise EnvironmentError("No database set!") return db #: Used to access the database database = Property(_get_database) def __get__(self, obj, cls=None): """ Handle objects from the class that owns the manager. Subclasses should override this as needed. """ raise NotImplementedError
class ExecutableGraph(model.Graph): controller = ForwardInstance(_import_graph_calculator_controller) nxgraph = Property(lambda self: self._get_nxgraph(), cached=True) topologyChanged = Event() valuesChanged = Event() attributesChanged = Event() def _get_nxgraph(self): g = nx.MultiDiGraph() for node in self.nodes: g.add_node(node.id, id=node.id, name=node.name) for edge in self.edges: g.add_edge(edge.start_socket.node.id, edge.end_socket.node.id, id=edge.id, source_socket=edge.start_socket.name, target_socket=edge.end_socket.name) return g def _observe_topologyChanged(self, change): self.get_member('nxgraph').reset(self) self.execute_graph() def _observe_valuesChanged(self, change): self.execute_graph() def _observe_attributesChanged(self, change): self.execute_graph() def execute_graph(self): for node_id in nx.topological_sort(self.nxgraph): self.node_dict[node_id].update()
class AbstractQtWidgetItemGroup(QtControl, ProxyAbstractWidgetItemGroup): #: Context menu for this group menu = Instance(QtMenu) def _get_items(self): return [c for c in self.children() if isinstance(c,AbstractQtWidgetItem)] #: Internal items #: TODO: Is a cached property the right thing to use here?? #: Why not a list?? _items = Property(lambda self:self._get_items(),cached=True) def init_layout(self): for child in self.children(): if isinstance(child, QtMenu): self.menu = child def refresh_style_sheet(self): pass # Takes a lot of time def child_added(self, child): super(AbstractQtWidgetItemGroup, self).child_added(child) self.get_member('_items').reset(self) def child_removed(self, child): super(AbstractQtWidgetItemGroup, self).child_removed(child) self.get_member('_items').reset(self)
class OutputMixin(Declarative): outputs = List().tag(metadata=True) buffer_size = Property().tag(metadata=True) def _get_active(self): return len(self.outputs) > 0 def add_output(self, o): if o in self.outputs: return self.outputs.append(o) o.target = self def remove_output(self, o): if o not in self.outputs: return self.outputs.remove(o) o.target = None def add_queued_epoch_output(self, queue, auto_decrement=True): # Subclasses of Enaml Declarative will automatically insert themselves # as children of the parent when initialized. o = QueuedEpochOutput(queue=queue, auto_decrement=auto_decrement) self.add_output(o) return o def _get_buffer_size(self): return self.engine.get_buffer_size(self.name)
class FormulaModel(Atom): """Base class to provide reference to the registered api.""" api = Property() _api = Typed(API) def _get_api(self): if registry.api is not None: return registry.api else: raise EnvironmentError('API has not been registered.') def _set_api(self, api): self._api = api @property def __id__(self): return self.__str__() @classmethod def from_dict(cls, kwargs): raise NotImplementedError def to_row(self): raise NotImplementedError
class Node(GraphItem): id = Str() name = Unicode() graph = ForwardTyped(import_graph_type) inputs = ContainerList(Socket) outputs = ContainerList(Socket) input_dict = Property(lambda self: self._mk_input_dict(), cached=True) output_dict = Property(lambda self: self._mk_output_dict(), cached=True) def _observe_inputs(self, change): if change['type'] == 'create': for n in change['value']: n.node = self n.socket_type = SocketType.INPUT n.index = change['value'].index(n) elif change['type'] == 'container': if change['operation'] == 'append': change['item'].node = self change['item'].socket_type = SocketType.INPUT change['item'].index = change['value'].index(n) elif change['operation'] == 'remove': change['item'].node = None self.get_member('input_dict').reset(self) def _mk_input_dict(self): return {v.name: v for v in self.inputs} def _observe_outputs(self, change): if change['type'] == 'create': for n in change['value']: n.node = self n.socket_type = SocketType.OUTPUT n.index = change['value'].index(n) elif change['type'] == 'container': if change['operation'] == 'append': change['item'].node = self change['item'].socket_type = SocketType.OUTPUT change['item'].index = change['value'].index(n) elif change['operation'] == 'remove': change['item'].node = None self.get_member('output_dict').reset(self) def _mk_output_dict(self): return {v.name: v for v in self.outputs}
class ComboBox(Control): """ A drop-down list from which one item can be selected at a time. Use a combo box to select a single item from a collection of items. See `ObjectCombo` for a more robust combo box control. """ #: The strings to display in the combo box. items = d_(List(Unicode())) #: The integer index of the currently selected item. If the index #: falls outside the range of items, the item will be deselected. index = d_(Int(-1)) #: A read only cached property which returns the selected item. selected_item = d_(Property(cached=True), writable=False) #: Whether the text in the combo box can be edited by the user. editable = d_(Bool(False)) #: A combo box hugs its width weakly by default. hug_width = set_default('weak') #: A reference to the ProxyComboBox object. proxy = Typed(ProxyComboBox) @selected_item.getter def get_selected_item(self): """ The getter function for the selected item property. If the index falls out of range, the selected item will be an empty string. """ items = self.items idx = self.index if idx < 0 or idx >= len(items): return u'' return items[idx] #-------------------------------------------------------------------------- # Observers #-------------------------------------------------------------------------- @observe('index', 'items', 'editable') def _update_proxy(self, change): """ An observer which sends state change to the proxy. """ # The superclass handler implementation is sufficient. super(ComboBox, self)._update_proxy(change) @observe('index', 'items') def _reset_selected_item(self, change): """ Reset the selected item when the index or items changes. """ if change['type'] == 'update': self.get_member('selected_item').reset(self)
class PSIManifest(PluginManifest): contribution = Typed(PSIContribution) id = Property(cached=True) def _get_id(self): class_type = self.__class__.__name__ return f'{self.contribution.name}.{class_type}'
class Driver(FormulaModel): birth_date = Typed(datetime.datetime) driverId = Unicode() shortId = Coerced(str) last = Unicode() first = Unicode() country = Unicode() url = Unicode() number = Coerced(int) seasons = Property() _seasons = Typed(Seasons) def _get_seasons(self): if not self._seasons: self.seasons = Seasons( self.api.query(driver_id=self.driverId, query_type='seasons')) return self._seasons def _set_seasons(self, seasons): self._seasons = seasons @classmethod def from_dict(cls, kwargs): if 'dateOfBirth' in kwargs.keys(): dob = kwargs.pop('dateOfBirth') if dob: kwargs['birth_date'] = datetime.datetime.strptime( dob, '%Y-%m-%d') kwargs['last'] = kwargs.pop('familyName') kwargs['first'] = kwargs.pop('givenName') kwargs['country'] = kwargs.pop('nationality') if 'permanentNumber' in kwargs.keys(): kwargs['number'] = kwargs.pop('permanentNumber') if 'code' in kwargs.keys(): kwargs['shortId'] = kwargs.pop('code', None) return cls(**kwargs) def __str__(self): return str(self.driverId) def __repr__(self): return str(self.first + ' ' + self.last) def to_row(self): return { 'birth_date': self.birth_date, 'driverId': self.driverId, 'shortId': self.shortId, 'last': self.last, 'first': self.first, 'country': self.country, 'number': self.number, 'object': self }
def _load_state(self, extension): """ Create a custom _StateHolder class at runtime and instantiate it Parameters ---------- extension : Extension Extension contributing to the state extension point for which a custom _StateHolder class should be build Returns ------- state_tuple: tuple Tuple containing the State declaration used to build the state holder, the custom class derived _StateHolder dynamically created, an instance of this class observing the plugin contributing the extension """ # Getting the state declaration contributed by the extension, either # as a child or returned by the factory. Only the first state is # considered. # TODO add support for arbitrary number of state per extension # TODO add support for dotted_names as sync_member workbench = self.workbench states = extension.get_children(State) if extension.factory is not None and not states: state = extension.factory(workbench) if not isinstance(state, State): msg = "extension '%s' created non-State of type '%s'" args = (extension.qualified_id, type(state).__name__) raise TypeError(msg % args) else: state = states[0] # Dynamic building of the state class # TODO add check sync_members and prop not confincting class_name = str(state.id.replace('.', '').capitalize()) members = {} for m in state.sync_members: members[m] = Value() for p in state.prop_getters: members[p] = Property() state_class = classobj(class_name, (_StateHolder,), members) # Instantiation , initialisation, and binding of the state object to # the plugin declaring it. state_object = state_class() plugin = workbench.get_plugin(extension.plugin_id) for m in state.sync_members: with state_object.setting_allowed(): setattr(state_object, m, getattr(plugin, m)) plugin.observe(m, state_object.updater) for p in state.prop_getters: prop = state_object.get_member(p) prop.getter(getattr(plugin, state.prop_getters[p])) return (state, state_class, state_object)
class FlatCalibration(Calibration): sensitivity = Float().tag(metadata=True) fixed_gain = Float().tag(metadata=True) mv_pa = Property() def _get_mv_pa(self): return util.dbi(self.sensitivity) * 1e3 def _set_mv_pa(self, value): self.sensitivity = util.db(value * 1e-3) @classmethod def as_attenuation(cls, vrms=1, **kwargs): ''' Allows levels to be specified in dB attenuation ''' return cls.from_spl(0, vrms, **kwargs) @classmethod def from_spl(cls, spl, vrms=1, **kwargs): ''' Generates a calibration object based on the recorded SPL Parameters ---------- spl : array-like List of magnitudes (e.g., speaker output in SPL) for the specified RMS voltage. vrms : float RMS voltage (in Volts) Additional kwargs are passed to the class initialization. ''' sensitivity = util.db(vrms)-spl-util.db(20e-6) return cls(sensitivity, **kwargs) @classmethod def from_mv_pa(cls, mv_pa, **kwargs): sens = util.db(mv_pa*1e-3) return cls(sens, **kwargs) def __init__(self, sensitivity, fixed_gain=0, source=None): ''' Parameters ---------- sensitivity : float Sensitivity of system in dB(V/Pa). ''' self.sensitivity = sensitivity self.fixed_gain = fixed_gain if source is not None: self.source = Path(source) def get_sens(self, frequency): return self.sensitivity-self.fixed_gain
class BBox(Atom): xmin = Float() ymin = Float() zmin = Float() xmax = Float() ymax = Float() zmax = Float() def _get_dx(self): return self.xmax - self.xmin dx = Property(_get_dx, cached=True) def _get_dy(self): return self.ymax - self.ymin dy = Property(_get_dy, cached=True) def _get_dz(self): return self.zmax - self.zmin dz = Property(_get_dz, cached=True) def __init__(self, xmin=0, ymin=0, zmin=0, xmax=0, ymax=0, zmax=0): super(BBox, self).__init__(xmin=xmin, ymin=ymin, zmin=zmin, xmax=xmax, ymax=ymax, zmax=zmax) def __getitem__(self, key): return (self.xmin, self.ymin, self.zmin, self.xmax, self.ymax, self.zmax)[key] def _get_center(self): return Point((self.xmin + self.xmax) / 2, (self.ymin + self.ymax) / 2, (self.zmin + self.zmax) / 2) center = Property(_get_center, cached=True) def _get_diagonal(self): return math.sqrt(self.dx**2 + self.dy**2 + self.dz**2) diagonal = Property(_get_diagonal, cached=True) def _get_min(self): return Point(self.xmin, self.ymin, self.zmin) def _get_max(self): return Point(self.xmax, self.xmax, self.xmax) min = Property(_get_min) max = Property(_get_max) def __repr__(self): return "<BBox: x=%s y=%s z=%s w=%s h=%s d=%s>" % ( self.xmin, self.ymin, self.zmin, self.dx, self.dy, self.dz)
class TreeViewItem(AbstractWidgetItem): #: Proxy reference proxy = Typed(ProxyTreeViewItem) #: The child items items = d_(ContainerList(default=[])) #: First visible row visible_row = d_(Int(0)) #: Number of rows visible visible_rows = d_(Int(100)) #: First visible column visible_column = d_(Int(0)) #: Number of columns visible visible_columns = d_(Int(1)) def _get_items(self): """ Items should be a list of child TreeViewItems excluding columns. """ return [c for c in self.children if isinstance(c, TreeViewItem)] def _get_columns(self): """ List of child TreeViewColumns including this item as the first column """ return [self] + [ c for c in self.children if isinstance(c, TreeViewColumn) ] #: Columns _columns = Property(lambda self: self._get_columns(), cached=True) def child_added(self, child): super(TreeViewItem, self).child_added(child) self.get_member('_columns').reset(self) self._update_rows() def child_removed(self, child): super(TreeViewItem, self).child_removed(child) self.get_member('_columns').reset(self) self._update_rows() def _update_rows(self): """ Update the row and column numbers of child items. """ for row, item in enumerate(self._items): item.row = row # Row is the Parent item item.column = 0 for column, item in enumerate(self._columns): item.row = self.row # Row is the Parent item item.column = column
class BaseSelector(PSIContribution): context_items = Typed(list, []) symbols = Typed(dict, {}) updated = Event() #: Since order of context items is important for certain selectors (e.g., #: the CartesianProduct), this attribute is used to persist experiment #: settings when saving/loading from a file. context_item_order = Property().tag(preference=True) def _get_context_item_order(self): return [i.name for i in self.context_items] def _set_context_item_order(self, order): old_items = self.context_items[:] new_items = [] for name in order: for item in old_items[:]: if item.name == name: new_items.append(item) old_items.remove(item) # Be sure to tack on any old items that were not saved to the ordering # in the preferences file. new_items.extend(old_items) self.context_items = new_items def append_item(self, item): ''' Add context item to selector Parameters ---------- item : ContextItem Item to add to selector ''' context_items = self.context_items[:] context_items.append(item) self.context_items = context_items self.updated = True def remove_item(self, item): ''' Remove context item from selector Parameters ---------- item : ContextItem Item to remove from selector ''' context_items = self.context_items[:] context_items.remove(item) self.context_items = context_items self.updated = True
class TDTHardwareAIChannel(TDTGeneralMixin, HardwareAIChannel): #: Decimation factor. The analog inputs allow for the data to be #: downsampled to a rate that's an integer divisor of the circuit #: frequency. decimation = d_(Int(1)).tag(metadata=True) #: Filter delay in samples. filter_delay_samples = Property().tag(metadata=True) def _get_filter_delay_samples(self): return int(round(self.filter_delay * self.fs))
def __call__(self, func): new_func = func_runner(func) new_func.fset_list = [] def setter(set_func): s_func = func_runner(set_func) s_func.pname = attr_name(set_func) new_func.fset_list.append(s_func) return s_func new_func.setter = setter return Property(new_func).tag(**self.tags)