[pytango] 431/483: Add new server features

Sandor Bodo-Merle sbodomerle-guest at moszumanska.debian.org
Thu Sep 28 19:15:09 UTC 2017


This is an automated email from the git hooks/post-receive script.

sbodomerle-guest pushed a commit to annotated tag bliss_8.10
in repository pytango.

commit 3c39a583292db62c979c712c2c586a65c1b7266c
Author: coutinho <coutinho at esrf.fr>
Date:   Tue Dec 16 17:20:14 2014 +0100

    Add new server features
    
    - callbacks at different phases
    - register_object works at any time during server lifetime.
      can only add objects of new class until phase1 (inlcuding).
      On phase >=2 can only add objects of registered classes.
    - Removed Server wrapper function; renamed _Server to Server
    - Reorganized methods in server private, protected, public
---
 src/boost/python/server.py | 350 ++++++++++++++++++++++-----------------------
 1 file changed, 173 insertions(+), 177 deletions(-)

diff --git a/src/boost/python/server.py b/src/boost/python/server.py
index 3dd2a04..23c577e 100644
--- a/src/boost/python/server.py
+++ b/src/boost/python/server.py
@@ -1168,7 +1168,7 @@ def __to_tango_type_fmt(value):
     return dtype, dfmt, max_dim_x, max_dim_y
 
 
-def create_tango_class(obj, tango_class_name=None, member_filter=None):
+def create_tango_class(server, obj, tango_class_name=None, member_filter=None):
     log = logging.getLogger("PyTango.Server")
 
     obj_klass = obj.__class__
@@ -1184,7 +1184,7 @@ def create_tango_class(obj, tango_class_name=None, member_filter=None):
 
         def __init__(self, tango_class_obj, name):
             Device.__init__(self, tango_class_obj, name)
-            self.__tango_obj = Server().get_tango_object(self.get_name())
+            self.__tango_obj = server.get_tango_object(self.get_name())
             self.__tango_obj.device = self
 
         def init_device(self):
@@ -1214,7 +1214,7 @@ def create_tango_class(obj, tango_class_name=None, member_filter=None):
             func = member
             func_name = name
             def _command(obj, func_name, param):
-                server = Server()
+                #server = Server()
                 runner = server.runner
                 args, kwargs = loads(*param)
                 f = getattr(obj, func_name)
@@ -1248,11 +1248,9 @@ def create_tango_class(obj, tango_class_name=None, member_filter=None):
                 dtype = CmdArgType.DevEncoded
                 fmt = AttrDataFormat.SCALAR
                 def read(dev, attr):
-                    server = Server()
-                    runner = server.runner
                     name = attr.get_name()
-                    if runner:
-                        value = runner.execute(getattr, obj, name)
+                    if server.runner:
+                        value = server.runner.execute(getattr, obj, name)
                     else:
                         value = getattr(obj, name)
                     attr.set_value(*server.dumps(value))
@@ -1260,29 +1258,23 @@ def create_tango_class(obj, tango_class_name=None, member_filter=None):
                     name = attr.get_name()
                     value = attr.get_write_value()
                     value = loads(*value)
-                    server = Server()
-                    runner = server.runner
-                    if runner:
-                        runner.execute(setattr, obj, name, value)
+                    if server.runner:
+                        server.runner.execute(setattr, obj, name, value)
                     else:
                         setattr(obj, name, value)
             else:
                 def read(dev, attr):
-                    server = Server()
-                    runner = server.runner
                     name = attr.get_name()
-                    if runner:
-                        value = runner.execute(getattr, obj, name)
+                    if server.runner:
+                        value = server.runner.execute(getattr, obj, name)
                     else:
                         value = getattr(obj, name)
                     attr.set_value(value)
                 def write(dev, attr):
-                    server = Server()
-                    runner = server.runner
                     name = attr.get_name()
                     value = attr.get_write_value()
-                    if runner:
-                        runner.execute(setattr, obj, name, value)
+                    if server.runner:
+                        server.runner.execute(setattr, obj, name, value)
                     else:
                         setattr(obj, name, value)
             read.__name__ = "_read_" + name
@@ -1293,7 +1285,7 @@ def create_tango_class(obj, tango_class_name=None, member_filter=None):
             if read_only:
                 write = None
             else:
