Skip to content

Improvements #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ python:
- "2.7"
- "3.3"
- "3.4"
- "3.5"

env:
- PINT="N" PYVISA='N'
Expand Down
4 changes: 2 additions & 2 deletions lantz_core/backends/visa.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ class VisaMessageDriver(BaseVisaDriver):
def read_status_byte(self):
return byte_to_dict(self._resource.read_stb(), self.STATUS_BYTE)

def default_get_feature(self, iprop, cmd, *args, **kwargs):
def default_get_feature(self, feat, cmd, *args, **kwargs):
"""Query the value using the provided command.

The command is formatted using the provided args and kwargs before
Expand All @@ -408,7 +408,7 @@ def default_get_feature(self, iprop, cmd, *args, **kwargs):
"""
return self._resource.query(cmd.format(*args, **kwargs))

def default_set_feature(self, iprop, cmd, *args, **kwargs):
def default_set_feature(self, feat, cmd, *args, **kwargs):
"""Set the iproperty value of the instrument.

The command is formatted using the provided args and kwargs before
Expand Down
33 changes: 22 additions & 11 deletions lantz_core/channel.py → lantz_core/base_channel.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""
lantz_core.channel
~~~~~~~~~~~~~
lantz_core.base_channel
~~~~~~~~~~~~~~~~~~~~~~~

Channel simplifies the writing of instrument implementing channel specific
behaviours.
Expand All @@ -14,7 +14,7 @@
absolute_import)

from .has_features import AbstractChannel
from .subsystem import SubSystem
from .base_subsystem import SubSystem


class Channel(SubSystem):
Expand Down Expand Up @@ -91,29 +91,40 @@ class ChannelContainer(object):
name : unicode
Name of the channel subpart on the parent.

list_available : unicode
Name of the parent method to use to query the available channels.
list_available : callable
Function to call to query the list of available channels.

aliases : dict
Dict mapping aliases names to the real channel id to use.

"""

def __init__(self, cls, parent, name, available):
def __init__(self, cls, parent, name, list_available, aliases):
self._cls = cls
self._channels = {}
self._name = name
self._parent = parent
if isinstance(available, (tuple, list)):
self._list = lambda: available
else:
self._list = getattr(parent, available)
self._aliases = aliases
self._list = list_available

@property
def available(self):
"""List the available channels.

"""
return self._list()
return self._list(self._parent)

@property
def aliases(self):
"""List the aliases.

"""
return self._aliases.copy()

def __getitem__(self, ch_id):
if ch_id in self._aliases:
ch_id = self._aliases[ch_id]

if ch_id in self._channels:
return self._channels[ch_id]

Expand Down
4 changes: 2 additions & 2 deletions lantz_core/subsystem.py → lantz_core/base_subsystem.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""
lantz_core.subsystem
~~~~~~~~~~~~~~~~~~~~
lantz_core.base_subsystem
~~~~~~~~~~~~~~~~~~~~~~~~~

Subsystems can be used to give a hierarchical organisation to a driver.

Expand Down
5 changes: 4 additions & 1 deletion lantz_core/features/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,8 @@
from .bool import Bool
from .scalars import Unicode, Int, Float
from .register import Register
from .alias import Alias
from .util import constant, conditional

__all__ = ['Bool', 'Unicode', 'Int', 'Float', 'Register']
__all__ = ['Bool', 'Unicode', 'Int', 'Float', 'Register', 'Alias', 'constant',
'conditional']
82 changes: 82 additions & 0 deletions lantz_core/features/alias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
"""
lantz_core.features.alias
~~~~~~~~~~~~~~~~~~~~~~~~~

Feature whose value is mapped to another Feature.

:copyright: 2015 by Lantz Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.

"""
from __future__ import (division, unicode_literals, print_function,
absolute_import)

from types import MethodType

from future.utils import exec_

from .feature import Feature, get_chain, set_chain


GET_DEF =\
"""def get(self, driver):
return {}

"""


SET_DEF =\
"""def set(self, driver, value):
{} = value

"""


class Alias(Feature):
"""Feature whose value is mapped to another Feature.

"""

def __init__(self, alias, settable=None):

super(Alias, self).__init__(True, settable)

accessor = 'driver.' + '.'.join([p if p else 'parent'
for p in alias.split('.')])

defs = GET_DEF.format(accessor)
if settable:
defs += '\n' + SET_DEF.format(accessor)

loc = {}
exec_(defs, globals(), loc)

self.get = MethodType(loc['get'], self)
if settable:
self.set = MethodType(loc['set'], self)

def post_set(self, driver, value, i_value, response):
"""Re-implemented here as an Alias does not need to do anaything
by default.

"""
pass

# =========================================================================
# --- Private API ---------------------------------------------------------
# =========================================================================

def _get(self, driver):
"""Re-implemented so that Alias never use the cache.

"""
with driver.lock:
return get_chain(self, driver)

