Skip to content
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

Add default arguments ability and update tests. #91

Merged
merged 16 commits into from
Sep 18, 2018
Merged
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
6 changes: 4 additions & 2 deletions pytac/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
"""Pytac: Python Toolkit for Accelerator Controls."""

# PV types
# PV types.
SP = 'setpoint'
RB = 'readback'
# Unit systems
# Unit systems.
ENG = 'engineering'
PHYS = 'physics'
# Data Source types.
SIM = 'simulation'
LIVE = 'live'
# Default argument flag.
DEFAULT = 'default'

from . import data_source, element, epics, exceptions, lattice, load_csv, units, utils # noqa: E402
"""Error 402 is suppressed as we cannot import these modules at the top of the
Expand Down
2 changes: 2 additions & 0 deletions pytac/cothread_cs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class CothreadControlSystem(ControlSystem):

It is used to communicate over channel access with the hardware
in the ring.

**Methods:**
"""
def __init__(self):
pass
Expand Down
5 changes: 2 additions & 3 deletions pytac/cs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@

class ControlSystem(object):
""" Abstract base class representing a control system.
"""
def __init__(self):
raise NotImplementedError()

**Methods:**
"""
def get(self, pv):
""" Get the value of the given PV.

Expand Down
31 changes: 26 additions & 5 deletions pytac/data_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ class DataSourceManager(object):
the correct data source. The unit conversion objects for all fields are also
held here.

Attributes:
default_units (str): Holds the current default unit type, pytac.PHYS or
pytac.ENG, for an element or lattice.
default_data_source (str): Holds the current default data source,
pytac.LIVE or pytac.SIM, for an element or
lattice.

.. Private Attributes:
_data_sources (dict): A dictionary of the data sources held.
_uc (dict): A dictionary of the unit conversion objects for each
Expand All @@ -65,6 +72,8 @@ class DataSourceManager(object):
def __init__(self):
self._data_sources = {}
self._uc = {}
self.default_units = pytac.ENG
self.default_data_source = pytac.LIVE

def set_data_source(self, data_source, data_source_type):
"""Add a data source to the manager.
Expand Down Expand Up @@ -139,13 +148,15 @@ def get_unitconv(self, field):
"""
return self._uc[field]

def get_value(self, field, handle, units, data_source):
def get_value(self, field, handle=pytac.RB, units=pytac.DEFAULT,
data_source=pytac.DEFAULT):
"""Get the value for a field.

Returns the value of a field on the manager. This value is uniquely
identified by a field and a handle. The returned value is either
in engineering or physics units. The data_source flag returns either
real or simulated values.
real or simulated values. If handle, units or data_source are not given
then the lattice default values are used.

Args:
field (str): The requested field.
Expand All @@ -160,6 +171,10 @@ def get_value(self, field, handle, units, data_source):
DeviceException: if there is no device on the given field.
FieldException: if the manager does not have the specified field.
"""
if units == pytac.DEFAULT:
units = self.default_units
if data_source == pytac.DEFAULT:
data_source = self.default_data_source
try:
data_source = self._data_sources[data_source]
value = data_source.get_value(field, handle)
Expand All @@ -172,10 +187,12 @@ def get_value(self, field, handle, units, data_source):
raise FieldException('No field {} on manager {}'.format(field,
self))

def set_value(self, field, value, handle, units, data_source):
def set_value(self, field, value, handle=pytac.SP, units=pytac.DEFAULT,
data_source=pytac.DEFAULT):
"""Set the value for a field.

This value can be set on the machine or the simulation.
This value can be set on the machine or the simulation. If handle, units
or data_source are not given then the lattice default values are used.

Args:
field (str): The requested field.
Expand All @@ -188,6 +205,10 @@ def set_value(self, field, value, handle, units, data_source):
DeviceException: if arguments are incorrect.
FieldException: if the manager does not have the specified field.
"""
if units == pytac.DEFAULT:
units = self.default_units
if data_source == pytac.DEFAULT:
data_source = self.default_data_source
if handle != pytac.SP:
raise HandleException('Must write using {}'.format(pytac.SP))
try:
Expand All @@ -207,7 +228,7 @@ def set_value(self, field, value, handle, units, data_source):
self))


class DeviceDataSource(object):
class DeviceDataSource(DataSource):
"""Data source containing control system devices.

**Attributes:**
Expand Down
2 changes: 2 additions & 0 deletions pytac/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Device(object):

Typically a control system will be used to set and get values on a
device.

**Methods:**
"""
def is_enabled(self):
"""Whether the device is enabled.
Expand Down
11 changes: 5 additions & 6 deletions pytac/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ class Element(object):
data sources associated
with this element.
"""
def __init__(self, name, length, element_type, s=None, index=None,
cell=None):
def __init__(self, name, length, element_type, s, index=None, cell=None):
"""
Args:
name (int): The unique identifier for the element in the ring.
Expand Down Expand Up @@ -138,8 +137,8 @@ def add_to_family(self, family):
"""
self.families.add(family)

def get_value(self, field, handle=pytac.RB, units=pytac.ENG,
data_source=pytac.LIVE):
def get_value(self, field, handle=pytac.RB, units=pytac.DEFAULT,
data_source=pytac.DEFAULT):
"""Get the value for a field.

Returns the value of a field on the element. This value is uniquely
Expand All @@ -163,8 +162,8 @@ def get_value(self, field, handle=pytac.RB, units=pytac.ENG,
return self._data_source_manager.get_value(field, handle, units,
data_source)

def set_value(self, field, value, handle=pytac.SP, units=pytac.ENG,
data_source=pytac.LIVE):
def set_value(self, field, value, handle=pytac.SP, units=pytac.DEFAULT,
data_source=pytac.DEFAULT):
"""Set the value for a field.

This value can be set on the machine or the simulation.
Expand Down
98 changes: 67 additions & 31 deletions pytac/lattice.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import numpy
import pytac
from pytac.data_source import DataSourceManager
from pytac.exceptions import LatticeException
from pytac.exceptions import LatticeException, UnitsException, DeviceException


class Lattice(object):
Expand Down Expand Up @@ -105,8 +105,8 @@ def get_unitconv(self, field):
"""
return self._data_source_manager.get_unitconv(field)

def get_value(self, field, handle=pytac.RB, units=pytac.ENG,
data_source=pytac.LIVE):
def get_value(self, field, handle=pytac.RB, units=pytac.DEFAULT,
data_source=pytac.DEFAULT):
"""Get the value for a field on the lattice.

Returns the value of a field on the lattice. This value is uniquely
Expand All @@ -130,8 +130,8 @@ def get_value(self, field, handle=pytac.RB, units=pytac.ENG,
return self._data_source_manager.get_value(field, handle, units,
data_source)

def set_value(self, field, value, handle=pytac.SP, units=pytac.ENG,
data_source=pytac.LIVE):
def set_value(self, field, value, handle=pytac.SP, units=pytac.DEFAULT,
data_source=pytac.DEFAULT):
"""Set the value for a field.

This value can be set on the machine or the simulation.
Expand Down Expand Up @@ -230,29 +230,6 @@ def get_all_families(self):

return families

def get_s(self, elem):
"""Find the s position of an element in the lattice.

Note that the given element must exist in the lattice.

Args:
elem (Element): The element that the position is being asked for.

Returns:
float: The position of the given element.

Raises:
LatticeException: if element doesn't exist in the lattice.
"""
s_pos = 0
for e in self._lattice:
if e is not elem:
s_pos += e.length
else:
return s_pos
raise LatticeException('Element {} not in lattice {}'.format(elem,
self))

def get_family_s(self, family):
"""Get s positions for all elements from the same family.

Expand All @@ -265,7 +242,7 @@ def get_family_s(self, family):
elements = self.get_elements(family)
s_positions = []
for element in elements:
s_positions.append(self.get_s(element))
s_positions.append(element.s)
return s_positions

def get_element_devices(self, family, field):
Expand Down Expand Up @@ -349,6 +326,65 @@ def set_element_values(self, family, field, values):
if len(elements) != len(values):
raise LatticeException("Number of elements in given array must be"
" equal to the number of elements in the "
"family")
"family.")
for element, value in zip(elements, values):
element.set_value(field, value)
element.set_value(field, value, handle=pytac.SP)

