Skip to content

Commit

Permalink
refactor Part to separate __init__ and Method.call_function, and add …
Browse files Browse the repository at this point in the history
…cadoublepart
  • Loading branch information
gilesknap committed Jul 20, 2016
1 parent dc3128d commit 39f2b59
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 35 deletions.
18 changes: 16 additions & 2 deletions malcolm/core/part.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
from malcolm.core.loggable import Loggable

class Part(Loggable):

def __init__(self, name, process, block):
class Part(Loggable):
def __init__(self, name, process, block, params):
self.process = process
self.block = block
self.name = name
self.set_logger_name("%s.%s" % (block, name))
self._call_setup(params)

def _call_setup(self, params):
# Expect setup() implementation to be decorated with @takes so it will
# have a Method attached to it. Calling the Method will fill in defaults
if not hasattr(self.setup, "Method"):
raise NotImplementedError()
# unfortunately thi has to be done now rather than at @takes decorate
# time so it gets the bound method rather than the unbound function
self.setup.Method.set_function(self.setup)
self.setup.Method.call_function(params)

def setup(selfself, params):
raise NotImplementedError()
29 changes: 29 additions & 0 deletions malcolm/parts/ca/cadoublepart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import numpy as np

from malcolm.parts.ca.capart import CAPart
from malcolm.metas.numbermeta import NumberMeta
from malcolm.metas.stringmeta import StringMeta
from malcolm.core.method import takes, returns, REQUIRED


class CADoublePart(CAPart):
""" Defines a part which connects via channel access to a DBR_DOUBLE pv"""

@takes(
StringMeta("name", "name of created attribute"), REQUIRED,
StringMeta("description", "desc of created attribute"), REQUIRED,
StringMeta("pv", "full pv of demand and default for rbv"), REQUIRED,
StringMeta("rbv", "override for rbv"), None,
StringMeta("rbv_suff", "set rbv ro pv + rbv_suff"), None,
)
def setup(self, params):
""" setup is called by the base class Part.__init__ via self.Method.
self. Method is defined by the @takes decorator above.
It defines an attribute to publish the pv via Malcolm
Args:
params(OrderedDict): parameters described in @takes
"""
meta = NumberMeta("meta", params.description, np.float64)
self.create_attribute(meta, params.pv, rbv=params.rbv,
rbv_suff=params.rbv_suff)
5 changes: 2 additions & 3 deletions malcolm/parts/ca/capart.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@

class CAPart(Part):

def __init__(self, name, process, block, meta, pv, rbv=None, rbv_suff=None,
long_string=False):
super(CAPart, self).__init__(name=name, process=process, block=block)
def create_attribute(self, meta, pv, rbv=None, rbv_suff=None,
long_string=False):
if rbv is None:
if rbv_suff is None:
rbv = pv
Expand Down
Empty file removed malcolm/parts/cadoublepart.py
Empty file.
14 changes: 14 additions & 0 deletions tests/setup_malcolm_paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,17 @@

from pkg_resources import require
require("mock", "numpy", "tornado", "cothread")

from mock import MagicMock

try:
import cothread
except:
# cothread doesn't work on python3 at the moment
cothread = MagicMock()
def callback_result(f, *args, **kwargs):
return f(*args, **kwargs)
cothread.CallbackResult.side_effect = callback_result
sys.modules["cothread"] = cothread
catools = MagicMock()
cothread.catools = catools
8 changes: 4 additions & 4 deletions tests/test_core/test_part.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import sys

sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
import setup_malcolm_paths

Expand All @@ -8,14 +9,13 @@

from malcolm.core.part import Part


class TestPart(unittest.TestCase):
def test_init(self):
process = Mock()
block = Mock()
p = Part("part", process, block)
self.assertIs(process, p.process)
self.assertIs(block, p.block)
self.assertEquals("part", p.name)
self.assertRaises(NotImplementedError, Part, "part", process, block,
None)

if __name__ == "__main__":
unittest.main(verbosity=2)
26 changes: 26 additions & 0 deletions tests/test_parts/test_ca/test_cadoublepart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))
import setup_malcolm_paths

from malcolm.parts.ca.cadoublepart import CADoublePart

import unittest
from mock import Mock, patch, ANY


class TestCADoublePart(unittest.TestCase):

def test_init(self):
CADoublePart.create_attribute = Mock()
# reading yaml will result in a dictionary such as:-
exposure_pv={"name": "exposure",
"description": "shutter time",
"pv": "BL00I-EA-DET-01:AcquireTime",
"rbv_suff": "_RBV"}
p = CADoublePart("exp", Mock(), Mock(), exposure_pv)

# TODO: add above exposure_pv params
p.create_attribute.assert_called_once_with(ANY,
"BL00I-EA-DET-01:AcquireTime", rbv=None, rbv_suff='_RBV')

46 changes: 20 additions & 26 deletions tests/test_parts/test_ca/test_capart.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,45 @@

import unittest
from mock import MagicMock

try:
import cothread
except:
# cothread doesn't work on python3 at the moment
cothread = MagicMock()
def callback_result(f, *args, **kwargs):
return f(*args, **kwargs)
cothread.CallbackResult.side_effect = callback_result
sys.modules["cothread"] = cothread
catools = MagicMock()
cothread.catools = catools
from cothread import catools

# logging
# import logging
# logging.basicConfig(level=logging.DEBUG)

# module imports
from malcolm.core.block import DummyLock

from malcolm.parts.ca.capart import CAPart

class TestCAPart(unittest.TestCase):

def create_part(self, params=None):
if params is None:
params = dict(meta=MagicMock(), pv="pv", rbv_suff="2")
params["meta"].name = "meta"

process = MagicMock()
block = MagicMock()

class MyCAPart(CAPart):
def _call_setup(self, anything):
self.create_attribute(**params)

p = MyCAPart("me", process, block, "anything")
return p

def test_init(self):
p = self.create_part()
self.assertEqual(p.rbv, "pv2")
p.block.add_attribute.assert_called_once_with(p.attr)

def test_init_no_rbv(self):
from malcolm.parts.ca.capart import CAPart
meta = MagicMock()
meta.name = "meta"
p = CAPart("me", MagicMock(), MagicMock(), meta, "pv")
params = dict(meta=MagicMock(), pv="pv")
params["meta"].name = "meta"
p = self.create_part(params)
self.assertEqual(p.rbv, "pv")
self.assertEqual(p.pv, "pv")

def create_part(self):
from malcolm.parts.ca.capart import CAPart
process = MagicMock()
block = MagicMock()
meta = MagicMock()
meta.name = "meta"
p = CAPart("me", process, block, meta, "pv", rbv_suff="2")
return p

def test_reset(self):
p = self.create_part()
catools.connect.return_value = MagicMock(ok=True)
Expand Down

0 comments on commit 39f2b59

Please sign in to comment.