def _set(self, driver, value):
"""Re-implemented so that Alias never uses the cache.

"""
with driver.lock:
set_chain(self, driver, value)
14 changes: 10 additions & 4 deletions lantz_core/features/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
"""
from __future__ import (division, unicode_literals, print_function,
absolute_import)

from types import MethodType
from collections import OrderedDict
from stringparser import Parser

from .util import wrap_custom_feat_method, MethodsComposer, COMPOSERS
from .util import (wrap_custom_feat_method, MethodsComposer, COMPOSERS,
AbstractGetSetFactory)
from ..errors import LantzError
from ..util import build_checker

Expand Down Expand Up @@ -68,7 +70,7 @@ class Feature(property):
discard : tuple or dict
Tuple of names of features whose cached value should be discarded after
setting the Feature or dictionary specifying a list of feature whose
cache should be discarded under the 'feature' key and a list of limits
cache should be discarded under the 'features' key and a list of limits
to discard under the 'limits' key.

Attributes
Expand All @@ -87,8 +89,7 @@ def __init__(self, getter=None, setter=None, extract='', retries=0,
self._setter = setter
self._retries = retries
self._customs = {}
# Don't create the weak values dict if it is not used.
self._proxies = ()

self.creation_kwargs = {'getter': getter, 'setter': setter,
'retries': retries, 'checks': checks,
'extract': extract, 'discard': discard}
Expand All @@ -98,6 +99,11 @@ def __init__(self, getter=None, setter=None, extract='', retries=0,
self._set if setter is not None else None,
self._del)

if isinstance(getter, AbstractGetSetFactory):
self.get = MethodType(getter.build_getter(), self)
if isinstance(setter, AbstractGetSetFactory):
self.set = MethodType(setter.build_setter(), self)

if checks:
self._build_checkers(checks)
if discard:
Expand Down
3 changes: 1 addition & 2 deletions lantz_core/features/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ def __init__(self, getter=None, setter=None, names=(), length=8,
# Makes sure every key is unique by using the bit index if None is
# found
for i, n in enumerate(names[:]):
if n is None:
names[i] = i
names[i] = n or i

self.names = tuple(names)
self.creation_kwargs['names'] = names
Expand Down
125 changes: 125 additions & 0 deletions lantz_core/features/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@
"""
from __future__ import (division, unicode_literals, print_function,
absolute_import)

from types import MethodType
from functools import update_wrapper

from future.utils import exec_


def wrap_custom_feat_method(meth, feat):
""" Wrap a HasFeature method to make it an driver method of a Feature.
Expand Down Expand Up @@ -333,3 +336,125 @@ def decorator(function):
return function

return decorator

# --- Getter/setter factories -------------------------------------------------


class AbstractGetSetFactory(object):
"""Abstract class for get/set factories.

Use by Feature to identify such a factory and use it to replace the
get/set method.

"""

def build_getter(self):
"""Build the function for getting the Feature value.

This method is called when a get/set factory is passed as the getter
argument to a Feature.

"""
raise NotImplementedError()

def build_setter(self):
"""Build the function for setting the Feature value.

This method is called when a get/set factory is passed as the setter
argument to a Feature.

"""
raise NotImplementedError()


class constant(AbstractGetSetFactory):
"""Make a Feature return always the same value.

This can only be used as a getter factory.

Parameters
----------
value :
The value the Feature should return

"""

def __init__(self, value):
super(constant, self).__init__()
self._value = value

def build_getter(self):
"""Build a trivial function to return the constant value.

"""
value = self._value

def getter(self, driver):
return value

return getter


GET_DEF =\
"""def get(self, driver):
val = {}
return {}

"""

SET_DEF =\
"""def set(self, driver, value):
cmd = {}
return driver.default_set_feature(self, cmd, value)
"""


class conditional(AbstractGetSetFactory):
"""Make a Feature modify getting/setting based on the driver state.

Parameters
----------
conditional_value : unicode
String of the form 'a if driver.b else c'. When setting the value is
accessible as value.

default : bool
Pass the result of the conditional evalutation to the
default_get/set_feature method of the driver if True, otherwise
directly return the result.
When building a setter this MUST be true.

"""

def __init__(self, conditional_value, default=False):
super(conditional, self).__init__()
self._cond = conditional_value
self._default = default

def build_getter(self):
"""Build the getter.

"""
if not self._default:
get_def = GET_DEF.format(self._cond, 'val')

else:
get_def = GET_DEF.format(self._cond,
'driver.default_get_feature(self, val)')

loc = {}
exec_(get_def, globals(), loc)

return loc['get']

def build_setter(self):
"""Build the setter.

"""
if not self._default:
raise ValueError('Can build a setter only if default is True')

loc = {}
exec_(SET_DEF.format(self._cond), globals(), loc)

return loc['set']
Loading