-                write.__name__ = "_write" + name
+                write.__name__ = "_write_" + name
                 pars['fset'] = write
                 setattr(DeviceDispatcher, write.__name__, write)
             attr_data = AttrData.from_dict(pars)
@@ -1301,7 +1293,14 @@ def create_tango_class(obj, tango_class_name=None, member_filter=None):
     return DeviceDispatcher
 
 
-class _Server:
+class Server:
+    """
+    Server helper
+    """
+
+    Phase0, Phase1, Phase2 = range(3)
+    PreInitPhase = Phase1
+    PostInitPhase = Phase2
 
     class TangoObject:
 
@@ -1331,15 +1330,18 @@ class _Server:
             return self.__obj()
 
     def __init__(self, server_name, server_type=None, port=None,
-                 event_loop_callback=None, pre_init_callback=None,
-                 post_init_callback=None, auto_clean=False, green_mode=None,
-                 tango_classes=None, protocol="pickle"):
+                 event_loop_callback=None, init_callbacks=None,
+                 auto_clean=False, green_mode=None, tango_classes=None,
+                 protocol="pickle"):
+        if server_name is None:
+            raise ValueError("Must give a valid server name")
         self.__server_name = server_name
         self.__server_type = server_type
         self.__port = port
         self.__event_loop_callback = event_loop_callback
-        self.__pre_init_callback = pre_init_callback
-        self.__post_init_callback = post_init_callback
+        if init_callbacks is None:
+            init_callbacks = {}
+        self.__init_callbacks = init_callbacks
         self.__util = None
         self.__objects = {}
         self.__running = False
@@ -1353,6 +1355,7 @@ class _Server:
         else:
             self.__runner = None
         self.log = logging.getLogger("PyTango.Server")
+        self.__phase = Server.Phase0
 
     def __build_args(self):
         args = [self.server_type, self.__server_name]
@@ -1361,129 +1364,6 @@ class _Server:
                          "giop:tcp::{0}".format(self.__port)])
         return args
 
-    def __get_devices(self):
-        """
-        Helper that retuns a dict of devices for this server.
-
-        :return:
-            Returns a tuple of two elements:
-              - dict<tango class name : list of device names>
-              - dict<device names : tango class name>
-        :rtype: tuple<dict, dict>
-        """
-        import PyTango
-        db = PyTango.Database()
-        server = self.server_instance
-        dev_list = db.get_device_class_list(server)
-        class_map, dev_map  = {}, {}
-        for class_name, dev_name in zip(dev_list[1::2], dev_list[::2]):
-            dev_names = class_map.get(class_name)
-            if dev_names is None:
-                class_map[class_name] = dev_names = []
-            dev_name = dev_name.lower()
-            dev_names.append(dev_name)
-            dev_map[dev_name] = class_name
-        return class_map, dev_map
-
-    @property
-    def server_type(self):
-        server_type = self.__server_type
-        if server_type is None:
-            server_file = os.path.basename(sys.argv[0])
-            server_type = os.path.splitext(server_file)[0]
-        return server_type
-
-    @property
-    def server_instance(self):
-        return "{0}/{1}".format(self.server_type, self.__server_name)
-
-    @property
-    def tango_util(self):
-        if self.__util is None:
-            import PyTango
-            self.__util = PyTango.Util(self.__build_args())
-        return self.__util
-
-    @property
-    def green_mode(self):
-        gm = self.__green_mode
-        if gm is None:
-            from PyTango import get_green_mode
-            gm = get_green_mode()
-        return gm
-
-    @green_mode.setter
-    def green_mode(self, gm):
-        if gm == self.__green_mode:
-            return
-        if self.__running:
-            raise RuntimeError("Cannot change green mode while "
-                               "server is running")
-        self.__green_mode = gm
-
-    @property
-    def gevent_mode(self):
-        return self.green_mode == GreenMode.Gevent
-
-    @property
-    def runner(self):
-        return self.__runner
-
-    def dumps(self, obj):
-        return dumps(self.__protocol, obj)
-
-    def get_tango_object(self, name):
-        return self.__objects.get(name.lower())
-
-    def get_tango_class(self, tango_class_name):
-        for klass in self.__tango_classes:
-            if klass.TangoClassName == tango_class_name:
-                return klass
-
-    def __find_tango_class(self, key):
-        pass
-
-    def register_tango_device(self, klass, name):
-        if inspect.isclass(klass):
-            if isinstance(klass, Device):
-                kk, k, kname = Device.TangoClassClass, Device, Device.TangoClassName
-            else:
-                raise ValueError
-        else:
-            raise NotImplementedError
-
-    def register_tango_class(self, klass):
-        if self.__running:
-            raise RuntimeError("Cannot create new Tango class while "
-                               "while server is running")
-        self.__tango_classes.append(klass)
-
-    def register_object(self, obj, name, tango_class_name=None,
-                        member_filter=None):
-        """
-        :param member_filter:
-            callable(obj, tango_class_name, member_name, member) -> bool
-        """
-        slash_count = name.count("/")
-        if slash_count == 0:
-            alias = name
-            full_name = "{0}/{1}".format(self.server_instance, name)
-        elif slash_count == 2:
-            alias = None
-            full_name = name
-        else:
-            raise
-        tango_object = self.TangoObject(obj, full_name, alias,
-                                        tango_class_name=tango_class_name)
-        tango_class_name = tango_object.tango_class_name
-        tango_class = self.get_tango_class(tango_class_name)
-        if tango_class is None:
-            tango_class = create_tango_class(obj, tango_class_name,
-                                             member_filter=member_filter)
-            self.register_tango_class(tango_class)
-        self.__objects[full_name.lower()] = tango_object
-        return tango_object
-
     def __exec_cb(self, cb):
         if not cb:
             return
