Skip to content
This repository has been archived by the owner on Apr 7, 2022. It is now read-only.

Commit

Permalink
Remove explicit metaclass definitions (PR #90)
Browse files Browse the repository at this point in the history
This PR makes DeviceMeta a subclass of Boost.Python.class, so the metaclass definition is automatically propagated to the subclasses of Device.

It also fixes a fundamental issue with asyncio servers that I hadn't noticed until today, see 995db76.

The docs and examples have been simplified (1890f6c and 64c8cc9 promote the run_server method and remove the metaclass definitions).

It also fixes issue #74, see 38e1eec (unrelated, but it made my debugging easier).
  • Loading branch information
vxgmichel committed Jan 30, 2017
2 parents d21b78e + 2f2ec27 commit c0b03bb
Show file tree
Hide file tree
Showing 15 changed files with 354 additions and 238 deletions.
24 changes: 11 additions & 13 deletions doc/_static/PowerSupplyDS.py
Expand Up @@ -7,23 +7,21 @@
import numpy

from tango import AttrQuality, AttrWriteType, DispLevel, DevState, DebugIt
from tango.server import Device, DeviceMeta, attribute, command, pipe, run
from tango.server import device_property
from tango.server import Device, attribute, command, pipe, device_property


class PowerSupply(Device):
__metaclass__ = DeviceMeta

voltage = attribute(label="Voltage", dtype=float,
display_level=DispLevel.OPERATOR,
access=AttrWriteType.READ,
unit="V",format="8.4f",
unit="V", format="8.4f",
doc="the power supply voltage")

current = attribute(label="Current", dtype=float,
display_level=DispLevel.EXPERT,
access=AttrWriteType.READ_WRITE,
unit="A",format="8.4f",
unit="A", format="8.4f",
min_value=0.0, max_value=8.5,
min_alarm=0.1, max_alarm=8.4,
min_warning=0.5, max_warning=8.0,
Expand All @@ -39,16 +37,16 @@ class PowerSupply(Device):

host = device_property(dtype=str)
port = device_property(dtype=int, default_value=9788)

def init_device(self):
Device.init_device(self)
self.__current = 0.0
self.set_state(DevState.STANDBY)

def read_voltage(self):
self.info_stream("read_voltage(%s, %d)", self.host, self.port)
return 9.99, time.time(), AttrQuality.ATTR_WARNING

def get_current(self):
return self.__current

Expand Down Expand Up @@ -76,12 +74,12 @@ def TurnOff(self):
self.set_state(DevState.OFF)

@command(dtype_in=float, doc_in="Ramp target current",
dtype_out=bool, doc_out="True if ramping went well, False otherwise")
dtype_out=bool, doc_out="True if ramping went well, "
"False otherwise")
def Ramp(self, target_current):
# should do the ramping
return True


if __name__ == "__main__":
run([PowerSupply])


if __name__ == "__main__":
PowerSupply.run_server()
1 change: 0 additions & 1 deletion doc/_templates/index.html
Expand Up @@ -87,7 +87,6 @@ <h1>Welcome to PyTango documentation!</h1>


<span class="k">class</span> <span class="nc">Clock</span><span class="p">(</span><span class="n">Device</span><span class="p">):</span>
<span class="n">__metaclass__</span> <span class="o">=</span> <span class="n">DeviceMeta</span>

<span class="n">time</span> <span class="o">=</span> <span class="n">attribute</span><span class="p">()</span>

Expand Down
57 changes: 17 additions & 40 deletions doc/howto.rst
Expand Up @@ -307,13 +307,10 @@ high level API
:linenos:
import time
from tango.server import run
from tango.server import Device, DeviceMeta
from tango.server import attribute, command, pipe
from tango.server import Device, attribute, command, pipe
class Clock(Device):
__metaclass__ = DeviceMeta
@attribute
def time(self):
Expand All @@ -332,37 +329,32 @@ high level API
if __name__ == "__main__":
run([Clock])
Clock.run_server()
**line 2-4**
**line 2**
import the necessary symbols

**line 7**
**line 5**
tango device class definition. A Tango device must inherit from
:class:`tango.server.Device`

**line 8**
mandatory *magic* line. A Tango device must define the metaclass as
:class:`tango.server.DeviceClass`. This has to be done due to a limitation
on boost-python

**line 10-12**
**line 7-9**
definition of the *time* attribute. By default, attributes are double, scalar,
read-only. Check the :class:`~tango.server.attribute` for the complete
list of attribute options.

**line 14-16**
**line 11-13**
the method *strftime* is exported as a Tango command. In receives a string
as argument and it returns a string. If a method is to be exported as a
Tango command, it must be decorated as such with the
:func:`~tango.server.command` decorator

**line 18-23**
**line 15-20**
definition of the *info* pipe. Check the :class:`~tango.server.pipe`
for the complete list of pipe options.

**line 28**
**line 24**
start the Tango run loop. The mandatory argument is a list of python classes
that are to be exported as Tango classes. Check :func:`~tango.server.run`
for the complete list of options
Expand All @@ -383,13 +375,12 @@ using the high level API. The example contains:
from time import time
from numpy.random import random_sample
from tango import AttrQuality, AttrWriteType, DispLevel, run
from tango.server import Device, DeviceMeta, attribute, command
from tango import AttrQuality, AttrWriteType, DispLevel
from tango.server import Device, attribute, command
from tango.server import class_property, device_property
class PowerSupply(Device):
__metaclass__ = DeviceMeta
current = attribute(label="Current", dtype=float,
display_level=DispLevel.EXPERT,
Expand Down Expand Up @@ -428,17 +419,7 @@ using the high level API. The example contains:
if __name__ == "__main__":
run([PowerSupply])
.. note::
the ``__metaclass__`` statement is mandatory due to a limitation in the
*boost-python* library used by PyTango.

If you are using python 3 you can write instead::

class PowerSupply(Device, metaclass=DeviceMeta)
pass
PowerSupply.run_server()
.. _logging:

Expand Down Expand Up @@ -573,29 +554,27 @@ separated python files: A :class:`PLC` class in a :file:`PLC.py`::

# PLC.py

from tango.server import Device, DeviceMeta, run
from tango.server import Device

class PLC(Device):
__metaclass__ = DeviceMeta

# bla, bla my PLC code

if __name__ == "__main__":
run([PLC])
PLC.run_server()

... and a :class:`IRMirror` in a :file:`IRMirror.py`::

# IRMirror.py

from tango.server import Device, DeviceMeta, run
from tango.server import Device

class IRMirror(Device):
__metaclass__ = DeviceMeta

# bla, bla my IRMirror code

if __name__ == "__main__":
run([IRMirror])
IRMirror.run_server()

You want to create a Tango server called `PLCMirror` that is able to contain
devices from both PLC and IRMirror classes. All you have to do is write
Expand Down Expand Up @@ -683,10 +662,9 @@ point attribute with the specified name::


from tango import Util, Attr
from tango.server import DeviceMeta, Device, command
from tango.server import Device, command

class MyDevice(Device):
__metaclass__ = DeviceMeta

@command(dtype_in=str)
def CreateFloatAttribute(self, attr_name):
Expand Down Expand Up @@ -730,10 +708,9 @@ creates a device of some arbitrary class (the example assumes the tango commands
with two strings. No error processing was done on the code for simplicity sake)::

from tango import Util
from tango.server import DeviceMeta, Device, command
from tango.server import Device, command

class MyDevice(Device):
__metaclass__ = DeviceMeta

@command(dtype_in=[str])
def CreateDevice(self, pars):
Expand Down

0 comments on commit c0b03bb

Please sign in to comment.