def set_default_units(self, default_units):
"""Sets the default unit type for the lattice and all its elements.

Args:
default_units (str): The default unit type to be set across the
entire lattice, pytac.ENG or pytac.PHYS.

Raises:
UnitsException: if specified default unit type is not a valid unit
type.
"""
if default_units == pytac.ENG or default_units == pytac.PHYS:
self._data_source_manager.default_units = default_units
elems = self.get_elements()
for elem in elems:
elem._data_source_manager.default_units = default_units
elif default_units is not None:
raise UnitsException('{0} is not a unit type. Please enter {1} or '
'{2}'.format(default_units, pytac.ENG,
pytac.PHYS))

def set_default_data_source(self, default_data_source):
"""Sets the default data source for the lattice and all its elements.

Args:
default_data_source (str): The default data source to be set across
the entire lattice, pytac.LIVE or
pytac.SIM.

Raises:
DeviceException: if specified default data source is not a valid
data source.
"""
if default_data_source == pytac.LIVE or default_data_source == pytac.SIM:
self._data_source_manager.default_data_source = default_data_source
elems = self.get_elements()
for elem in elems:
elem._data_source_manager.default_data_source = default_data_source
elif default_data_source is not None:
raise DeviceException('{0} is not a data source. Please enter {1} '
'or {2}'.format(default_data_source,
pytac.LIVE, pytac.SIM))

def get_default_units(self):
"""Get the default unit type, pytac.ENG or pytac.PHYS.

Returns:
str: the default unit type for the entire lattice.
"""
return self._data_source_manager.default_units

def get_default_data_source(self):
"""Get the default data source, pytac.LIVE or pytac.SIM.

Returns:
str: the default data source for the entire lattice.
"""
return self._data_source_manager.default_data_source
4 changes: 2 additions & 2 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def double_uc():
def simple_element(x_device, y_device, mock_sim_data_source, unit_uc,
double_uc):
# A unit conversion object that returns the same as the input.
element = Element('element1', 0, 'BPM', cell=1)
element = Element('element1', 0, 'BPM', 0.0, cell=1)
element.add_to_family('family')
element.set_data_source(DeviceDataSource(), pytac.LIVE)
element.add_device('x', x_device, unit_uc)
Expand Down Expand Up @@ -109,7 +109,7 @@ def mock_cs():

@pytest.fixture
def simple_epics_element(mock_cs, unit_uc):
element = EpicsElement(1, 0, 'BPM', cell=1)
element = EpicsElement(1, 0, 'BPM', 0.0, cell=1)
x_device = EpicsDevice('x_device', mock_cs, True, RB_PV, SP_PV)
y_device = EpicsDevice('y_device', mock_cs, True, SP_PV, RB_PV)
element.add_to_family('family')
Expand Down
23 changes: 0 additions & 23 deletions test/test_cs.py

This file was deleted.

9 changes: 5 additions & 4 deletions test/test_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@


def test_create_element():
e = pytac.element.Element('bpm1', 6.0, 'bpm')
e = pytac.element.Element('bpm1', 6.0, 'bpm', 0.0)
e.add_to_family('BPM')
assert 'BPM' in e.families
assert e.length == 6.0


def test_add_element_to_family():
e = pytac.element.Element('dummy', 6.0, 'Quad')
e = pytac.element.Element('dummy', 6.0, 'Quad', 0.0)
e.add_to_family('fam')
assert 'fam' in e.families

Expand Down Expand Up @@ -48,14 +48,15 @@ def test_get_value_uses_uc_if_necessary_for_sim_call(simple_element, double_uc):


def test_set_value_eng(simple_element):
simple_element.set_value('x', DUMMY_VALUE_2)
simple_element.set_value('x', DUMMY_VALUE_2, handle=pytac.SP)
# No conversion needed
simple_element.get_device('x').set_value.assert_called_with(DUMMY_VALUE_2)


def test_set_value_phys(simple_element, double_uc):
simple_element._data_source_manager._uc['x'] = double_uc
simple_element.set_value('x', DUMMY_VALUE_2, units=pytac.PHYS)
simple_element.set_value('x', DUMMY_VALUE_2, handle=pytac.SP,
units=pytac.PHYS)
# Conversion fron physics to engineering units
simple_element.get_device('x').set_value.assert_called_with((DUMMY_VALUE_2 / 2))

Expand Down
Loading