@@ -1492,16 +1372,16 @@ class _Server:
         else:
             cb()
 
-    def _pre_init_callback(self):
-        self.__exec_cb(self.__pre_init_callback)
-
-    def _post_init_callback(self):
-        self.__exec_cb(self.__post_init_callback)
+    def __find_tango_class(self, key):
+        pass
 
     def __prepare(self):
         """Update database with existing devices"""
         self.log.debug("prepare")
 
+        if self.__phase > 0:
+            raise RuntimeError("Internal error: Can only prepare in phase 0")
+
         server_instance = self.server_instance
         db = Database()
 
@@ -1519,7 +1399,7 @@ class _Server:
                 except:
                     self.log.info("Last time server was not properly "
                                   "shutdown!")
-            db_class_map, db_device_map = self.__get_devices()
+            db_class_map, db_device_map = self.get_devices()
         else:
             db_class_map, db_device_map = {}, {}
 
@@ -1588,8 +1468,6 @@ class _Server:
         util = self.tango_util
         u_instance = util.instance()
 
-        self._pre_init_callback()
-
         if gevent_mode:
             if event_loop:
                 event_loop = functools.partial(self.__runner.execute,
@@ -1614,7 +1492,7 @@ class _Server:
         self.__running = True
         u_instance = self.tango_util.instance()
         u_instance.server_init()
-        self._post_init_callback()
+        self.__phase = Server.Phase2
         self.log.info("Ready to accept request")
         u_instance.server_run()
         if self.gevent_mode:
@@ -1623,6 +1501,143 @@ class _Server:
             self.__clean_up_process()
         self.log.debug("Tango loop exit")
 
+    @property
+    def _phase(self):
+        return self.__phase
+
+    @_phase.setter
+    def _phase(self, phase):
+        self.__phase = phase
+        cb = self.__init_callbacks.get(phase)
+        self.__exec_cb(cb)
+
+    @property
+    def server_type(self):
+        server_type = self.__server_type
+        if server_type is None:
+            server_file = os.path.basename(sys.argv[0])
+            server_type = os.path.splitext(server_file)[0]
+        return server_type
+
+    @property
+    def server_instance(self):
+        return "{0}/{1}".format(self.server_type, self.__server_name)
+
+    @property
+    def tango_util(self):
+        if self.__util is None:
+            import PyTango
+            self.__util = PyTango.Util(self.__build_args())
+            self._phase = Server.Phase1
+        return self.__util
+
+    @property
+    def green_mode(self):
+        gm = self.__green_mode
+        if gm is None:
+            from PyTango import get_green_mode
+            gm = get_green_mode()
+        return gm
+
+    @green_mode.setter
+    def green_mode(self, gm):
+        if gm == self.__green_mode:
+            return
+        if self.__running:
+            raise RuntimeError("Cannot change green mode while "
+                               "server is running")
+        self.__green_mode = gm
+
+    @property
+    def gevent_mode(self):
+        return self.green_mode == GreenMode.Gevent
+
+    @property
+    def runner(self):
+        return self.__runner
+
+    def dumps(self, obj):
+        return dumps(self.__protocol, obj)
+
+    def get_devices(self):
+        """
+        Helper that retuns a dict of devices for this server.
+
+        :return:
+            Returns a tuple of two elements:
+              - dict<tango class name : list of device names>
+              - dict<device names : tango class name>
+        :rtype: tuple<dict, dict>
+        """
+        import PyTango
+        db = PyTango.Database()
+        server = self.server_instance
+        dev_list = db.get_device_class_list(server)
+        class_map, dev_map  = {}, {}
+        for class_name, dev_name in zip(dev_list[1::2], dev_list[::2]):
+            dev_names = class_map.get(class_name)
+            if dev_names is None:
+                class_map[class_name] = dev_names = []
+            dev_name = dev_name.lower()
+            dev_names.append(dev_name)
+            dev_map[dev_name] = class_name
+        return class_map, dev_map
+
+    def get_tango_object(self, name):
+        return self.__objects.get(name.lower())
+
+    def get_tango_class(self, tango_class_name):
+        for klass in self.__tango_classes:
+            if klass.TangoClassName == tango_class_name:
+                return klass
+
+    def register_tango_device(self, klass, name):
+        if inspect.isclass(klass):
+            if isinstance(klass, Device):
+                kk, k, kname = Device.TangoClassClass, Device, Device.TangoClassName
+            else:
+                raise ValueError
+        else:
+            raise NotImplementedError
+
+    def register_tango_class(self, klass):
+        if self._phase > Server.Phase1:
+            raise RuntimeError("Cannot add new class after phase 1 "
+                               "(i.e. after server_init)")
+        self.__tango_classes.append(klass)
+
+    def register_object(self, obj, name, tango_class_name=None,
+                        member_filter=None):
+        """
+        :param member_filter:
+            callable(obj, tango_class_name, member_name, member) -> bool
+        """
+        slash_count = name.count("/")
+        if slash_count == 0:
+            alias = name
+            full_name = "{0}/{1}".format(self.server_instance, name)
+        elif slash_count == 2:
+            alias = None
+            full_name = name
+        else:
+            raise ValueError("Invalid name")
+
+        tango_class_name = tango_class_name or obj.__class__.__name__
+        tango_class = self.get_tango_class(tango_class_name)
+
+        if tango_class is None:
+            tango_class = create_tango_class(self, obj, tango_class_name,
+                                             member_filter=member_filter)
+            self.register_tango_class(tango_class)
+
+        tango_object = self.TangoObject(obj, full_name, alias,
+                                        tango_class_name=tango_class_name)
+        self.__objects[full_name.lower()] = tango_object
+        if self._phase > Server.Phase1:
+            util = self.tango_util
+            util.create_device(tango_class_name, name)
+        return tango_object
+
     def run(self, timeout=None):
         self.log.debug("run")
         gevent_mode = self.gevent_mode
@@ -1634,22 +1649,3 @@ class _Server:
             if not gevent_mode:
                 raise RuntimeError("Server is already running")
         self.__run(timeout=timeout)
-
-
-__SERVER = None
-def Server(server_name=None, server_type=None, port=None,
-           event_loop_callback=None, post_init_callback=None,
-           auto_clean=False, green_mode=None):
-    """Experimental server class. Not part of the official API"""
-
-    global __SERVER
-    if __SERVER is None:
-        if server_name is None:
-            raise ValueError("Must give a valid server name")
-        __SERVER = _Server(server_name,
-                           server_type=server_type, port=port,
-                           event_loop_callback=event_loop_callback,
-                           post_init_callback=post_init_callback,
-                           auto_clean=auto_clean,
-                           green_mode=green_mode)
-    return __SERVER

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/pytango.git



More information about the debian-science-commits mailing list