Commit 35f66c14 authored by Piergiorgio Pancino's avatar Piergiorgio Pancino

Merge branch 'mapping_session' into 'master'

Issue 767 + mapping refactoring

Closes #767

See merge request bliss/bliss!1311
parents 3a7f3696 37028270
Pipeline #11494 passed with stages
in 35 minutes and 41 seconds
......@@ -7,11 +7,6 @@
"""Bliss main package
For your convenience, configuration motion and scan APIs have been made available
directly at this level.
Here are the main bliss sub-systems:
.. autosummary::
:toctree:
......@@ -40,5 +35,3 @@ monkey.patch_all(thread=False)
from redis import selector
selector._DEFAULT_SELECTOR = selector.SelectSelector
from bliss.common import logtools
......@@ -6,10 +6,12 @@
# Distributed under the GNU LGPLv3. See LICENSE for more info.
from warnings import warn
import logging
from .embl import ExporterClient
from bliss.common.logtools import LogMixin
from bliss.common import session
import gevent
from gevent.queue import Queue
from .embl import ExporterClient
exporter_clients = {}
......@@ -25,7 +27,7 @@ def start_exporter(address, port, timeout=3, retries=1):
return exporter_clients[(address, port)]
class Exporter(ExporterClient.ExporterClient):
class Exporter(ExporterClient.ExporterClient, LogMixin):
STATE_EVENT = "State"
STATUS_EVENT = "Status"
VALUE_EVENT = "Value"
......@@ -57,6 +59,10 @@ class Exporter(ExporterClient.ExporterClient):
self.events_queue = Queue()
self.events_processing_task = None
session.get_current().map.register(
self, parents_list=["comms"], tag=f"exporter: {address}:{port}"
)
def start(self):
pass
# self.started=True
......@@ -139,7 +145,7 @@ class Exporter(ExporterClient.ExporterClient):
try:
cb(self._to_python_value(value))
except:
logging.exception(
self._logger.exception(
"Exception while executing callback %s for event %s", cb, name
)
continue
......
......@@ -21,7 +21,6 @@ __all__ = [
import re
import enum
import logging
import gevent
from gevent import lock
import numpy
......@@ -32,7 +31,7 @@ from ...common.greenlet_utils import KillMask, protect_from_kill
from bliss.comm.util import HexMsg
from bliss.common.tango import DeviceProxy
from bliss.common import mapping
from bliss.common import session
from bliss.common.logtools import LogMixin
__TMO_TUPLE = (
......@@ -137,7 +136,7 @@ class Prologix(LogMixin):
hostname = match.group(2)
port = match.group(3) and int(match.group(3)) or 1234
self._sock = Socket(hostname, port, timeout=keys.get("timeout"))
mapping.register(self, children_list=["comms", self._sock])
session.get_current().map.register(self, children_list=["comms", self._sock])
self._logger.debug(f"Prologix::__init__() host = {hostname} port = {port}")
self._gpib_kwargs = keys
......@@ -237,7 +236,7 @@ class TangoDeviceServer(LogMixin):
self._pad = keys["pad"]
self._sad = keys.get("sad", 0)
self._pad_sad = self._pad + (self._sad << 8)
mapping.register(self)
session.get_current().map.register(self)
def init(self):
self._logger.debug("TangoDeviceServer::init()")
......@@ -283,7 +282,7 @@ class LocalGpib(LogMixin):
raise LocalGpibError("LocalGpib: url is not valid (%s)" % url)
self._gpib_kwargs = keys
mapping.register(self, tag=str(self))
session.get_current().map.register(self, tag=str(self))
def __str__(self):
return "{0}(board={1})".format(type(self).__name__, self.board_index)
......@@ -373,7 +372,7 @@ class Gpib(LogMixin):
self._raw_handler = None
self._data = b""
mapping.register(self, tag=str(self))
session.get_current().map.register(self, tag=str(self))
def __str__(self):
opts = self._gpib_kwargs
......
......@@ -35,7 +35,7 @@
import socket, sys
from struct import *
from bliss.common import mapping
from bliss.common import session
from bliss.common.logtools import LogMixin
# debug = ["io", "ignore_not_impl"] # "dummy_io", "rw"
......@@ -75,12 +75,12 @@ class EnetSocket(LogMixin):
self.sta = self.err = self.cnt = 0
self.enet1000 = False
self._extra_socket = list()
mapping.register(self, parents_list=["comms"], tag=str(self))
session.get_current().map.register(self, parents_list=["comms"], tag=str(self))
def _open(self):
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.connect((self._host, self._port))
mapping.register(
session.get_current().map.register(
self, parents_list=["comms"], children_list=[self._sock], tag=str(self)
)
......
......@@ -18,7 +18,7 @@ from .exceptions import CommunicationError, CommunicationTimeout
from ..common.greenlet_utils import KillMask, protect_from_kill
from . import serial
from bliss.common import mapping
from bliss.common import session
from bliss.common.logtools import LogMixin
......@@ -94,7 +94,7 @@ class Modbus_RTU(LogMixin):
self._serial = serial.Serial(*args, **kwargs)
self.node = node
self._lock = lock.RLock()
mapping.register(self, children_list=[self._serial])
session.get_current().map.register(self, children_list=[self._serial])
def __del__(self):
self._serial.close()
......
"""
:term:`SCPI` helpers (:class:`~bliss.comm.scpi.SCPI` class and \
:func:`~bliss.comm.scpi.BaseDevice` )
:func:`~bliss.comm.scpi.BaseSCPIDevice` )
Example::
......@@ -36,13 +36,14 @@ Example::
import re
import inspect
import logging
from functools import partial
import numpy
from .util import get_interface
from .exceptions import CommunicationError, CommunicationTimeout
from bliss.common import session
from bliss.common.logtools import LogMixin
def decode_IDN(s):
......@@ -380,7 +381,7 @@ def sanitize_msgs(*msgs, **opts):
return commands, queries, eol.join(result) + eol
class SCPI(object):
class SCPI(LogMixin):
"""
:term:`SCPI` language helper.
......@@ -410,15 +411,15 @@ class SCPI(object):
print scpi['*IDN']
"""
def __init__(self, *args, **kwargs):
interface, args, kwargs = get_interface(*args, **kwargs)
def __init__(self, interface=None, commands=COMMANDS, **kwargs):
self.interface = interface
session.get_current().map.register(
self, parents_list=["comms"], children_list=[self.interface], tag=str(self)
)
self._strict_query = kwargs.get("strict_query", True)
self._logger = logging.getLogger(str(self))
self._debug = self._logger.debug
self._contexts = []
self._eol = interface._eol
self.commands = Commands(kwargs.get("commands", COMMANDS))
self.commands = Commands(commands)
def enter_context(self):
context = dict(commands=[], result=None)
......@@ -594,7 +595,9 @@ class SCPI(object):
try:
result = getf(result)
except:
self._debug("Failed to convert result. Details:", exc_info=1)
self._logger.debug(
"Failed to convert result. Details:", exc_info=1
)
results.append((query, result))
return results
......@@ -656,7 +659,7 @@ class SCPI(object):
return stack or None
class BaseDevice(object):
class BaseSCPIDevice(LogMixin):
"""Base SCPI device class"""
def __init__(self, *args, **kwargs):
......@@ -664,7 +667,9 @@ class BaseDevice(object):
commands = kwargs.pop("commands", {})
self.interface = interface
self.language = SCPI(interface=interface, commands=commands)
self._logger = logging.getLogger(str(self))
session.get_current().map.register(
self, children_list=[self.language], tag=str(self)
)
def __str__(self):
return "{0}({1})".format(type(self).__name__, self.language)
......@@ -688,158 +693,3 @@ class BaseDevice(object):
def __exit__(self, etype, evalue, etraceback):
return self.language.exit_context(etype, evalue, etraceback)
def main(argv=None):
"""
Start a SCPI console
The following example will start a SCPI console with one SCPI instrument
called *s*::
$ python -m bliss.comm.scpi gpib --pad=15 enet://gpibhost
scpi> print s['*IDN']
"""
import sys
import argparse
try:
import serial
except:
serial = None
parser = argparse.ArgumentParser(description=main.__doc__)
parser.add_argument(
"--log-level",
type=str,
default="info",
choices=["trace", "debug", "info", "warning", "error"],
help="global log level [default: info]",
)
parser.add_argument(
"--scpi-log-level",
type=str,
default="info",
choices=["trace", "debug", "info", "warning", "error"],
help="log level for scpi object[default: info]",
)
parser.add_argument(
"--gevent",
action="store_true",
default=False,
help="enable gevent in console [default: False]",
)
subparsers = parser.add_subparsers(
title="connection",
dest="connection",
description="valid type of connections",
help="choose one type of connection",
)
gpib_parser = subparsers.add_parser("gpib", help="GPIB connection")
add = gpib_parser.add_argument
add(
"url", type=str, help="gpib instrument url (ex: gpibhost, enet://gpibhost:5000)"
)
add("--pad", type=int, required=True, help="primary address")
add("--sad", type=int, default=0, help="secondary address [default: 0]")
add(
"--tmo",
type=int,
default=10,
help="gpib timeout (gpib tmo unit) [default: 10 (=300ms)]",
)
add("--eos", type=str, default="\n", help=r"end of string [default: '\n']")
add("--timeout", type=float, default=0.4, help="socket timeout [default: 0.4]")
tcp_parser = subparsers.add_parser("tcp", help="TCP connection")
add = tcp_parser.add_argument
add("url", type=str, help="tcp instrument url (ex: host:5000, socket://host:5000)")
add("--timeout", type=float, default=5, help="timeout")
add("--eol", type=str, default="\n", help=r"end of line [default: '\n']")
if serial:
serial_parser = subparsers.add_parser("serial", help="serial line connection")
add = serial_parser.add_argument
add(
"port",
type=str,
help="serial instrument port (ex: rfc2217://.., ser2net://..)",
)
add("--baudrate", type=int, default=9600, help="baud rate")
add(
"--bytesize",
type=int,
choices=[6, 7, 8],
default=serial.EIGHTBITS,
help="byte size",
)
add(
"--parity",
choices=serial.PARITY_NAMES.keys(),
default=serial.PARITY_NONE,
help="parity type",
)
add("--timeout", type=float, default=5, help="timeout")
add(
"--stopbits",
type=float,
choices=[1, 1.5, 2],
default=serial.STOPBITS_ONE,
help="stop bits",
)
add("--xonxoff", action="store_true", default=False, help="")
add("--rtscts", action="store_true", default=False, help="")
add("--write-timeout", dest="writeTimeout", type=float, default=None, help="")
add("--dsrdtr", action="store_true", default=False, help="")
add(
"--interchar-timeout",
dest="interCharTimeout",
type=float,
default=None,
help="",
)
add("--eol", type=str, default="\n", help="end of line [default: '\\n']")
args = parser.parse_args()
vargs = vars(args)
log_level = vargs.pop("log_level").upper()
scpi_log_level = vargs.pop("scpi_log_level").upper()
logging.basicConfig(
level=log_level, format="%(asctime)s %(levelname)s %(name)s: %(message)s"
)
gevent_arg = vargs.pop("gevent")
conn = vargs.pop("connection")
kwargs = {conn: vargs, "commands": COMMANDS}
mode = not gevent_arg and "interactive, no gevent" or "gevent"
scpi = SCPI(**kwargs)
scpi._logger.setLevel(scpi_log_level)
local = dict(s=scpi)
banner = "\nWelcome to SCPI console " "(connected to {0}) ({1})\n".format(
scpi, mode
)
sys.ps1 = "scpi> "
sys.ps2 = len(sys.ps1) * "."
if gevent_arg:
try:
from gevent.monkey import patch_sys
except ImportError:
mode = "no gevent"
else:
patch_sys()
import code
code.interact(banner=banner, local=local)
if __name__ == "__main__":
main()
......@@ -19,7 +19,7 @@ from gevent import socket, select, lock, event
from ..common.greenlet_utils import KillMask
from bliss.common.cleanup import capture_exceptions
from bliss.common import mapping
from bliss.common import session
from bliss.common.logtools import LogMixin
import serial
......@@ -746,7 +746,7 @@ class Serial(LogMixin):
self._timeout = timeout
self._raw_handler = None
self._lock = lock.RLock()
mapping.register(self, parents_list=["comms"], tag=str(self))
session.get_current().map.register(self, parents_list=["comms"], tag=str(self))
def __del__(self):
self.close()
......@@ -771,7 +771,7 @@ class Serial(LogMixin):
self._raw_handler = TangoSerial(self, **self._serial_kwargs)
else: # LOCAL
self._raw_handler = LocalSerial(self, **self._serial_kwargs)
mapping.register(
session.get_current().map.register(
self,
parents_list=["comms"],
children_list=[self._raw_handler],
......
......@@ -15,7 +15,6 @@ from bliss.common import event
import gevent
import weakref
import types
import logging
(DOREG, DONTREG, WAITREG) = (0, 1, 2)
......
......@@ -16,7 +16,6 @@ SpecCommandA
import sys
import types
import logging
import gevent
from gevent.event import Event
from .connection import SpecConnection
......
......@@ -17,8 +17,9 @@ import gevent
import gevent.socket
import socket
import weakref
import logging
from bliss.common import event
from bliss.common import session
from bliss.common.logtools import LogMixin
from .error import SpecClientNotConnectedError
from .channel import SpecChannel
from .message import *
......@@ -118,7 +119,7 @@ def connectionHandler(conn, socket_to_spec):
try:
reply = conn.registeredReplies[replyID]
except BaseException:
logging.getLogger("SpecClient").exception(
conn._logger.exception(
"Unexpected error while receiving a message from server"
)
else:
......@@ -142,7 +143,7 @@ def connectionHandler(conn, socket_to_spec):
receivedStrings = [s[offset:]]
class SpecConnection:
class SpecConnection(LogMixin):
"""SpecConnection class
Signals:
connected() -- emitted when the required Spec version gets connected
......@@ -183,6 +184,8 @@ class SpecConnection:
self.port = None
self.scanport = True
session.get_current().map.register(self, parents_list=["comms"], tag=str(self))
def __str__(self):
return "<connection to Spec, host=%s, port=%s>" % (
self.host,
......@@ -226,7 +229,7 @@ class SpecConnection:
# we received a value, so emit an update signal
channel.update(channelValue, force=True)
except BaseException:
logging.getLogger("SpecClient").exception(
self._logger.exception(
"Uncaught exception in SpecConnection.registerChannel"
)
......@@ -260,7 +263,7 @@ class SpecConnection:
def error(self, error):
"""Emit the 'error' signal when the remote Spec version signals an error."""
logging.getLogger("SpecClient").error("Error from Spec: %s", error)
self._logger.error("Error from Spec: %s", error)
event.send(self, "error", (error,))
......@@ -273,7 +276,7 @@ class SpecConnection:
old_state = self.state
self.state = CONNECTED
if old_state != CONNECTED:
logging.getLogger("SpecClient").info(
self._logger.info(
"Connected to %s:%s",
self.host,
(self.scanport and self.scanname) or self.port,
......@@ -290,7 +293,7 @@ class SpecConnection:
old_state = self.state
self.state = DISCONNECTED
if old_state == CONNECTED:
logging.getLogger("SpecClient").info(
self._logger.info(
"Disconnected from %s:%s",
self.host,
(self.scanport and self.scanname) or self.port,
......@@ -347,7 +350,7 @@ class SpecConnection:
cmd -- command string
"""
if self.serverVersion < 3:
logging.getLogger("SpecClient").error(
self._logger.error(
"Cannot execute command in Spec : feature is available since Spec server v3 only"
)
else:
......@@ -369,7 +372,7 @@ class SpecConnection:
cmd -- command string
"""
if self.serverVersion < 3:
logging.getLogger("SpecClient").error(
self._logger.error(
"Cannot execute command in Spec : feature is available since Spec server v3 only"
)
else:
......
......@@ -23,7 +23,7 @@ from .exceptions import CommunicationError, CommunicationTimeout
from ..common.greenlet_utils import KillMask
from bliss.common.cleanup import error_cleanup, capture_exceptions
from bliss.common import mapping
from bliss.common import session
from bliss.common.logtools import LogMixin
......@@ -90,7 +90,7 @@ class BaseSocket(LogMixin):
self._event = event.Event()
self._raw_read_task = None
self._lock = lock.RLock()
mapping.register(self, parents_list=["comms"], tag=str(self))
session.get_current().map.register(self, parents_list=["comms"], tag=str(self))
def __del__(self):
self.close()
......@@ -405,15 +405,12 @@ class Command(LogMixin):
"""Raw command class. Provides command like API through sockets.
Consider using :class:`Tcp` with url starting with *command://* instead."""
class Transaction(LogMixin):
class Transaction:
def __init__(self, socket, transaction, clear_transaction=True):
self.__socket = socket
self.__transaction = transaction
self.__clear_transaction = clear_transaction
self.data = b""
mapping.register(
self, children_list=[self.__socket], parents_list=["comms"]
)
def __enter__(self):
return self
......@@ -461,7 +458,7 @@ class Command(LogMixin):
self._raw_read_task = None
self._transaction_list = []
self._lock = lock.RLock()
mapping.register(self, parents_list=["comms"], tag=str(self))
session.get_current().map.register(self, parents_list=["comms"], tag=str(self))
def __del__(self):
self.close()
......@@ -501,11 +498,6 @@ class Command(LogMixin):
return True
self._fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mapping.register(
self._fd,
parents_list=[self, "comms"],
tag=f"Socket[{local_host}:{local_port}",
)
err_msg = "timeout on command(%s, %d)" % (local_host, local_port)
with gevent.Timeout(local_timeout, CommandTimeout(err_msg)):
......
......@@ -15,9 +15,9 @@ The alias serves the following purposes:
import weakref
from tabulate import tabulate
from bliss.config import static
from bliss import setup_globals
from bliss.common import session
from bliss.common.utils import get_counters_iter
class AliasMixin(object):
......@@ -161,7 +161,7 @@ class Alias(object):
raise RuntimeError(
f"Alias '{alias_name}' for '{original_name}' can not be set! There is alreadey an Object or Alias with this name"
)
elif alias_name in static.get_config().names_list:
elif alias_name in session.get_current().config.names_list:
raise RuntimeError(
f"Alias '{alias_name}' for '{original_name}' can not be set! {alias_name} already used as name-key in config"
)
......@@ -173,14 +173,13 @@ class Alias(object):
# check if there is a counter around that can be linked to this alias
if not disable_link_search:
from bliss.common.utils import counter_dict
for key, item in counter_dict().items():
for cnt in get_counters_iter():
key = cnt.fullname
if key == original_name:
self._link_to(item)
self._link_to(cnt)
break
elif item.name == original_name:
self._link_to(item)
elif cnt.name == original_name:
self._link_to(cnt)
break
print(f"Alias '{alias_name}' added for '{original_name}'")
......
......@@ -40,8 +40,6 @@ from bliss.common.hook import MotionHook
from bliss.config.channels import Channel
from bliss.common.alias import AliasMixin
from bliss.physics.trajectory import LinearTrajectory
from bliss import setup_globals
from bliss.common import mapping
from bliss.common.logtools import LogMixin
import gevent
import re
......@@ -590,7 +588,6 @@ class Axis(AliasMixin, LogMixin):
disabled_cache.extend(config.get("disabled_cache", [])) # get it for this axis
for settings_name in disabled_cache:
self.settings.disable_cache(settings_name)
mapping.register(self, parents_list=[self.__controller], tag=f"axis.{name}")
self._unit = self.config.get("unit", str, None)
def __close__(self):
......
......@@ -5,7 +5,6 @@
# Copyright (c) 2015-2019 Beamline Control Unit, ESRF
# Distributed under the GNU LGPLv3. See LICENSE for more info.
from bliss.common import log as elog
from bliss.common.motor_config import StaticConfig
from bliss.common import event
import time
......
......@@ -9,12 +9,13 @@
how to use motion hooks in your system"""
import weakref
from bliss.common import session
from bliss.common.logtools import LogMixin
__all__ = ["MotionHook"]
class MotionHook(object):
class MotionHook(LogMixin):
"""
Base motion hook. Executed before a motion starts and after motion ends.
"""
......@@ -30,6 +31,7 @@ class MotionHook(object):
axis (Axis): new axis to be added to the hook
"""
self.__axes[axis.name] = axis
session.get_current().map.register(self, children_list=list(self.axes.values()))
@property
def axes(self):
......
This diff is collapsed.
This diff is collapsed.
......@@ -14,8 +14,24 @@ import weakref
from collections import namedtuple
import enum
from bliss.common.utils import add_conversion_function
from bliss.common.alias import AliasMixin
from bliss.common import session
def add_conversion_function(obj, method_name, function):
meth = getattr(obj, method_name)
if inspect.ismethod(meth):
if callable(function):