Commit 16d0d78f authored by Matias Guijarro's avatar Matias Guijarro

config plugins: unified axes and temp plugins code

* moved Reference class from emotion to utils
    - 'replace_reference_by_object' uses Reference objects by default
* allow empty names, both for motor controllers or temperature controllers
* controllers are not returned from config plugin, if no name has been given
parent df531401
......@@ -13,7 +13,6 @@ import math
import gevent
import gevent.event
from bliss.common import session
from bliss.common.task import task
from bliss.common.logtools import LogMixin
from bliss.common.utils import with_custom_members
......@@ -49,10 +48,6 @@ class Input(LogMixin):
self.__name = config["name"]
self.__config = config
session.get_current().map.register(
self, parents_list=[controller, "counters"], tag=f"{self.name}"
)
# useful attribute for a temperature controller writer
self._attr_dict = {}
......@@ -120,10 +115,6 @@ class Output(LogMixin):
# useful attribute for a temperature controller writer
self._attr_dict = {}
session.get_current().map.register(
self, parents_list=[controller, "counters"], tag=f"{self.name}"
)
@property
def controller(self):
""" returns the temperature controller """
......@@ -387,8 +378,8 @@ class Loop(LogMixin):
self.__controller = controller
self.__name = config["name"]
self.__config = config
self.__input = controller.get_object(config["input"][1:])
self.__output = controller.get_object(config["output"][1:])
self.__input = config.get("input")
self.__output = config.get("output")
self._Pval = None
self._Ival = None
self._Dval = None
......@@ -396,13 +387,6 @@ class Loop(LogMixin):
# useful attribute for a temperature controller writer
self._attr_dict = {}
session.get_current().map.register(
self,
parents_list=[controller],
children_list=[self.__input, self.__output],
tag=f"{self.name}",
)
@property
def controller(self):
""" returns the temperature controller """
......@@ -421,11 +405,15 @@ class Loop(LogMixin):
@property
def input(self):
""" returns the loop input object """
if not isinstance(self.__input, Input):
self.__input = self.__input()
return self.__input
@property
def output(self):
""" returns the loop output object """
if not isinstance(self.__output, Output):
self.__output = self.__output()
return self.__output
def set(self, new_setpoint=None, wait=False, **kwargs):
......
......@@ -13,13 +13,12 @@ import pkgutil
from bliss.common import axis as axis_module
from bliss.common.axis import Axis
from bliss.common.encoder import Encoder
from bliss.config.static import Config, get_config
from bliss.config.static import Config
from bliss.common.tango import DeviceProxy
from bliss.config.plugins.utils import find_class, replace_reference_by_object
from bliss.config.plugins.utils import find_class, replace_reference
import bliss.controllers.motors
import gevent
import hashlib
import sys
......@@ -313,21 +312,6 @@ def add_axis(cfg, request):
)
class Reference:
def __init__(self, name, *args, **kwargs):
self.__name = name.lstrip("$")
@property
def name(self):
return self.__name
def __call__(self, *args, **kwargs):
return get_config().get(self.name)
def __str__(self):
return f"${self.name}"
def create_objects_from_config_node(config, node):
if "axes" in node or "encoders" in node:
# asking for a controller
......@@ -338,13 +322,6 @@ def create_objects_from_config_node(config, node):
controller_class_name = node.get("class")
controller_name = node.get("name")
if controller_name is None:
h = hashlib.md5()
for axis_config in node.get("axes"):
name = axis_config.get("name")
if name is not None:
h.update(name.encode())
controller_name = h.hexdigest()
controller_class = find_class(node, "bliss.controllers.motors")
controller_module = sys.modules[controller_class.__module__]
axes = list()
......@@ -370,7 +347,7 @@ def create_objects_from_config_node(config, node):
(switches, switches_names, None, "Switch", node.get("switches", [])),
):
for config_dict in config_nodes_list:
replace_reference_by_object(config, config_dict, placeholder=Reference)
replace_reference(config, config_dict)
if not isinstance(config_dict.get("name"), str):
# reference
object_class = config_dict.get("name")
......@@ -402,12 +379,13 @@ def create_objects_from_config_node(config, node):
all_names = axes_names + encoders_names + switches_names + shutters_names
cache_dict = dict(zip(all_names, [controller] * len(all_names)))
ctrl = cache_dict.pop(obj_name, None)
if ctrl is not None:
objects_dict = {}
if controller_name:
objects_dict[controller_name] = controller
if obj_name is not None:
obj = create_object_from_cache(None, obj_name, controller)
return {controller_name: controller, obj_name: obj}, cache_dict
else:
return {controller_name: controller}, cache_dict
objects_dict[obj_name] = obj
return objects_dict, cache_dict
def create_object_from_cache(config, name, controller):
......
......@@ -5,59 +5,77 @@
# Copyright (c) 2015-2019 Beamline Control Unit, ESRF
# Distributed under the GNU LGPLv3. See LICENSE for more info.
import sys
import itertools
from bliss.common.temperature import Input, Output, Loop
from bliss.config.plugins.utils import find_class, replace_reference
from bliss.config.plugins.utils import find_class
def create_objects_from_config_node(config, node):
if "inputs" in node or "outputs" in node or "loops" in node:
# asking for a controller
obj_name = None
else:
obj_name = node.get("name")
node = node.parent
def create_objects_from_config_node(config, item_cfg_node):
parent_node = item_cfg_node.parent
item_name = item_cfg_node["name"]
controller_class_name = node.get("class")
controller_name = node.get("name")
controller_class = find_class(node, "bliss.controllers.temperature")
controller_module = sys.modules[controller_class.__module__]
inputs = list()
outputs = list()
loops = list()
names = dict()
for category, objects in [
("inputs", inputs),
("outputs", outputs),
("ctrl_loops", loops),
]:
pnode_cat = parent_node.get(category)
if pnode_cat:
for config_item in pnode_cat:
name = config_item.get("name")
objects.append((name, config_item))
names.setdefault(category, list()).append(name)
inputs, inputs_names = [], []
outputs, outputs_names = [], []
loops, loops_names = [], []
node = node.to_dict()
controller_class = find_class(parent_node, "bliss.controllers.temperature")
controller = controller_class(parent_node, inputs, outputs, loops)
for (
objects,
objects_names,
default_class,
default_class_name,
config_nodes_list,
) in (
(inputs, inputs_names, Input, "", node.get("inputs", [])),
(outputs, outputs_names, Output, "", node.get("outputs", [])),
(loops, loops_names, Loop, "", node.get("ctrl_loops", [])),
):
for config_dict in config_nodes_list:
replace_reference(config, config_dict)
if not isinstance(config_dict.get("name"), str):
# reference
object_class = config_dict.get("name")
object_name = object_class.name
else:
object_name = config_dict.get("name")
object_class_name = config_dict.get("class")
if object_class_name is None:
object_class = default_class
if object_class is None:
try:
object_class = getattr(
controller_module, default_class_name
)
except AttributeError:
pass
else:
object_class = getattr(controller_module, object_class_name)
objects_names.append(object_name)
objects.append((object_name, object_class, config_dict))
cache_dict = dict()
for category in ("inputs", "outputs", "ctrl_loops"):
try:
cache_dict.update(
dict(zip(names[category], [controller] * len(names[category])))
)
except KeyError:
pass
controller = controller_class(node, inputs, outputs, loops)
# controller.initialize()
o = controller.get_object(item_name)
if item_name in dict(loops).keys():
referenced_object = o.config["input"][1:]
if referenced_object in controller._objects:
# referencing an object in same controller
o._Loop__input = controller._objects[referenced_object]
else:
o._Loop__input = config.get(referenced_object)
referenced_object = o.config["output"][1:]
if referenced_object in controller._objects:
# referencing an object in same controller
o._Loop__output = controller._objects[referenced_object]
else:
o._Loop__output = config.get(referenced_object)
controller._init()
return {item_name: o}, cache_dict
all_names = inputs_names + outputs_names + loops_names
cache_dict = dict(zip(all_names, [controller] * len(all_names)))
objects_dict = {}
if controller_name:
objects_dict[controller_name] = controller
if obj_name is not None:
obj = controller.get_object(obj_name)
objects_dict[obj_name] = obj
return objects_dict, cache_dict
def create_object_from_cache(config, name, controller):
......
......@@ -5,6 +5,7 @@
# Copyright (c) 2015-2019 Beamline Control Unit, ESRF
# Distributed under the GNU LGPLv3. See LICENSE for more info.
from bliss.config.static import get_config
import re
......@@ -103,6 +104,21 @@ def _parse_list(config, value, placeholder):
return object_list
class Reference:
def __init__(self, name, *args, **kwargs):
self.__name = name.lstrip("$")
@property
def name(self):
return self.__name
def __call__(self, *args, **kwargs):
return get_config().get(self.name)
def __str__(self):
return f"${self.name}"
def replace_reference_by_object(
config, item_cfg_node, ref_objects=None, placeholder=None
):
......@@ -125,3 +141,9 @@ def replace_reference_by_object(
if subref:
referenced_objects[name] = subref
item_cfg_node.update(subdict)
def replace_reference(config, item_cfg_node, ref_objects=None):
return replace_reference_by_object(
config, item_cfg_node, ref_objects, placeholder=Reference
)
......@@ -689,6 +689,7 @@ class Config:
instance_object = name2items.get(name)
from bliss.common.axis import Axis
from bliss.common.temperature import Input, Output, Loop
if isinstance(instance_object, Axis):
from bliss.common import session
......@@ -698,6 +699,22 @@ class Config:
parents_list=[instance_object.controller, "axes"],
tag=instance_object.name,
)
elif isinstance(instance_object, (Input, Output, Loop)):
from bliss.common import session
parents_list = [instance_object.controller]
if isinstance(instance_object, Loop):
children_list = [instance_object.input, instance_object.output]
else:
parents_list.append("counters")
children_list = []
session.get_current().map.register(
instance_object,
parents_list=parents_list,
children_list=children_list,
tag=instance_object.name,
)
return instance_object
......
......@@ -32,6 +32,7 @@ controller:
input: $thermo_sample <- mandatory
output: $heater <- mandatory
"""
import itertools
from bliss.common.temperature import *
from bliss.common.utils import set_custom_members
......@@ -45,50 +46,25 @@ class Controller(LogMixin):
"""
def __init__(self, config, inputs, outputs, loops):
mapping_name = config.get("name") or self.__class__.__name__.lower()
session.get_current().map.register(
self, parents_list=["controllers"], tag=mapping_name
)
# self._logger.info("on Controller")
self.__config = config
self._inputs = dict()
self._outputs = dict()
self._loops = dict()
self.__name = config.get("name")
self._objects = {}
self.initialize()
for name, cfg in inputs:
self._logger.debug(" input name: %s" % (name))
self._logger.debug(" input config: %s" % (cfg))
new_input = Input(self, cfg)
self._inputs[name] = new_input
self.initialize_input(new_input)
session.get_current().map.register(self, parents_list=["controllers"])
# For custom attributes and commands.
set_custom_members(self, new_input)
for name, cfg in outputs:
self._logger.debug(" output name: %s" % (name))
self._logger.debug(" output config: %s" % (cfg))
new_output = Output(self, cfg)
self._outputs[name] = new_output
for name, klass, cfg in itertools.chain(inputs, outputs, loops):
self._logger.debug(f" {klass.__name__} name: {name}")
self._logger.debug(f" {klass.__name__} config: {cfg}")
new_obj = klass(self, cfg)
self.initialize_output(new_output)
self._objects[name] = new_obj
# For custom attributes and commands.
set_custom_members(self, new_output)
for name, cfg in loops:
self._logger.debug(" loops name: %s" % (name))
self._logger.debug(" loops config: %s" % (cfg))
new_loop = Loop(self, cfg)
self._loops[name] = new_loop
set_custom_members(self, new_obj)
self.initialize_loop(new_loop)
# For custom attributes and commands.
set_custom_members(self, new_loop)
@property
def name(self):
return self.__name
@property
def config(self):
......@@ -109,7 +85,18 @@ class Controller(LogMixin):
"""
self._logger.info("Controller:get_object: %s" % (name))
# it is used by Loop class
return self._inputs.get(name, self._outputs.get(name, self._loops.get(name)))
return self._objects.get(name)
def _init(self):
self.initialize()
for obj in self._objects.values():
if isinstance(obj, Input):
self.initialize_input(obj)
elif isinstance(obj, Output):
self.initialize_output(obj)
elif isinstance(obj, Loop):
self.initialize_loop(obj)
def initialize(self):
"""
......
......@@ -7,7 +7,7 @@
from bliss.config.conductor import client
import pytest
import os
import sys, os
def test_config_save(beacon, beacon_directory):
......@@ -62,12 +62,12 @@ def test_references(beacon):
s1vo = beacon.get("s1vo")
try:
assert refs_cfg["scan"]["axis"].__repr__() == repr(m0)
assert refs_cfg["slits"][0]["axis"].__repr__() == repr(s1hg)
assert repr(refs_cfg["scan"]["axis"]) == repr(m0)
assert repr(refs_cfg["slits"][0]["axis"]) == repr(s1hg)
assert refs_cfg["slits"][0]["position"] == 0
assert refs_cfg["slits"][1]["axis"].__repr__() == repr(s1vo)
assert repr(refs_cfg["slits"][1]["axis"]) == repr(s1vo)
assert refs_cfg["slits"][1]["position"] == 1
assert refs_cfg["m0"].__repr__() == repr(m0)
assert repr(refs_cfg["m0"]) == repr(m0)
finally:
m0.__close__()
s1hg.__close__()
......@@ -93,8 +93,6 @@ class DummyObject:
def test_inherited_package(beacon):
import sys, os
try:
sys.path.append(os.path.dirname(__file__))
assert isinstance(beacon.get("dummy1"), DummyObject)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment