diff --git a/attribute_wrapper/__init__.py b/attribute_wrapper/__init__.py index 7b0c11e119b50068ae0102fe7e61571b285ffb7d..5dbbfba59ffdb20d1aa8f9d58d5b82231c2858bd 100644 --- a/attribute_wrapper/__init__.py +++ b/attribute_wrapper/__init__.py @@ -1,8 +1,8 @@ -""" My Awesome Package """ +""" PyTango Attribute Wrapper """ try: from importlib import metadata except ImportError: # for Python<3.8 import importlib_metadata as metadata -# __version__ = metadata.version("AttributeWrapper") +__version__ = metadata.version("AttributeWrapper") diff --git a/attribute_wrapper/attribute_wrapper.py b/attribute_wrapper/attribute_wrapper.py index cbb0138a9eca149e9d2d955569d1a82636420b44..e1ae6d604e8cd84c0eb147a0bbd090e5dd3adebc 100644 --- a/attribute_wrapper/attribute_wrapper.py +++ b/attribute_wrapper/attribute_wrapper.py @@ -248,8 +248,7 @@ class AttributeWrapper(attribute): ) def get_attribute_io(self, device): - """ - returns the attribute I/O functions from a certain device, or registers it if not present + """returns the attribute I/O functions from a certain device, or registers it if not present """ try: diff --git a/attribute_wrapper/interface.py b/attribute_wrapper/interface.py new file mode 100644 index 0000000000000000000000000000000000000000..90174f6a6cf702e16fd349a18bba0a0649a0078b --- /dev/null +++ b/attribute_wrapper/interface.py @@ -0,0 +1,14 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +import logging + +logger = logging.getLogger() + +__all__ = ["AttributeWrapperInterface"] + +class AttributeWrapperInterface: + + def __init__(self): + """prepare the caches for attribute wrapper objects""" + self._attribute_wrapper_io = {} diff --git a/attribute_wrapper/states.py b/attribute_wrapper/states.py new file mode 100644 index 0000000000000000000000000000000000000000..6c7aa97d04ed84d73e5aabd4971fa31d1415907e --- /dev/null +++ b/attribute_wrapper/states.py @@ -0,0 +1,15 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +from tango import DevState + +# The Device states in which we consider our device operational, +# and thus allow interaction. +OPERATIONAL_STATES = [DevState.ON, DevState.ALARM] + +# States in which Initialise() has happened, and the hardware +# can thus be configured or otherwise interacted with. +INITIALISED_STATES = OPERATIONAL_STATES + [DevState.STANDBY, DevState.DISABLE] + +# States in which most commands are allowed +DEFAULT_COMMAND_STATES = INITIALISED_STATES diff --git a/tests/test_attr_wrapper.py b/tests/test_attr_wrapper.py index 867b261c524a50e45d1c58117ac786c4c12b0131..57e532fdb4f5a61cc32e13654ab0459006636880 100644 --- a/tests/test_attr_wrapper.py +++ b/tests/test_attr_wrapper.py @@ -5,21 +5,23 @@ """ import asyncio +import unittest import numpy -from unittest import mock, TestCase +from unittest import TestCase import testscenarios - # External imports from tango import DevState, DevFailed, AttrWriteType, DeviceProxy from tango.server import attribute, command, Device, DeviceMeta # Test imports from tango.test_context import DeviceTestContext -from attribute_wrapper.attribute_wrapper import AttributeWrapper # Internal imports +from attribute_wrapper.attribute_wrapper import AttributeWrapper +from attribute_wrapper.interface import AttributeWrapperInterface +from attribute_wrapper.states import INITIALISED_STATES from test_client import TestClient SCALAR_DIMS = (1,) @@ -39,7 +41,18 @@ STR_IMAGE_VAL = [["1", "1"], ["1", "1"], ["1", "1"]] # device.test_client.start() -class device_wrapper(Device, metaclass=DeviceMeta): +class DeviceWrapper(Device, metaclass=DeviceMeta): + + def __init__(self, cl, name): + super().__init__(cl, name) + + self._attribute_wrapper_io = {} + + def is_attribute_access_allowed(self, req_type): + """Returns whether an attribute wrapped by the AttributeWrapper be accessed.""" + + return self.get_state() in INITIALISED_STATES + @classmethod def attr_list(cls): """Return a list of all the AttributeWrapper members of this class.""" @@ -70,14 +83,14 @@ class device_wrapper(Device, metaclass=DeviceMeta): self.configure_for_initialise() -class TestAttributeTypes: +class TestAttributeTypes(testscenarios.WithScenarios, unittest.TestCase): # def setUp(self): # # Avoid the device trying to access itself as a client - # self.deviceproxy_patch = mock.patch.object(device_wrapper, "DeviceProxy") + # self.deviceproxy_patch = mock.patch.object(DeviceWrapper, "DeviceProxy") # self.deviceproxy_patch.start() # self.addCleanup(self.deviceproxy_patch.stop) - class StrScalarDevice(device_wrapper): + class StrScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper(comms_annotation="str_scalar_R", datatype=str) scalar_RW = AttributeWrapper( comms_annotation="str_scalar_RW", @@ -85,7 +98,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class BoolScalarDevice(device_wrapper): + class BoolScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper(comms_annotation="bool_scalar_R", datatype=bool) scalar_RW = AttributeWrapper( comms_annotation="bool_scalar_RW", @@ -93,7 +106,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class Float32ScalarDevice(device_wrapper): + class Float32ScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="float32_scalar_R", datatype=numpy.float32 ) @@ -103,7 +116,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class Float64ScalarDevice(device_wrapper): + class Float64ScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="float64_scalar_R", datatype=numpy.float64 ) @@ -113,7 +126,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class DoubleScalarDevice(device_wrapper): + class DoubleScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="double_scalar_R", datatype=numpy.double ) @@ -123,7 +136,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class Uint8ScalarDevice(device_wrapper): + class Uint8ScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="uint8_scalar_R", datatype=numpy.uint8 ) @@ -133,7 +146,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class Uint16ScalarDevice(device_wrapper): + class Uint16ScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="uint16_scalar_R", datatype=numpy.uint16 ) @@ -143,7 +156,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class Uint32ScalarDevice(device_wrapper): + class Uint32ScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="uint32_scalar_R", datatype=numpy.uint32 ) @@ -153,7 +166,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class Uint64ScalarDevice(device_wrapper): + class Uint64ScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="uint64_scalar_R", datatype=numpy.uint64 ) @@ -163,7 +176,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class Int16ScalarDevice(device_wrapper): + class Int16ScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="int16_scalar_R", datatype=numpy.int16 ) @@ -173,7 +186,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class Int32ScalarDevice(device_wrapper): + class Int32ScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="int32_scalar_R", datatype=numpy.int32 ) @@ -183,7 +196,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class Int64ScalarDevice(device_wrapper): + class Int64ScalarDevice(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="int64_scalar_R", datatype=numpy.int64 ) @@ -193,7 +206,7 @@ class TestAttributeTypes: access=AttrWriteType.READ_WRITE, ) - class StrSpectrumDevice(device_wrapper): + class StrSpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="str_spectrum_R", datatype=str, dims=SPECTRUM_DIMS ) @@ -204,7 +217,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class BoolSpectrumDevice(device_wrapper): + class BoolSpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="bool_spectrum_R", datatype=bool, dims=SPECTRUM_DIMS ) @@ -215,7 +228,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class Float32SpectrumDevice(device_wrapper): + class Float32SpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="float32_spectrum_R", datatype=numpy.float32, @@ -228,7 +241,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class Float64SpectrumDevice(device_wrapper): + class Float64SpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="float64_spectrum_R", datatype=numpy.float64, @@ -241,7 +254,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class DoubleSpectrumDevice(device_wrapper): + class DoubleSpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="double_spectrum_R", datatype=numpy.double, @@ -254,7 +267,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class Uint8SpectrumDevice(device_wrapper): + class Uint8SpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="uint8_spectrum_R", datatype=numpy.uint8, @@ -267,7 +280,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class Uint16SpectrumDevice(device_wrapper): + class Uint16SpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="uint16_spectrum_R", datatype=numpy.uint16, @@ -280,7 +293,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class Uint32SpectrumDevice(device_wrapper): + class Uint32SpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="uint32_spectrum_R", datatype=numpy.uint32, @@ -293,7 +306,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class Uint64SpectrumDevice(device_wrapper): + class Uint64SpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="uint64_spectrum_R", datatype=numpy.uint64, @@ -306,7 +319,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class Int16SpectrumDevice(device_wrapper): + class Int16SpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="int16_spectrum_R", datatype=numpy.int16, @@ -319,7 +332,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class Int32SpectrumDevice(device_wrapper): + class Int32SpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="int32_spectrum_R", datatype=numpy.int32, @@ -332,7 +345,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class Int64SpectrumDevice(device_wrapper): + class Int64SpectrumDevice(DeviceWrapper): spectrum_R = AttributeWrapper( comms_annotation="int64_spectrum_R", datatype=numpy.int64, @@ -345,7 +358,7 @@ class TestAttributeTypes: dims=SPECTRUM_DIMS, ) - class StrImageDevice(device_wrapper): + class StrImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="str_image_R", datatype=str, dims=(3, 2) ) @@ -356,7 +369,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class BoolImageDevice(device_wrapper): + class BoolImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="bool_image_R", datatype=bool, dims=(3, 2) ) @@ -367,7 +380,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class Float32ImageDevice(device_wrapper): + class Float32ImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="float32_image_R", datatype=numpy.float32, dims=(3, 2) ) @@ -378,7 +391,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class Float64ImageDevice(device_wrapper): + class Float64ImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="float64_image_R", datatype=numpy.float64, dims=(3, 2) ) @@ -389,7 +402,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class DoubleImageDevice(device_wrapper): + class DoubleImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="double_image_R", datatype=numpy.double, dims=(3, 2) ) @@ -400,7 +413,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class Uint8ImageDevice(device_wrapper): + class Uint8ImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="uint8_image_R", datatype=numpy.uint8, dims=(3, 2) ) @@ -411,7 +424,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class Uint16ImageDevice(device_wrapper): + class Uint16ImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="uint16_image_R", datatype=numpy.uint16, dims=(3, 2) ) @@ -422,7 +435,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class Uint32ImageDevice(device_wrapper): + class Uint32ImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="uint32_image_R", datatype=numpy.uint32, dims=(3, 2) ) @@ -433,7 +446,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class Uint64ImageDevice(device_wrapper): + class Uint64ImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="uint64_image_R", datatype=numpy.uint64, dims=(3, 2) ) @@ -444,7 +457,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class Int16ImageDevice(device_wrapper): + class Int16ImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="int16_image_R", datatype=numpy.int16, dims=(3, 2) ) @@ -455,7 +468,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class Int32ImageDevice(device_wrapper): + class Int32ImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="int32_image_R", datatype=numpy.int32, dims=(3, 2) ) @@ -466,7 +479,7 @@ class TestAttributeTypes: dims=(3, 2), ) - class Int64ImageDevice(device_wrapper): + class Int64ImageDevice(DeviceWrapper): image_R = AttributeWrapper( comms_annotation="int64_image_R", datatype=numpy.int64, dims=(3, 2) ) @@ -938,11 +951,11 @@ class TestAttributeTypes: class TestAttributeAccess(testscenarios.WithScenarios, TestCase): # def setUp(self): # # Avoid the device trying to access itself as a client - # self.deviceproxy_patch = mock.patch.object(device_wrapper, "DeviceProxy") + # self.deviceproxy_patch = mock.patch.object(DeviceWrapper, "DeviceProxy") # self.deviceproxy_patch.start() # self.addCleanup(self.deviceproxy_patch.stop) - class float32_scalar_device(device_wrapper): + class float32_scalar_device(DeviceWrapper): scalar_R = AttributeWrapper( comms_annotation="float32_scalar_R", datatype=numpy.float32 ) diff --git a/tox.ini b/tox.ini index 1454f6c2a571ae1b3a985a79652ac63b34859532..3311c2759a7cff6d41574dbabd646aedefea8e5f 100644 --- a/tox.ini +++ b/tox.ini @@ -20,7 +20,7 @@ commands_pre = pip install --no-cache 'PyTango>=9.3.6' commands = {envpython} --version - {envpython} -m pytest + {envpython} -m pytest {posargs} [testenv:coverage] commands =