From 4e9d30d4179a86b894481d15cb3484421df4ab9e Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 15 Apr 2019 16:23:25 +0200 Subject: [PATCH 01/99] Add main Taurus parser with common options and ability to load subcommands --- lib/taurus/cli/__init__.py | 73 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 lib/taurus/cli/__init__.py diff --git a/lib/taurus/cli/__init__.py b/lib/taurus/cli/__init__.py new file mode 100644 index 000000000..ceffb06f6 --- /dev/null +++ b/lib/taurus/cli/__init__.py @@ -0,0 +1,73 @@ +import argparse +import pkg_resources + +from taurus import Release + + +def _make_parser(): + """ + Create main Taurus parser obejct with common options + """ + # TODO: fine tune those options + + + help_tauruslog = "taurus log level. Allowed values are (case insensitive): critical, "\ + "error, warning/warn, info, debug, trace" + help_tangohost = "Tango host name (either HOST:PORT or a Taurus URI, e.g. tango://foo:1234)" + help_tauruspolling = "taurus global polling period in milliseconds" + help_taurusserial = "taurus serialization mode. Allowed values are (case insensitive): "\ + "serial, concurrent (default)" + help_rcport = "enables remote debugging using the given port" + help_formatter = "Override the default formatter" + + parser = argparse.ArgumentParser(description="Taurus main launcher") + parser.add_argument("-v", "--version", action="version", version=Release) + + main_group = parser.add_argument_group(title="Common Taurus options", + description="Basic options present in any taurus application") + main_group.add_argument("--taurus-log-level", + choices=["critical", "error", "warning", "info", "debug", "trace"], + metavar="LEVEL", + default="info", + help=help_tauruslog) + main_group.add_argument("--taurus-polling-period", + type=int, + metavar="PERIOD", + help=help_tauruspolling) + main_group.add_argument("--taurus-seriallization-mode", + choices=["TangoSerial", "Serial", "Concurrent"], + metavar="SERIAL", + default="Concurrent", + help=help_taurusserial) + main_group.add_argument("--tango-host", + help=help_tangohost) + main_group.add_argument("--remote-console-port", + type=int, + metavar="PORT", + help=help_rcport) + main_group.add_argument("--default-formatter", + metavar="FORMATTER", + help=help_formatter) + + return parser + + +def _load_subcommands(parser): + """ + Load subcommands to given parser from entrypoint + """ + subparsers = parser.add_subparsers(dest='subcommand') + + for ep in pkg_resources.iter_entry_points("taurus.cli.subcommands"): + ep.load()(subparsers) + + +def main(): + parser = _make_parser() + _load_subcommands(parser) + args = parser.parse_args() + args.cmd(args) + + +if __name__ == '__main__': + main() From 0db8ad81a7b25f5076a3d91c9699ef1b923faf4a Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 15 Apr 2019 16:25:53 +0200 Subject: [PATCH 02/99] Rebuild testsuite laucnhing method to support it as a subcommand --- lib/taurus/test/testsuite.py | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/taurus/test/testsuite.py b/lib/taurus/test/testsuite.py index 488bf259a..fce1e8cea 100644 --- a/lib/taurus/test/testsuite.py +++ b/lib/taurus/test/testsuite.py @@ -101,30 +101,8 @@ def run(disableLogger=True, exclude_pattern='(?!)'): return runner.run(suite) -def main(): +def main(args): import taurus.test.skip - import argparse - from taurus import Release - parser = argparse.ArgumentParser(description='Main test suite for Taurus') - parser.add_argument('--skip-gui-tests', dest='skip_gui', - action='store_true', default=False, - help='Do not perform tests requiring GUI') - # TODO: Define the default exclude patterns as a tauruscustomsettings - # variable. - help = """regexp pattern matching test ids to be excluded. - (e.g. 'taurus\.core\..*' would exclude taurus.core tests) - """ - parser.add_argument('-e', '--exclude-pattern', - dest='exclude_pattern', - default='(?!)', - help=help) - parser.add_argument('--version', action='store_true', default=False, - help="show program's version number and exit") - args = parser.parse_args() - - if args.version: - print(Release.version) - sys.exit(0) if args.skip_gui: import taurus.test.skip @@ -144,5 +122,27 @@ def main(): sys.exit(exit_code) +def add_parser(make_parser): + parser = make_parser(description='Main test suite for Taurus') + parser.add_argument('--skip-gui-tests', dest='skip_gui', + action='store_true', default=False, + help='Do not perform tests requiring GUI') + # TODO: Define the default exclude patterns as a tauruscustomsettings + # variable. + help = """regexp pattern matching test ids to be excluded. + (e.g. 'taurus\.core\..*' would exclude taurus.core tests) + """ + parser.add_argument('-e', '--exclude-pattern', + default='(?!)', + help=help) + + parser.set_defaults(cmd=main) + + return parser + + if __name__ == '__main__': - main() + from argparse import ArgumentParser + parser = add_parser(ArgumentParser) + args = parser.parse_args() + args.cmd(args) From 4771f9ac0a3693ebefd28a5203a5d52e955d9b07 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 20:38:17 +0200 Subject: [PATCH 03/99] Add skeleton for config loader --- .../qtgui/taurusgui/config_loader/__init__.py | 45 +++++++++++++++++++ .../qtgui/taurusgui/config_loader/abstract.py | 35 +++++++++++++++ .../qtgui/taurusgui/config_loader/jsonconf.py | 33 ++++++++++++++ .../qtgui/taurusgui/config_loader/pyconf.py | 33 ++++++++++++++ .../qtgui/taurusgui/config_loader/xmlconf.py | 33 ++++++++++++++ 5 files changed, 179 insertions(+) create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py new file mode 100644 index 000000000..dd37fbe65 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -0,0 +1,45 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + +"""""" + +import os + + +__all__ = ["getLoader"] + + +def getLoader(confname): + ext = os.path.splitext(confname)[-1] + + if os.path.isdir(confname) or ext == ".py": + from .pyconf import PyConfigLoader + return PyConfigLoader(confname) + elif ext == ".xml": + from .xmlconf import XmlConfigLoader + return XmlConfigLoader(confname) + elif ext == ".json": + from .jsonconf import JsonConfigLoader + return JsonConfigLoader(confname) + else: + raise NotImplementedError("No config loader implementation for '%s'" % ext) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py new file mode 100644 index 000000000..03de591b8 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -0,0 +1,35 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + +"""""" + +__all__ = ["AbstractConfigLoader"] + + +class AbstractConfigLoader(object): + """ + Abstract class for config loaders + """ + + def __init__(self, confname): + self.confname = confname diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py new file mode 100644 index 000000000..b8884c3f2 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -0,0 +1,33 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + +"""""" + +from .abstract import AbstractConfigLoader + + +__all__ = ["JsonConfigLoader"] + + +class JsonConfigLoader(AbstractConfigLoader): + pass diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py new file mode 100644 index 000000000..878cc0a0a --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -0,0 +1,33 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + +"""""" + +from .abstract import AbstractConfigLoader + + +__all__ = ["PyConfigLoader"] + + +class PyConfigLoader(AbstractConfigLoader): + pass diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py new file mode 100644 index 000000000..5148bc4e4 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -0,0 +1,33 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + +"""""" + +from .abstract import AbstractConfigLoader + + +__all__ = ["XmlConfigLoader"] + + +class XmlConfigLoader(AbstractConfigLoader): + pass From e0e5c9254215d7431b5cc6478e6900f9155e46bb Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 21:19:57 +0200 Subject: [PATCH 04/99] Define interface of abstract class --- .../qtgui/taurusgui/config_loader/abstract.py | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 03de591b8..3fbc07f93 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -23,7 +23,13 @@ """""" -__all__ = ["AbstractConfigLoader"] +__all__ = ["AbstractConfigLoader", "ConfigLoaderError"] + + +class ConfigLoaderError(Exception): + def __init__(self, message): + message = "Exception raised while loading configuration: " + message + super(ConfigLoaderError, self).__init__(message) class AbstractConfigLoader(object): @@ -33,3 +39,22 @@ class AbstractConfigLoader(object): def __init__(self, confname): self.confname = confname + + self.app_name = None + self.org_name = None + self.custom_logo = None + self.org_logo = None + self.single_instance = None + self.manual_uri = None + self.ini_file = None + self.extra_catalog_widgets = None + self.synoptics = None + self.console = None + + self.panels = [] + self.toolbars = [] + self.applets = [] + self.external_apps = [] + + def load(): + pass From 938db8c742d66a8d4695d5fc9cbffbc4608fcb91 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 21:37:27 +0200 Subject: [PATCH 05/99] Move to use abstract class --- .../qtgui/taurusgui/config_loader/abstract.py | 105 ++++++++++++++---- 1 file changed, 84 insertions(+), 21 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 3fbc07f93..5d13dd815 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -22,6 +22,12 @@ ########################################################################### """""" +import abc + +# Python 2/3 compatibility +if not hasattr(abc, "ABC"): + setattr(abc, "ABC", abc.ABCMeta('ABC', (object,), {})) + __all__ = ["AbstractConfigLoader", "ConfigLoaderError"] @@ -32,29 +38,86 @@ def __init__(self, message): super(ConfigLoaderError, self).__init__(message) -class AbstractConfigLoader(object): +class AbstractConfigLoader(abc.ABC): """ Abstract class for config loaders """ def __init__(self, confname): - self.confname = confname - - self.app_name = None - self.org_name = None - self.custom_logo = None - self.org_logo = None - self.single_instance = None - self.manual_uri = None - self.ini_file = None - self.extra_catalog_widgets = None - self.synoptics = None - self.console = None - - self.panels = [] - self.toolbars = [] - self.applets = [] - self.external_apps = [] - - def load(): - pass + self._confname = confname + + @abc.abstractmethod + def load(self): + """ + This method is meant to load actual data from file on disk + """ + + @abc.abstractproperty + def app_name(self): + """Name of the application""" + return None + + @abc.abstractproperty + def org_name(self): + """Name of organization""" + return None + + @abc.abstractproperty + def custom_logo(self): + """Path to application's custom logo file""" + return None + + @abc.abstractproperty + def org_logo(self): + """Path to organization's custom logo file""" + return None + + @abc.abstractproperty + def single_instance(self): + """Whether more than one instance of application can be launched simultaously or not""" + return None + + @abc.abstractproperty + def manual_uri(self): + """URI pointing to application's manual""" + return None + + @abc.abstractproperty + def ini_file(self): + """Path to application's default INI file with settings""" + return None + + @abc.abstractproperty + def extra_catalog_widgets(self): + """Path to application's custom logo file""" + return [] + + @abc.abstractproperty + def synoptics(self): + """Sequence of paths to synoptic files""" + return [] + + @abc.abstractproperty + def console(self): + """Whether to add console widget or not""" + return None + + @abc.abstractproperty + def panels(self): + """List of custom panels with widgets""" + return [] + + @abc.abstractproperty + def toolbars(self): + """List of custom toolbars""" + return [] + + @abc.abstractproperty + def applets(self): + """List of custom applets""" + return [] + + @abc.abstractproperty + def external_apps(self): + """List of external applications""" + return [] From 88d733c617520713761db172b8d83bf2e232a489 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 21:44:13 +0200 Subject: [PATCH 06/99] Implementation of JSON config loader --- .../qtgui/taurusgui/config_loader/jsonconf.py | 91 ++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index b8884c3f2..1df3cac44 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -23,11 +23,98 @@ """""" -from .abstract import AbstractConfigLoader +import json + +from ..utils import PanelDescription, ToolBarDescription, AppletDescription, ExternalApp +from .abstract import AbstractConfigLoader, ConfigLoaderError __all__ = ["JsonConfigLoader"] class JsonConfigLoader(AbstractConfigLoader): - pass + + def __init__(self, confname): + super(JsonConfigLoader, self).__init__(confname) + self._data = {} + + def load(self): + try: + with open(self._confname, "r") as fp: + self._data = json.load(fp) + except IOError as e: + raise ConfigLoaderError("Problem with accessing config file: " + str(e)) + except ValueError as e: + raise ConfigLoaderError("Problem with config file decoding: " + str(e)) + + @property + def app_name(self): + return self._data.get("guiName") + + @property + def org_name(self): + return self._data.get("organization") + + @property + def custom_logo(self): + return self._data.get("customLogo") + + @property + def org_logo(self): + return self._data.get("organizationLogo") + + @property + def single_instance(self): + return self._data.get("singleInstance") + + @property + def manual_uri(self): + return self._data.get("manual") + + @property + def ini_file(self): + return self._data.get("iniFile") + + @property + def extra_catalog_widgets(self): + return self._data.get("extraCatalogWidgets", []) + + @property + def synoptics(self): + return self._data.get("synoptic", []) + + @property + def console(self): + return self._data.get("console") + + @property + def panels(self): + panels = [] + for p in self._data.get("panels", []): + if isinstance(p, dict): + panels.append(PanelDescription(**p)) + return panels + + @property + def toolbars(self): + toolbars = [] + for t in self._data.get("toolbars", []): + if isinstance(t, dict): + toolbars.append(ToolBarDescription(**t)) + return toolbars + + @property + def applets(self): + applets = [] + for a in self._data.get("applets", []): + if isinstance(a, dict): + applets.append(AppletDescription(**a)) + return applets + + @property + def external_apps(self): + external_apps = [] + for e in self._data.get("externalApps", []): + if isinstance(e, dict): + external_apps.append(PanelDescription(**e)) + return external_apps From 512a931e0eea4b49a013c2d0e7c85f145f89c7ec Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 22:13:03 +0200 Subject: [PATCH 07/99] Delegate non-path strings to PyConfigLoader --- lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index dd37fbe65..76662aeac 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -32,7 +32,7 @@ def getLoader(confname): ext = os.path.splitext(confname)[-1] - if os.path.isdir(confname) or ext == ".py": + if os.path.isdir(confname) or ext == ".py" or "/" not in confname: from .pyconf import PyConfigLoader return PyConfigLoader(confname) elif ext == ".xml": From 9ab3ef470c20e4f3e8ae26df140a177abc3cf374 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 22:13:30 +0200 Subject: [PATCH 08/99] Add implementation fo Python config loader --- .../qtgui/taurusgui/config_loader/pyconf.py | 130 +++++++++++++++++- 1 file changed, 128 insertions(+), 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 878cc0a0a..7a70a5a49 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -23,11 +23,137 @@ """""" -from .abstract import AbstractConfigLoader +import os +import sys +import types +import inspect + +from ..utils import PanelDescription, AppletDescription, ToolBarDescription, ExternalApp +from .abstract import AbstractConfigLoader, ConfigLoaderError __all__ = ["PyConfigLoader"] class PyConfigLoader(AbstractConfigLoader): - pass + + def __init__(self, confname): + super(PyConfigLoader, self).__init__(confname) + self._mod = types.ModuleType('__dummy_conf_module_%s__' %s confname) # dummy module + + def _importConfiguration(self): + '''returns the module corresponding to `confname` or to + `tgconf_`. Note: the `conf` subdirectory of the directory in + which taurusgui.py file is installed is temporally prepended to sys.path + ''' + confsubdir = os.path.join(os.path.abspath(os.path.dirname( + __file__)), 'conf') # the path to a conf subdirectory of the place where taurusgui.py is + oldpath = sys.path + try: + # add the conf subdirectory dir to the pythonpath + sys.path = [confsubdir] + sys.path + mod = __import__(self._confname) + except ImportError: + altconfname = "tgconf_%s" % self._confname + try: + mod = __import__(altconfname) + except ImportError: + msg = 'cannot import %s or %s' % (self._confname, altconfname) + raise ConfigLoaderError(msg) + finally: + sys.path = oldpath # restore the previous sys.path + return mod + + def load(self): + '''Reads a configuration file + + :param confname: (str or None) the name of module located in the + PYTHONPATH or in the conf subdirectory of the directory + in which taurusgui.py file is installed. + This method will try to import . + If that fails, it will try to import + `tgconf_`. + Alternatively, `confname` can be the path to the + configuration module (not necessarily in the + PYTHONPATH). + `confname` can also be None, in which case a dummy + empty module will be used. + ''' + + # import the python config file + if os.path.exists(self._confname): # if confname is a dir or file name + import imp + path, name = os.path.split(self._confname) + name, _ = os.path.splitext(name) + try: + f, filename, data = imp.find_module(name, [path]) + conf = imp.load_module(name, f, filename, data) + confname = name + except ImportError: + self._mod = self._importConfiguration() + else: # if confname is not a dir name, we assume it is a module name in the python path + self._mod = self._importConfiguration() + + @property + def app_name(self): + return getattr(self._mod, 'GUI_NAME') + + @property + def org_name(self): + return getattr(self._mod, 'ORGANIZATION') + + @property + def custom_logo(self): + return getattr(self._mod, 'CUSTOM_LOGO') + + @property + def org_logo(self): + return getattr(self._mod, 'ORGANIZATION_LOGO') + + @property + def single_instance(self): + return getattr(self._mod, 'SINGLE_INSTANCE') + + @property + def manual_uri(self): + return getattr(self._mod, 'MANUAL_URI') + + @property + def ini_file(self): + return getattr(self._mod, 'INIFILE') + + @property + def extra_catalog_widgets(self): + return getattr(self._mod, 'EXTRA_CATALOG_WIDGETS', []) + + @property + def synoptics(self): + return getattr(self._mod, 'SYNOPTIC', []) + + @property + def console(self): + return getattr(self._mod, 'CONSOLE', []) + + @property + def panels(self): + panels = [obj for name, obj in inspect.getmembers(self._mod) + if isinstance(obj, PanelDescription)] + return panels + + @property + def toolbars(self): + toolbars = [obj for name, obj in inspect.getmembers(self._mod) + if isinstance(obj, ToolBarDescription)] + return toolbars + + @property + def applets(self): + applets = [obj for name, obj in inspect.getmembers(self._mod) + if isinstance(obj, AppletDescription)] + return applets + + @property + def external_apps(self): + external_apps = [obj for name, obj in inspect.getmembers(self._mod) + if isinstance(obj, ExternalApp)] + return external_apps From 00a0c43d5fd68d6ec35eb9c91d06a7ebee3aa5d4 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 22:36:27 +0200 Subject: [PATCH 09/99] Add implementation of config loader from XML file --- .../qtgui/taurusgui/config_loader/xmlconf.py | 114 +++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index 5148bc4e4..9c63ec369 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -23,11 +23,121 @@ """""" -from .abstract import AbstractConfigLoader +from lxml import etree + +from ..utils import PanelDescription, ToolBarDescription, AppletDescription, ExternalApp +from .abstract import AbstractConfigLoader, ConfigLoaderError __all__ = ["XmlConfigLoader"] class XmlConfigLoader(AbstractConfigLoader): - pass + def __init__(self, confname): + super(XmlConfigLoader, self).__init__(confname) + self._root = etree.fromstring('') + + def _get(self, nodename, default=None): + """ + Helper method for getting data from XML + """ + name = self._root.find(nodename) + if name is None or name.text is None: + return default + else: + return name.text + + def _get_objects(self, klass): + """ + Helper method to get list of objects of given Python class + """ + objs = [] + obj = self._root.find(klass.__name__) + if obj is not None: + for child in obj: + if child.tag == klass.__name__: + child_str = etree.tostring(child, encoding='unicode') + o = klass.fromXml(child_str) + if o is not None: + objs.append(o) + return objs + + def load(self): + """ + Get the xml root node from the xml configuration file + """ + try: + with open(self._confname, 'r') as xmlFile: + self._root = etree.fromstring(xmlFile.read()) + except IOError as e: + raise ConfigLoaderError("Problem with accessing config file: " + str(e)) + except Exception as e: + msg = 'Error reading the XML file: "%s"' % self._confname + raise ConfigLoaderError(msg) + + @property + def app_name(self): + return self._get("GUI_NAME") + + @property + def org_name(self): + return self._get("ORGANIZATION") + + @property + def custom_logo(self): + return self._get("CUSTOM_LOGO") + + @property + def org_logo(self): + return self._get("ORGANIZATION_LOGO") + + @property + def single_instance(self): + return self._get("SINGLE_INSTANCE") + + @property + def manual_uri(self): + return self._get("MANUAL_URI") + + @property + def ini_file(self): + return self._get("INIFILE") + + @property + def extra_catalog_widgets(self): + """ + Not implemented for now + """ + return [] + + @property + def synoptics(self): + synoptic = [] + node = self._root.find("SYNOPTIC") + if (node is not None) and (node.text is not None): + for child in node: + s = child.get("str") + # we do not append empty strings + if s: + synoptic.append(s) + return synoptic + + @property + def console(self): + return self._get("CONSOLE") + + @property + def panels(self): + return self._get_objects(PanelDescription) + + @property + def toolbars(self): + return self._get_objects(ToolBarDescription) + + @property + def applets(self): + return self._get_objects(AppletDescription) + + @property + def external_apps(self): + return self._get_objects(ExternalApp) From 9e021a5723069204f1999a018c27df08b708b50a Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 22:58:40 +0200 Subject: [PATCH 10/99] Specify proper section in XML --- lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index 9c63ec369..80b6fb986 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -52,7 +52,7 @@ def _get_objects(self, klass): Helper method to get list of objects of given Python class """ objs = [] - obj = self._root.find(klass.__name__) + obj = self._root.find(klass.__name__ + "s") # 's' is for plural form if obj is not None: for child in obj: if child.tag == klass.__name__: @@ -65,7 +65,7 @@ def _get_objects(self, klass): def load(self): """ Get the xml root node from the xml configuration file - """ + """ try: with open(self._confname, 'r') as xmlFile: self._root = etree.fromstring(xmlFile.read()) From 684ba73737b63f19c9c334d09f488bcbf8d3908d Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 22:59:36 +0200 Subject: [PATCH 11/99] Get in line with what XML file loads --- .../qtgui/taurusgui/config_loader/jsonconf.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 1df3cac44..4d25fee66 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -49,48 +49,48 @@ def load(self): @property def app_name(self): - return self._data.get("guiName") + return self._data.get("GUI_NAME") @property def org_name(self): - return self._data.get("organization") + return self._data.get("ORGANIZATION") @property def custom_logo(self): - return self._data.get("customLogo") + return self._data.get("CUSTOM_LOGO") @property def org_logo(self): - return self._data.get("organizationLogo") + return self._data.get("ORGANIZATION_LOGO") @property def single_instance(self): - return self._data.get("singleInstance") + return self._data.get("SINGE_INSTANCE") @property def manual_uri(self): - return self._data.get("manual") + return self._data.get("MANUAL_URI") @property def ini_file(self): - return self._data.get("iniFile") + return self._data.get("INIFILE") @property def extra_catalog_widgets(self): - return self._data.get("extraCatalogWidgets", []) + return self._data.get("EXTRA_CATALOG_WIDGETS", []) @property def synoptics(self): - return self._data.get("synoptic", []) + return self._data.get("SYNOPTIC", []) @property def console(self): - return self._data.get("console") + return self._data.get("CONSOLE") @property def panels(self): panels = [] - for p in self._data.get("panels", []): + for p in self._data.get("PanelDescriptions", []): if isinstance(p, dict): panels.append(PanelDescription(**p)) return panels @@ -98,7 +98,7 @@ def panels(self): @property def toolbars(self): toolbars = [] - for t in self._data.get("toolbars", []): + for t in self._data.get("ToolBarDescriptions", []): if isinstance(t, dict): toolbars.append(ToolBarDescription(**t)) return toolbars @@ -106,7 +106,7 @@ def toolbars(self): @property def applets(self): applets = [] - for a in self._data.get("applets", []): + for a in self._data.get("AppletDescriptions", []): if isinstance(a, dict): applets.append(AppletDescription(**a)) return applets @@ -114,7 +114,7 @@ def applets(self): @property def external_apps(self): external_apps = [] - for e in self._data.get("externalApps", []): + for e in self._data.get("ExternalApps", []): if isinstance(e, dict): external_apps.append(PanelDescription(**e)) return external_apps From 91184981cc12a84eeaade4ac21fc7436a0ae4e00 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 23:02:21 +0200 Subject: [PATCH 12/99] Use helper function --- .../qtgui/taurusgui/config_loader/jsonconf.py | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 4d25fee66..4101c9822 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -38,6 +38,16 @@ def __init__(self, confname): super(JsonConfigLoader, self).__init__(confname) self._data = {} + def _get_objects(self, klass): + """ + Helper function to get list of Python objects from dictionary + """ + objs = [] + for o in self._data.get(klass.__name__ + "s", []): # 's' is for plural form + if isinstance(o, dict): + objs.append(klass(**o)) + return objs + def load(self): try: with open(self._confname, "r") as fp: @@ -89,32 +99,16 @@ def console(self): @property def panels(self): - panels = [] - for p in self._data.get("PanelDescriptions", []): - if isinstance(p, dict): - panels.append(PanelDescription(**p)) - return panels + return self._get_objects(PanelDescription) @property def toolbars(self): - toolbars = [] - for t in self._data.get("ToolBarDescriptions", []): - if isinstance(t, dict): - toolbars.append(ToolBarDescription(**t)) - return toolbars + return self._get_objects(ToolBarDescription) @property def applets(self): - applets = [] - for a in self._data.get("AppletDescriptions", []): - if isinstance(a, dict): - applets.append(AppletDescription(**a)) - return applets + return self._get_objects(AppletDescription) @property def external_apps(self): - external_apps = [] - for e in self._data.get("ExternalApps", []): - if isinstance(e, dict): - external_apps.append(PanelDescription(**e)) - return external_apps + return self._get_objects(ExternalApp) From 445285e8cfa5ac2e17556f76c56e067d15eed697 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 23:09:08 +0200 Subject: [PATCH 13/99] Use helper function for Python config loader also --- .../qtgui/taurusgui/config_loader/pyconf.py | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 7a70a5a49..a1cd8a082 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -41,6 +41,10 @@ def __init__(self, confname): super(PyConfigLoader, self).__init__(confname) self._mod = types.ModuleType('__dummy_conf_module_%s__' %s confname) # dummy module + def _get_objects(self, klass): + objs = [obj for name, obj in inspect.getmembers(self._mod) + if isinstance(obj, klass)] + def _importConfiguration(self): '''returns the module corresponding to `confname` or to `tgconf_`. Note: the `conf` subdirectory of the directory in @@ -136,24 +140,16 @@ def console(self): @property def panels(self): - panels = [obj for name, obj in inspect.getmembers(self._mod) - if isinstance(obj, PanelDescription)] - return panels + return self._get_objects(PanelDescription) @property def toolbars(self): - toolbars = [obj for name, obj in inspect.getmembers(self._mod) - if isinstance(obj, ToolBarDescription)] - return toolbars + return self._get_objects(ToolBarDescription) @property def applets(self): - applets = [obj for name, obj in inspect.getmembers(self._mod) - if isinstance(obj, AppletDescription)] - return applets + return self._get_objects(AppletDescription) @property def external_apps(self): - external_apps = [obj for name, obj in inspect.getmembers(self._mod) - if isinstance(obj, ExternalApp)] - return external_apps + return self._get_objects(ExternalApp) From 00e4139b873845be2081589f29306175224dd82d Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 23:20:33 +0200 Subject: [PATCH 14/99] Use config loader for most of configuration --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 252 ++++----------------- 1 file changed, 48 insertions(+), 204 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 296a8af98..5f2d89ceb 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -52,6 +52,7 @@ from taurus.qt.qtgui.util.ui import UILoadable from taurus.qt.qtgui.taurusgui.utils import ExternalAppAction from taurus.core.util.log import deprecation_decorator +from taurus.qt.qtgui.taurusgui.config_loader import getLoader __all__ = ["DockWidgetPanel", "TaurusGui"] @@ -976,77 +977,18 @@ def createInstrumentsFromPool(self, macroservername): if len(instrument.model) > 0] return ret - def __getVarFromXML(self, root, nodename, default=None): - name = root.find(nodename) - if name is None or name.text is None: + def getConfigValue(self, conf, field, default=None): + value = getattr(conf, field) + if value is None: return default else: - return name.text - - def _importConfiguration(self, confname): - '''returns the module corresponding to `confname` or to - `tgconf_`. Note: the `conf` subdirectory of the directory in - which taurusgui.py file is installed is temporally prepended to sys.path - ''' - confsubdir = os.path.join(os.path.abspath(os.path.dirname( - __file__)), 'conf') # the path to a conf subdirectory of the place where taurusgui.py is - oldpath = sys.path - try: - # add the conf subdirectory dir to the pythonpath - sys.path = [confsubdir] + sys.path - conf = __import__(confname) - except ImportError: - altconfname = "tgconf_%s" % confname - try: - conf = __import__(altconfname) - except ImportError: - msg = 'cannot import %s or %s' % (confname, altconfname) - self.error(msg) - Qt.QMessageBox.critical( - self, 'Initialization error', msg, Qt.QMessageBox.Abort) - sys.exit() - finally: - sys.path = oldpath # restore the previous sys.path - return conf + return value def loadConfiguration(self, confname): '''Reads a configuration file - - :param confname: (str or None) the name of module located in the - PYTHONPATH or in the conf subdirectory of the directory - in which taurusgui.py file is installed. - This method will try to import . - If that fails, it will try to import - `tgconf_`. - Alternatively, `confname` can be the path to the - configuration module (not necessarily in the - PYTHONPATH). - `confname` can also be None, in which case a dummy - empty module will be used. ''' - - # import the python config file try: - if confname is None: - import types - conf = types.ModuleType( - '__dummy_conf_module__') # dummy module - confname = str(Qt.qApp.applicationName()) - self._confDirectory = '' - elif os.path.exists(confname): # if confname is a dir or file name - import imp - path, name = os.path.split(confname) - name, _ = os.path.splitext(name) - try: - f, filename, data = imp.find_module(name, [path]) - conf = imp.load_module(name, f, filename, data) - confname = name - except ImportError: - conf = self._importConfiguration(confname) - self._confDirectory = os.path.dirname(conf.__file__) - else: # if confname is not a dir name, we assume it is a module name in the python path - conf = self._importConfiguration(confname) - self._confDirectory = os.path.dirname(conf.__file__) + conf = getLoader(confname).load() except Exception: import traceback msg = 'Error loading configuration: %s' % traceback.format_exc() # repr(e) @@ -1055,75 +997,39 @@ def loadConfiguration(self, confname): self, 'Initialization error', msg, Qt.QMessageBox.Abort) sys.exit() - xmlroot = self._loadXmlConfig(conf) - - self._loadAppName(conf, confname, xmlroot) - self._loadOrgName(conf, xmlroot) - self._loadCustomLogo(conf, xmlroot) + xmlroot = None + self._loadAppName(conf, confname) + self._loadOrgName(conf) + self._loadCustomLogo(conf) Qt.QApplication.instance().basicConfig() - self._loadOrgLogo(conf, xmlroot) + self._loadOrgLogo(conf) - self._loadSingleInstance(conf, xmlroot) + self._loadSingleInstance(conf) - self._loadExtraCatalogWidgets(conf, xmlroot) - self._loadManualUri(conf, xmlroot) + self._loadExtraCatalogWidgets(conf) + self._loadManualUri(conf) POOLINSTRUMENTS = self._loadSardanaOptions(conf, xmlroot) - self._loadSynoptic(conf, xmlroot) + self._loadSynoptic(conf) # TODO: remove deprecated _loadConsole - self._loadConsole(conf, xmlroot) - - self._loadCustomPanels(conf, xmlroot, POOLINSTRUMENTS) - self._loadCustomToolBars(conf, xmlroot) - self._loadCustomApplets(conf, xmlroot) - self._loadExternalApps(conf, xmlroot) - self._loadIniFile(conf, xmlroot) - - def _loadXmlConfig(self, conf): - """ - Get the xml root node from the xml configuration file - """ + self._loadConsole(conf) - xml_config = getattr(conf, 'XML_CONFIG', None) - if xml_config is None: - self._xmlConfigFileName = None - else: - self._xmlConfigFileName = os.path.join( - self._confDirectory, xml_config) - # default fallback (in case of I/O or parse errors) - xmlroot = etree.fromstring('') - if xml_config is not None: - try: - # If a relative name was given, the conf directory will be used - # as base path - xmlfname = os.path.join(self._confDirectory, xml_config) - xmlFile = open(xmlfname, 'r') - xmlstring = xmlFile.read() - xmlFile.close() - xmlroot = etree.fromstring(xmlstring) - except Exception as e: - msg = 'Error reading the XML file: "%s"' % xmlfname - self.error(msg) - self.traceback(level=taurus.Info) - result = Qt.QMessageBox.critical(self, 'Initialization error', '%s\nReason:"%s"' % ( - msg, repr(e)), Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore) - if result == Qt.QMessageBox.Abort: - sys.exit() - return xmlroot + self._loadCustomPanels(conf, POOLINSTRUMENTS) + self._loadCustomToolBars(conf) + self._loadCustomApplets(conf) + self._loadExternalApps(conf) + self._loadIniFile(conf) - def _loadAppName(self, conf, confname, xmlroot): - appname = getattr(conf, 'GUI_NAME', self.__getVarFromXML( - xmlroot, "GUI_NAME", confname)) + def _loadAppName(self, conf, confname): + appname = self.getConfigValue(conf, "app_name") Qt.qApp.setApplicationName(appname) self.setWindowTitle(appname) - def _loadOrgName(self, conf, xmlroot): - orgname = getattr(conf, 'ORGANIZATION', self.__getVarFromXML( - xmlroot, "ORGANIZATION", str(Qt.qApp.organizationName()) or 'Taurus')) + def _loadOrgName(self, conf): + orgname = self.getConfigValue(conf, "org_name", str(Qt.qApp.organizationName()) or 'Taurus') Qt.qApp.setOrganizationName(orgname) - def _loadCustomLogo(self, conf, xmlroot): - custom_logo = getattr(conf, 'CUSTOM_LOGO', getattr( - conf, 'LOGO', self.__getVarFromXML(xmlroot, "CUSTOM_LOGO", 'logos:taurus.png'))) + def _loadCustomLogo(self, conf): + custom_logo = self.getConfigValue(conf, "custom_logo", 'logos:taurus.png') if Qt.QFile.exists(custom_logo): custom_icon = Qt.QIcon(custom_logo) else: @@ -1137,11 +1043,7 @@ def _loadOrgLogo(self, conf, xmlroot): logo = getattr(tauruscustomsettings, "ORGANIZATION_LOGO", "logos:taurus.png") - org_logo = getattr(conf, - "ORGANIZATION_LOGO", - self.__getVarFromXML(xmlroot, - "ORGANIZATION_LOGO", - logo)) + org_logo = self.getConfigValue(conf, "org_logo", logo) if Qt.QFile.exists(org_logo): org_icon = Qt.QIcon(org_logo) else: @@ -1150,12 +1052,12 @@ def _loadOrgLogo(self, conf, xmlroot): if self.APPLETS_TOOLBAR_ENABLED: self.jorgsBar.addAction(org_icon, Qt.qApp.organizationName()) - def _loadSingleInstance(self, conf, xmlroot): + def _loadSingleInstance(self, conf): """ if required, enforce that only one instance of this GUI can be run """ - single_inst = getattr(conf, 'SINGLE_INSTANCE', (self.__getVarFromXML( - xmlroot, "SINGLE_INSTANCE", 'True').lower() == 'true')) + single_inst = self.getConfigValue(conf, "single_instance", True) + if single_inst: if not self.checkSingleInstance(): msg = 'Only one instance of %s is allowed to run the same time' % ( @@ -1165,12 +1067,12 @@ def _loadSingleInstance(self, conf, xmlroot): self, 'Multiple copies', msg, Qt.QMessageBox.Abort) sys.exit(1) - def _loadExtraCatalogWidgets(self, conf, xmlroot): + def _loadExtraCatalogWidgets(self, conf): """ get custom widget catalog entries """ # @todo: support also loading from xml - extra_catalog_widgets = getattr(conf, 'EXTRA_CATALOG_WIDGETS', []) + extra_catalog_widgets = self.getConfigValue(conf, "extra_catalog_widgets", []) self._extraCatalogWidgets = [] for class_name, pix_map_name in extra_catalog_widgets: # If a relative file name is given, the conf directory will be used @@ -1183,9 +1085,7 @@ def _loadManualUri(self, conf, xmlroot): """ manual panel """ - manual_uri = getattr(conf, 'MANUAL_URI', - self.__getVarFromXML(xmlroot, "MANUAL_URI", - taurus.Release.url)) + manual_uri = self.getConfigValue(conf, "manual_uri", taurus.Release.url) self.setHelpManualURI(manual_uri) if self.HELP_MENU_ENABLED: @@ -1251,22 +1151,13 @@ def _loadInstrumentsFromPool(self, conf, xmlroot, macro_server_name): return pool_instruments ### SARDANA MACRO STUFF OFF - def _loadSynoptic(self, conf, xmlroot): + def _loadSynoptic(self, conf): # Synoptics - synoptic = getattr(conf, 'SYNOPTIC', None) + synoptic = self.getConfigValue(conf, "synoptic", []) if isinstance(synoptic, string_types): # old config file style self.warning( 'Deprecated usage of synoptic keyword (now it expects a list of paths). Please update your configuration file to: "synoptic=[\'%s\']".' % synoptic) synoptic = [synoptic] - if synoptic is None: # we look in the xml config file if not present in the python config - synoptic = [] - node = xmlroot.find("SYNOPTIC") - if (node is not None) and (node.text is not None): - for child in node: - s = child.get("str") - # we do not append empty strings - if s is not None and len(s): - synoptic.append(s) for s in synoptic: self.createMainSynoptic(s) @@ -1276,27 +1167,17 @@ def _loadConsole(self, conf, xmlroot): Panel with a `silx.gui.console.IPythonWidget` """ # TODO: remove this method when making deprecation efective - console = getattr(conf, 'CONSOLE', self.__getVarFromXML( - xmlroot, "CONSOLE", [])) + console = self.getConfigValue(conf, "console", []) if console: self.createConsole([]) - def _loadCustomPanels(self, conf, xmlroot, poolinstruments=None): + def _loadCustomPanels(self, conf, poolinstruments=None): """ get custom panel descriptions from the python config file, xml config and create panels based on the panel descriptions """ - custom_panels = [obj for name, obj in inspect.getmembers( - conf) if isinstance(obj, PanelDescription)] - - panel_descriptions = xmlroot.find("PanelDescriptions") - if panel_descriptions is not None: - for child in panel_descriptions: - if child.tag == "PanelDescription": - child_str = etree.tostring(child, encoding='unicode') - pd = PanelDescription.fromXml(child_str) - if pd is not None: - custom_panels.append(pd) + + custom_panels = conf.panels for p in custom_panels + poolinstruments: try: @@ -1366,24 +1247,12 @@ def _loadCustomPanels(self, conf, xmlroot, poolinstruments=None): if result == Qt.QMessageBox.Abort: sys.exit() - def _loadCustomToolBars(self, conf, xmlroot): + def _loadCustomToolBars(self, conf): """ get custom toolbars descriptions from the python config file, xml config and create toolbars based on the descriptions """ - custom_toolbars = [obj for name, obj in inspect.getmembers( - conf) if isinstance(obj, ToolBarDescription)] - - tool_bar_descriptions = xmlroot.find("ToolBarDescriptions") - if tool_bar_descriptions is not None: - for child in tool_bar_descriptions: - if child.tag == "ToolBarDescription": - child_str = etree.tostring(child, encoding='unicode') - d = ToolBarDescription.fromXml(child_str) - if d is not None: - custom_toolbars.append(d) - - for d in custom_toolbars: + for d in conf.toolbars: try: try: self.splashScreen().showMessage("Creating Toolbar %s" % d.name) @@ -1411,7 +1280,7 @@ def _loadCustomToolBars(self, conf, xmlroot): if result == Qt.QMessageBox.Abort: sys.exit() - def _loadCustomApplets(self, conf, xmlroot): + def _loadCustomApplets(self, conf): """ get custom applet descriptions from the python config file, xml config and create applet based on the descriptions @@ -1424,19 +1293,7 @@ def _loadCustomApplets(self, conf, xmlroot): custom_applets.append(AppletDescription( "monitor", classname="TaurusMonitorTiny", model=MONITOR)) - custom_applets += [obj for name, obj in inspect.getmembers( - conf) if isinstance(obj, AppletDescription)] - - applet_descriptions = xmlroot.find("AppletDescriptions") - if applet_descriptions is not None: - for child in applet_descriptions: - if child.tag == "AppletDescription": - child_str = etree.tostring(child, encoding='unicode') - d = AppletDescription.fromXml(child_str) - if d is not None: - custom_applets.append(d) - - for d in custom_applets: + for d in conf.applets: try: try: self.splashScreen().showMessage("Creating applet %s" % d.name) @@ -1460,34 +1317,21 @@ def _loadCustomApplets(self, conf, xmlroot): if result == Qt.QMessageBox.Abort: sys.exit() - def _loadExternalApps(self, conf, xmlroot): + def _loadExternalApps(self, conf): """ add external applications from both the python and the xml config files """ - external_apps = [obj for name, obj in inspect.getmembers( - conf) if isinstance(obj, ExternalApp)] - - ext_apps_node = xmlroot.find("ExternalApps") - if ext_apps_node is not None: - for child in ext_apps_node: - if child.tag == "ExternalApp": - child_str = etree.tostring(child, encoding='unicode') - ea = ExternalApp.fromXml(child_str) - if ea is not None: - external_apps.append(ea) - - for a in external_apps: + for a in conf.external_apps: self._external_app_names.append(str(a.getAction().text())) self.addExternalAppLauncher(a.getAction()) - def _loadIniFile(self, conf, xmlroot): + def _loadIniFile(self, conf): """ get the "factory settings" filename. By default, it is called "default.ini" and resides in the configuration dir """ + ini_file = self.getConfigValue(conf, "ini_file", "default.ini") - ini_file = getattr(conf, 'INIFILE', self.__getVarFromXML( - xmlroot, "INIFILE", "default.ini")) # if a relative name is given, the conf dir is used as the root path ini_file_name = os.path.join(self._confDirectory, ini_file) From 81bf0576ffd362663e437f3d8a3ca7672f01c2d5 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 23:25:32 +0200 Subject: [PATCH 15/99] Allow setting deprecated Monitor widget --- lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py | 6 ++++++ lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py | 4 ++++ lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py | 4 ++++ lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py | 4 ++++ lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 7 +++---- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 5d13dd815..520111b08 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -121,3 +121,9 @@ def applets(self): def external_apps(self): """List of external applications""" return [] + + # deprecated + @abc.abstractproperty + def monitor(self): + """Model of Monitor widget""" + return None diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 4101c9822..4e1dd377b 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -97,6 +97,10 @@ def synoptics(self): def console(self): return self._data.get("CONSOLE") + @property + def monitor(self): + return self._data.get("MONITOR") + @property def panels(self): return self._get_objects(PanelDescription) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index a1cd8a082..937214acf 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -138,6 +138,10 @@ def synoptics(self): def console(self): return getattr(self._mod, 'CONSOLE', []) + @property + def monitor(self): + return getattr(self._mod, 'MONITOR') + @property def panels(self): return self._get_objects(PanelDescription) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index 80b6fb986..f45b3c311 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -126,6 +126,10 @@ def synoptics(self): def console(self): return self._get("CONSOLE") + @property + def monitor(self): + return self._get("MONITOR") + @property def panels(self): return self._get_objects(PanelDescription) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 5f2d89ceb..9c961e701 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -1285,15 +1285,14 @@ def _loadCustomApplets(self, conf): get custom applet descriptions from the python config file, xml config and create applet based on the descriptions """ - custom_applets = [] + custom_applets = conf.applets[:] # for backwards compatibility - MONITOR = getattr( - conf, "MONITOR", self.__getVarFromXML(xmlroot, "MONITOR", [])) + MONITOR = self.getConfigValue(conf, "monitor", []) if MONITOR: custom_applets.append(AppletDescription( "monitor", classname="TaurusMonitorTiny", model=MONITOR)) - for d in conf.applets: + for d in custom_applets: try: try: self.splashScreen().showMessage("Creating applet %s" % d.name) From cce2f9a5ad12b66b9bb5431143fb368106718be1 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 23:38:19 +0200 Subject: [PATCH 16/99] Add filed with absolute path to config directory --- lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py | 7 +++++++ lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py | 5 +++++ lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py | 4 ++++ lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py | 6 ++++++ lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 4 +++- 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 520111b08..0093ee42f 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -52,6 +52,13 @@ def load(self): This method is meant to load actual data from file on disk """ + @abc.abstractproperty + def conf_dir(self): + """ + Absolute path to directory in which config file is placed + """ + return None + @abc.abstractproperty def app_name(self): """Name of the application""" diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 4e1dd377b..0d34b09d5 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -24,6 +24,7 @@ """""" import json +import os from ..utils import PanelDescription, ToolBarDescription, AppletDescription, ExternalApp from .abstract import AbstractConfigLoader, ConfigLoaderError @@ -57,6 +58,10 @@ def load(self): except ValueError as e: raise ConfigLoaderError("Problem with config file decoding: " + str(e)) + @property + def conf_dir(self): + return os.path.abspath(os.path.dirname(self._confname)) + @property def app_name(self): return self._data.get("GUI_NAME") diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 937214acf..5879b4189 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -98,6 +98,10 @@ def load(self): else: # if confname is not a dir name, we assume it is a module name in the python path self._mod = self._importConfiguration() + @property + def conf_dir(self): + return os.path.abspath(os.path.dirname(self._mod.__file__)) + @property def app_name(self): return getattr(self._mod, 'GUI_NAME') diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index f45b3c311..f8f29b314 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -23,6 +23,8 @@ """""" +import os + from lxml import etree from ..utils import PanelDescription, ToolBarDescription, AppletDescription, ExternalApp @@ -75,6 +77,10 @@ def load(self): msg = 'Error reading the XML file: "%s"' % self._confname raise ConfigLoaderError(msg) + @property + def conf_dir(self): + return os.path.abspath(os.path.dirname(self._confname)) + @property def app_name(self): return self._get("GUI_NAME") diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 9c961e701..b4a2bba4c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -988,7 +988,9 @@ def loadConfiguration(self, confname): '''Reads a configuration file ''' try: - conf = getLoader(confname).load() + conf = getLoader(confname) + conf.load() + self._confDirectory = conf.conf_dir except Exception: import traceback msg = 'Error loading configuration: %s' % traceback.format_exc() # repr(e) From 1fb53f8b40ca521e1fcbeba10365806ffa7bf50d Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 23:54:18 +0200 Subject: [PATCH 17/99] Load Sardana stuff from config files --- .../qtgui/taurusgui/config_loader/abstract.py | 27 +++++++++++++ .../qtgui/taurusgui/config_loader/jsonconf.py | 20 ++++++++++ .../qtgui/taurusgui/config_loader/pyconf.py | 20 ++++++++++ .../qtgui/taurusgui/config_loader/xmlconf.py | 20 ++++++++++ lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 40 ++++++++----------- 5 files changed, 104 insertions(+), 23 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 0093ee42f..5688fe66a 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -134,3 +134,30 @@ def external_apps(self): def monitor(self): """Model of Monitor widget""" return None + + # SARDANA STUFF ON + @abc.abstractproperty + def macroserver_name(self): + """Name of MacroServer""" + return None + + @abc.abstractproperty + def macro_panels(self): + """Whether to enable Sardana macro panels or not""" + return None + + @abc.abstractproperty + def door_name(self): + """Name of MacroServer's Door""" + return None + + @abc.abstractproperty + def macroeditors_path(self): + """Path to macro editors (?)""" + return None + + @abc.abstractproperty + def instruments_from_pool(self): + """Whether to load instruments from Pool as panels or not""" + return None + # SARDANA STUFF OFF diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 0d34b09d5..671d09932 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -121,3 +121,23 @@ def applets(self): @property def external_apps(self): return self._get_objects(ExternalApp) + + @property + def macroserver_name(self): + return self._data.get("MACROSERVER_NAME") + + @property + def macro_panels(self): + return self._data.get("MACRO_PANELS") + + @property + def door_name(self): + return self._data.get("DOOR_NAME") + + @property + def macroeditors_path(self): + return self._data.get("MACROEDITORS_PATH") + + @property + def instruments_from_pool(self): + return self._data.get("INSTRUMENTS_FROM_POOL") diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 5879b4189..5453bdf16 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -161,3 +161,23 @@ def applets(self): @property def external_apps(self): return self._get_objects(ExternalApp) + + @property + def macroserver_name(self): + return getattr(self._mod, "MACROSERVER_NAME") + + @property + def macro_panels(self): + return getattr(self._mod, "MACRO_PANELS") + + @property + def door_name(self): + return getattr(self._mod, "DOOR_NAME") + + @property + def macroeditors_path(self): + return getattr(self._mod, "MACROEDITORS_PATH") + + @property + def instruments_from_pool(self): + return getattr(self._mod, "INSTRUMENTS_FROM_POOL") diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index f8f29b314..ea260fe99 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -151,3 +151,23 @@ def applets(self): @property def external_apps(self): return self._get_objects(ExternalApp) + + @property + def macroserver_name(self): + return self._get("MACROSERVER_NAME") + + @property + def macro_panels(self): + return self._get("MACRO_PANELS") + + @property + def door_name(self): + return self._get("DOOR_NAME") + + @property + def macroeditors_path(self): + return self._get("MACROEDITORS_PATH") + + @property + def instruments_from_pool(self): + return self._get("INSTRUMENTS_FROM_POOL") diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index b4a2bba4c..f58b96cea 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -1010,7 +1010,7 @@ def loadConfiguration(self, confname): self._loadExtraCatalogWidgets(conf) self._loadManualUri(conf) - POOLINSTRUMENTS = self._loadSardanaOptions(conf, xmlroot) + POOLINSTRUMENTS = self._loadSardanaOptions(conf) self._loadSynoptic(conf) # TODO: remove deprecated _loadConsole self._loadConsole(conf) @@ -1095,52 +1095,46 @@ def _loadManualUri(self, conf, xmlroot): icon=Qt.QIcon.fromTheme('help-browser')) ### SARDANA MACRO STUFF ON - def _loadSardanaOptions(self, conf, xmlroot): + def _loadSardanaOptions(self, conf): """configure macro infrastructure""" - ms = self._loadMacroServerName(conf, xmlroot) - mp = self._loadMacroPanels(conf, xmlroot) + ms = self._loadMacroServerName(conf) + mp = self._loadMacroPanels(conf) # macro infrastructure will only be created if MACROSERVER_NAME is set if ms is not None and mp is True: from sardana.taurus.qt.qtgui.macrolistener import MacroBroker self.__macroBroker = MacroBroker(self) - self._loadDoorName(conf, xmlroot) - self._loadMacroEditorsPath(conf, xmlroot) - pool_instruments = self._loadInstrumentsFromPool(conf, xmlroot, ms) + self._loadDoorName(conf) + self._loadMacroEditorsPath(conf) + pool_instruments = self._loadInstrumentsFromPool(conf, ms) return pool_instruments - def _loadMacroServerName(self, conf, xmlroot): - macro_server_name = getattr(conf, "MACROSERVER_NAME", self.__getVarFromXML( - xmlroot, "MACROSERVER_NAME", None)) + def _loadMacroServerName(self, conf): + macro_server_name = self.getConfigValue(conf, "macroserver_name") if macro_server_name: self.macroserverNameChanged.emit(macro_server_name) return macro_server_name - def _loadMacroPanels(self, conf, xmlroot): - macro_panels = getattr(conf, "MACRO_PANELS", self.__getVarFromXML( - xmlroot, "MACRO_PANELS", True)) - return macro_panels + def _loadMacroPanels(self, conf): + return self.getConfigValue(conf, "macro_panels", True) - def _loadDoorName(self, conf, xmlroot): - door_name = getattr(conf, "DOOR_NAME", - self.__getVarFromXML(xmlroot, "DOOR_NAME", '')) + def _loadDoorName(self, conf): + door_name = self.getConfigValue(conf, "door_name", True) if door_name: self.doorNameChanged.emit(door_name) - def _loadMacroEditorsPath(self, conf, xmlroot): - macro_editors_path = getattr(conf, "MACROEDITORS_PATH", self.__getVarFromXML( - xmlroot, "MACROEDITORS_PATH", "")) + def _loadMacroEditorsPath(self, conf): + macro_editors_path = self.getConfigValue(conf, "macroeditors_path", True) if macro_editors_path: from sardana.taurus.qt.qtgui.extra_macroexecutor.macroparameterseditor.macroparameterseditor import \ ParamEditorManager ParamEditorManager().parsePaths(macro_editors_path) ParamEditorManager().browsePaths() - def _loadInstrumentsFromPool(self, conf, xmlroot, macro_server_name): + def _loadInstrumentsFromPool(self, conf, macro_server_name): """ Get panel descriptions from pool if required """ - instruments_from_pool = getattr(conf, "INSTRUMENTS_FROM_POOL", (self.__getVarFromXML( - xmlroot, "INSTRUMENTS_FROM_POOL", "False").lower() == "true")) + instruments_from_pool = self.getConfigValue(conf, "instruments_from_pool", False) if instruments_from_pool: try: self.splashScreen().showMessage("Gathering Instrument info from Pool") From b45c6037769734c1dee6963355328cad8343e2c2 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Fri, 12 Jun 2020 23:55:21 +0200 Subject: [PATCH 18/99] Cleanup xmlroot --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index f58b96cea..0c7c07f1c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -999,7 +999,6 @@ def loadConfiguration(self, confname): self, 'Initialization error', msg, Qt.QMessageBox.Abort) sys.exit() - xmlroot = None self._loadAppName(conf, confname) self._loadOrgName(conf) self._loadCustomLogo(conf) @@ -1041,7 +1040,7 @@ def _loadCustomLogo(self, conf): if self.APPLETS_TOOLBAR_ENABLED: self.jorgsBar.addAction(custom_icon, Qt.qApp.applicationName()) - def _loadOrgLogo(self, conf, xmlroot): + def _loadOrgLogo(self, conf): logo = getattr(tauruscustomsettings, "ORGANIZATION_LOGO", "logos:taurus.png") @@ -1083,7 +1082,7 @@ def _loadExtraCatalogWidgets(self, conf): pix_map_name = os.path.join(self._confDirectory, pix_map_name) self._extraCatalogWidgets.append((class_name, pix_map_name)) - def _loadManualUri(self, conf, xmlroot): + def _loadManualUri(self, conf): """ manual panel """ @@ -1157,7 +1156,7 @@ def _loadSynoptic(self, conf): for s in synoptic: self.createMainSynoptic(s) - def _loadConsole(self, conf, xmlroot): + def _loadConsole(self, conf): """ Deprecated CONSOLE command (if you need a IPython Console, just add a Panel with a `silx.gui.console.IPythonWidget` From ea2e63438d3f2c4949c8e468b8abd07bf4dd0e17 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 13 Jun 2020 00:09:35 +0200 Subject: [PATCH 19/99] Make loader more robust --- .../qtgui/taurusgui/config_loader/__init__.py | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index 76662aeac..4a378305b 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -30,16 +30,29 @@ def getLoader(confname): - ext = os.path.splitext(confname)[-1] - if os.path.isdir(confname) or ext == ".py" or "/" not in confname: + if os.path.exists(confname): + if os.path.isfile(confname): + ext = os.path.splitext(confname)[-1] + # happy path, we got file + if ext == ".py": + from .pyconf import PyConfigLoader + return PyConfigLoader(confname) + elif ext == ".xml": + from .xmlconf import XmlConfigLoader + return XmlConfigLoader(confname) + elif ext == ".json": + from .jsonconf import JsonConfigLoader + return JsonConfigLoader(confname) + else: + raise NotImplementedError("Not supported config file format: '%s'" % ext) + elif os.path.isdir(confname): + # if it's directory, assume it's importable Python package + from .pyconf import PyConfigLoader + return PyConfigLoader(confname) + else: + raise ValueError("Not file or directory: '%s'" % confname) + else: + # not path, assume it's importable Python package path from .pyconf import PyConfigLoader return PyConfigLoader(confname) - elif ext == ".xml": - from .xmlconf import XmlConfigLoader - return XmlConfigLoader(confname) - elif ext == ".json": - from .jsonconf import JsonConfigLoader - return JsonConfigLoader(confname) - else: - raise NotImplementedError("No config loader implementation for '%s'" % ext) From 5e83ae38117e1dbd3edc9ba82ee0ab5b73d5fd21 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 13 Jun 2020 14:48:49 +0200 Subject: [PATCH 20/99] Delete function from unsucessful merge --- lib/taurus/test/testsuite.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/lib/taurus/test/testsuite.py b/lib/taurus/test/testsuite.py index fc151ce1d..2bf5878e5 100644 --- a/lib/taurus/test/testsuite.py +++ b/lib/taurus/test/testsuite.py @@ -135,24 +135,5 @@ def testsuite_cmd(gui_tests, exclude_pattern): sys.exit(exit_code) -def add_parser(make_parser): - parser = make_parser(description='Main test suite for Taurus') - parser.add_argument('--skip-gui-tests', dest='skip_gui', - action='store_true', default=False, - help='Do not perform tests requiring GUI') - # TODO: Define the default exclude patterns as a tauruscustomsettings - # variable. - help = """regexp pattern matching test ids to be excluded. - (e.g. 'taurus\.core\..*' would exclude taurus.core tests) - """ - parser.add_argument('-e', '--exclude-pattern', - default='(?!)', - help=help) - - parser.set_defaults(cmd=main) - - return parser - - if __name__ == '__main__': testsuite_cmd() From 7a27f2a6309b7c609e3c555d6383b4ef9a74b432 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 13 Jun 2020 14:59:27 +0200 Subject: [PATCH 21/99] Use absolute paths for imports --- lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py | 6 ++++-- lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py | 6 ++++-- lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 671d09932..f69d9efa9 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -26,8 +26,10 @@ import json import os -from ..utils import PanelDescription, ToolBarDescription, AppletDescription, ExternalApp -from .abstract import AbstractConfigLoader, ConfigLoaderError +from taurus.qt.qtgui.taurusgui.utils import ( + PanelDescription, ToolBarDescription, AppletDescription, ExternalApp) +from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( + AbstractConfigLoader, ConfigLoaderError) __all__ = ["JsonConfigLoader"] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 5453bdf16..3d5dcb7dd 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -28,8 +28,10 @@ import types import inspect -from ..utils import PanelDescription, AppletDescription, ToolBarDescription, ExternalApp -from .abstract import AbstractConfigLoader, ConfigLoaderError +from taurus.qt.qtgui.taurusgui.utils import ( + PanelDescription, AppletDescription, ToolBarDescription, ExternalApp) +from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( + AbstractConfigLoader, ConfigLoaderError) __all__ = ["PyConfigLoader"] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index ea260fe99..de2616c44 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -27,8 +27,10 @@ from lxml import etree -from ..utils import PanelDescription, ToolBarDescription, AppletDescription, ExternalApp -from .abstract import AbstractConfigLoader, ConfigLoaderError +from taurus.qt.qtgui.taurusgui.utils import ( + PanelDescription, ToolBarDescription, AppletDescription, ExternalApp) +from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( + AbstractConfigLoader, ConfigLoaderError) __all__ = ["XmlConfigLoader"] From 4f213ff8400418a507abcacafa6044c9fc38754c Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 13 Jun 2020 15:01:46 +0200 Subject: [PATCH 22/99] Remove unused imports --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 0c7c07f1c..282d98d30 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -33,7 +33,6 @@ import copy import click import weakref -import inspect from future.utils import string_types from lxml import etree @@ -47,7 +46,6 @@ from taurus.qt.qtgui.base import TaurusBaseWidget, TaurusBaseComponent from taurus.qt.qtgui.container import TaurusMainWindow from taurus.qt.qtgui.taurusgui.utils import (ExternalApp, PanelDescription, - ToolBarDescription, AppletDescription) from taurus.qt.qtgui.util.ui import UILoadable from taurus.qt.qtgui.taurusgui.utils import ExternalAppAction From d5e7d0f64a4dc9d5c1a8439d70aab0648e1c4d0e Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 13 Jun 2020 15:06:20 +0200 Subject: [PATCH 23/99] Load monitor widget directly in config loader --- .../qt/qtgui/taurusgui/config_loader/abstract.py | 5 ++++- .../qt/qtgui/taurusgui/config_loader/jsonconf.py | 6 +++++- lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py | 6 +++++- lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py | 6 +++++- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 10 ++++------ 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 5688fe66a..53b85ec84 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -132,7 +132,10 @@ def external_apps(self): # deprecated @abc.abstractproperty def monitor(self): - """Model of Monitor widget""" + """ + ApplicationDescription object with TaurusTinyMonitor widget + and model set from config + """ return None # SARDANA STUFF ON diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index f69d9efa9..884d8f6a9 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -106,7 +106,11 @@ def console(self): @property def monitor(self): - return self._data.get("MONITOR") + return AppletDescription( + "monitor", + classname="TaurusMonitorTiny", + model=self._data.get("MONITOR"), + ) @property def panels(self): diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 3d5dcb7dd..299f3bd8f 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -146,7 +146,11 @@ def console(self): @property def monitor(self): - return getattr(self._mod, 'MONITOR') + return AppletDescription( + "monitor", + classname="TaurusMonitorTiny", + model=getattr(self._mod, 'MONITOR'), + ) @property def panels(self): diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index de2616c44..15e5fe2b5 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -136,7 +136,11 @@ def console(self): @property def monitor(self): - return self._get("MONITOR") + return AppletDescription( + "monitor", + classname="TaurusMonitorTiny", + model=self._get("MONITOR"), + ) @property def panels(self): diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 282d98d30..74628d3e3 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -45,8 +45,7 @@ from taurus.qt.qtgui.util import TaurusWidgetFactory from taurus.qt.qtgui.base import TaurusBaseWidget, TaurusBaseComponent from taurus.qt.qtgui.container import TaurusMainWindow -from taurus.qt.qtgui.taurusgui.utils import (ExternalApp, PanelDescription, - AppletDescription) +from taurus.qt.qtgui.taurusgui.utils import ExternalApp, PanelDescription from taurus.qt.qtgui.util.ui import UILoadable from taurus.qt.qtgui.taurusgui.utils import ExternalAppAction from taurus.core.util.log import deprecation_decorator @@ -1280,10 +1279,9 @@ def _loadCustomApplets(self, conf): """ custom_applets = conf.applets[:] # for backwards compatibility - MONITOR = self.getConfigValue(conf, "monitor", []) - if MONITOR: - custom_applets.append(AppletDescription( - "monitor", classname="TaurusMonitorTiny", model=MONITOR)) + monitor = self.getConfigValue(conf, "monitor", []) + if monitor: + custom_applets.append(monitor) for d in custom_applets: try: From 072f025fa4e68f9e0542c2dc90d0bf292978cae6 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 13 Jun 2020 15:15:42 +0200 Subject: [PATCH 24/99] Add some documentation --- .../qt/qtgui/taurusgui/config_loader/__init__.py | 15 ++++++++++++++- .../qt/qtgui/taurusgui/config_loader/abstract.py | 7 ++++++- .../qt/qtgui/taurusgui/config_loader/jsonconf.py | 3 +++ .../qt/qtgui/taurusgui/config_loader/pyconf.py | 3 +++ .../qt/qtgui/taurusgui/config_loader/xmlconf.py | 4 ++++ 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index 4a378305b..cc4ace350 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -21,7 +21,12 @@ ## ########################################################################### -"""""" +""" +This module provides factory 'getLoader' for proper ConfigLoader object +detected from 'confname' string. Each config loader has to implement interface +defined by AbstractConfigLoader class in +taurus.qt.qtgui.taurusgui.config_loader.abstract +""" import os @@ -30,6 +35,14 @@ def getLoader(confname): + """ + Discover proper config loader based on passed string. + It can be either path to file or directory or Python + abolute path to module with configuration. + + :param confname: name of configuration + :return: A AbstractConfigLoader subclass object + """ if os.path.exists(confname): if os.path.isfile(confname): diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 53b85ec84..ecd860439 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -33,6 +33,9 @@ class ConfigLoaderError(Exception): + """ + Base exception raised by ConfigLoader + """ def __init__(self, message): message = "Exception raised while loading configuration: " + message super(ConfigLoaderError, self).__init__(message) @@ -40,7 +43,9 @@ def __init__(self, message): class AbstractConfigLoader(abc.ABC): """ - Abstract class for config loaders + Abstract class for config loaders. + It defines interface which has to be implemneted by subclass in + order for it to be ConfigLoader """ def __init__(self, confname): diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 884d8f6a9..137adfc2b 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -36,6 +36,9 @@ class JsonConfigLoader(AbstractConfigLoader): + """ + Loads configuration for TaurusGui from JSON file + """ def __init__(self, confname): super(JsonConfigLoader, self).__init__(confname) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 299f3bd8f..775211380 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -38,6 +38,9 @@ class PyConfigLoader(AbstractConfigLoader): + """ + Loads configuration for TaurusGui from Python module or package + """ def __init__(self, confname): super(PyConfigLoader, self).__init__(confname) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index 15e5fe2b5..dfa50ab17 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -37,6 +37,10 @@ class XmlConfigLoader(AbstractConfigLoader): + """ + Loads configuration for TaurusGui from XML file + """ + def __init__(self, confname): super(XmlConfigLoader, self).__init__(confname) self._root = etree.fromstring('') From 4ee3e726bb66ccaf2460256a6a195fc3b55b6707 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 13 Jun 2020 15:20:47 +0200 Subject: [PATCH 25/99] Fix bugs when loading Python module --- lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 775211380..ffdc062ef 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -44,11 +44,12 @@ class PyConfigLoader(AbstractConfigLoader): def __init__(self, confname): super(PyConfigLoader, self).__init__(confname) - self._mod = types.ModuleType('__dummy_conf_module_%s__' %s confname) # dummy module + self._mod = types.ModuleType('__dummy_conf_module_%s__' % confname) # dummy module def _get_objects(self, klass): objs = [obj for name, obj in inspect.getmembers(self._mod) if isinstance(obj, klass)] + return objs def _importConfiguration(self): '''returns the module corresponding to `confname` or to @@ -96,8 +97,7 @@ def load(self): name, _ = os.path.splitext(name) try: f, filename, data = imp.find_module(name, [path]) - conf = imp.load_module(name, f, filename, data) - confname = name + self._mod = imp.load_module(name, f, filename, data) except ImportError: self._mod = self._importConfiguration() else: # if confname is not a dir name, we assume it is a module name in the python path From 8b857505c3d91586300cd471274732943356ccca Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 13 Jun 2020 15:35:52 +0200 Subject: [PATCH 26/99] PEP8 --- .../qtgui/taurusgui/config_loader/__init__.py | 9 ++- .../qtgui/taurusgui/config_loader/abstract.py | 4 +- .../qtgui/taurusgui/config_loader/jsonconf.py | 21 +++++-- .../qtgui/taurusgui/config_loader/pyconf.py | 59 +++++++++++-------- .../qtgui/taurusgui/config_loader/xmlconf.py | 20 +++++-- 5 files changed, 77 insertions(+), 36 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index cc4ace350..1b9335eca 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -50,22 +50,29 @@ def getLoader(confname): # happy path, we got file if ext == ".py": from .pyconf import PyConfigLoader + return PyConfigLoader(confname) elif ext == ".xml": from .xmlconf import XmlConfigLoader + return XmlConfigLoader(confname) elif ext == ".json": from .jsonconf import JsonConfigLoader + return JsonConfigLoader(confname) else: - raise NotImplementedError("Not supported config file format: '%s'" % ext) + raise NotImplementedError( + "Not supported config file format: '%s'" % ext + ) elif os.path.isdir(confname): # if it's directory, assume it's importable Python package from .pyconf import PyConfigLoader + return PyConfigLoader(confname) else: raise ValueError("Not file or directory: '%s'" % confname) else: # not path, assume it's importable Python package path from .pyconf import PyConfigLoader + return PyConfigLoader(confname) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index ecd860439..24d102a0f 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -26,7 +26,7 @@ # Python 2/3 compatibility if not hasattr(abc, "ABC"): - setattr(abc, "ABC", abc.ABCMeta('ABC', (object,), {})) + setattr(abc, "ABC", abc.ABCMeta("ABC", (object,), {})) __all__ = ["AbstractConfigLoader", "ConfigLoaderError"] @@ -36,6 +36,7 @@ class ConfigLoaderError(Exception): """ Base exception raised by ConfigLoader """ + def __init__(self, message): message = "Exception raised while loading configuration: " + message super(ConfigLoaderError, self).__init__(message) @@ -168,4 +169,5 @@ def macroeditors_path(self): def instruments_from_pool(self): """Whether to load instruments from Pool as panels or not""" return None + # SARDANA STUFF OFF diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 137adfc2b..ed8274964 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -27,9 +27,15 @@ import os from taurus.qt.qtgui.taurusgui.utils import ( - PanelDescription, ToolBarDescription, AppletDescription, ExternalApp) + PanelDescription, + ToolBarDescription, + AppletDescription, + ExternalApp, +) from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, ConfigLoaderError) + AbstractConfigLoader, + ConfigLoaderError, +) __all__ = ["JsonConfigLoader"] @@ -49,7 +55,8 @@ def _get_objects(self, klass): Helper function to get list of Python objects from dictionary """ objs = [] - for o in self._data.get(klass.__name__ + "s", []): # 's' is for plural form + classname = klass.__name__ + "s" # 's' is for plural form + for o in self._data.get(classname, []): if isinstance(o, dict): objs.append(klass(**o)) return objs @@ -59,9 +66,13 @@ def load(self): with open(self._confname, "r") as fp: self._data = json.load(fp) except IOError as e: - raise ConfigLoaderError("Problem with accessing config file: " + str(e)) + raise ConfigLoaderError( + "Problem with accessing config file: " + str(e) + ) except ValueError as e: - raise ConfigLoaderError("Problem with config file decoding: " + str(e)) + raise ConfigLoaderError( + "Problem with config file decoding: " + str(e) + ) @property def conf_dir(self): diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index ffdc062ef..d73ee5476 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -29,9 +29,15 @@ import inspect from taurus.qt.qtgui.taurusgui.utils import ( - PanelDescription, AppletDescription, ToolBarDescription, ExternalApp) + PanelDescription, + AppletDescription, + ToolBarDescription, + ExternalApp, +) from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, ConfigLoaderError) + AbstractConfigLoader, + ConfigLoaderError, +) __all__ = ["PyConfigLoader"] @@ -44,20 +50,26 @@ class PyConfigLoader(AbstractConfigLoader): def __init__(self, confname): super(PyConfigLoader, self).__init__(confname) - self._mod = types.ModuleType('__dummy_conf_module_%s__' % confname) # dummy module + self._mod = types.ModuleType( + "__dummy_conf_module_%s__" % confname + ) # dummy module def _get_objects(self, klass): - objs = [obj for name, obj in inspect.getmembers(self._mod) - if isinstance(obj, klass)] + objs = [ + obj + for name, obj in inspect.getmembers(self._mod) + if isinstance(obj, klass) + ] return objs def _importConfiguration(self): - '''returns the module corresponding to `confname` or to + """returns the module corresponding to `confname` or to `tgconf_`. Note: the `conf` subdirectory of the directory in which taurusgui.py file is installed is temporally prepended to sys.path - ''' - confsubdir = os.path.join(os.path.abspath(os.path.dirname( - __file__)), 'conf') # the path to a conf subdirectory of the place where taurusgui.py is + """ + confsubdir = os.path.join( + os.path.abspath(os.path.dirname(__file__)), "conf" + ) # the path to a conf subdirectory of the place where taurusgui.py is oldpath = sys.path try: # add the conf subdirectory dir to the pythonpath @@ -68,14 +80,14 @@ def _importConfiguration(self): try: mod = __import__(altconfname) except ImportError: - msg = 'cannot import %s or %s' % (self._confname, altconfname) + msg = "cannot import %s or %s" % (self._confname, altconfname) raise ConfigLoaderError(msg) finally: sys.path = oldpath # restore the previous sys.path return mod def load(self): - '''Reads a configuration file + """Reads a configuration file :param confname: (str or None) the name of module located in the PYTHONPATH or in the conf subdirectory of the directory @@ -88,11 +100,12 @@ def load(self): PYTHONPATH). `confname` can also be None, in which case a dummy empty module will be used. - ''' + """ # import the python config file if os.path.exists(self._confname): # if confname is a dir or file name import imp + path, name = os.path.split(self._confname) name, _ = os.path.splitext(name) try: @@ -109,50 +122,50 @@ def conf_dir(self): @property def app_name(self): - return getattr(self._mod, 'GUI_NAME') + return getattr(self._mod, "GUI_NAME") @property def org_name(self): - return getattr(self._mod, 'ORGANIZATION') + return getattr(self._mod, "ORGANIZATION") @property def custom_logo(self): - return getattr(self._mod, 'CUSTOM_LOGO') + return getattr(self._mod, "CUSTOM_LOGO") @property def org_logo(self): - return getattr(self._mod, 'ORGANIZATION_LOGO') + return getattr(self._mod, "ORGANIZATION_LOGO") @property def single_instance(self): - return getattr(self._mod, 'SINGLE_INSTANCE') + return getattr(self._mod, "SINGLE_INSTANCE") @property def manual_uri(self): - return getattr(self._mod, 'MANUAL_URI') + return getattr(self._mod, "MANUAL_URI") @property def ini_file(self): - return getattr(self._mod, 'INIFILE') + return getattr(self._mod, "INIFILE") @property def extra_catalog_widgets(self): - return getattr(self._mod, 'EXTRA_CATALOG_WIDGETS', []) + return getattr(self._mod, "EXTRA_CATALOG_WIDGETS", []) @property def synoptics(self): - return getattr(self._mod, 'SYNOPTIC', []) + return getattr(self._mod, "SYNOPTIC", []) @property def console(self): - return getattr(self._mod, 'CONSOLE', []) + return getattr(self._mod, "CONSOLE", []) @property def monitor(self): return AppletDescription( "monitor", classname="TaurusMonitorTiny", - model=getattr(self._mod, 'MONITOR'), + model=getattr(self._mod, "MONITOR"), ) @property diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index dfa50ab17..9932f33ff 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -28,9 +28,15 @@ from lxml import etree from taurus.qt.qtgui.taurusgui.utils import ( - PanelDescription, ToolBarDescription, AppletDescription, ExternalApp) + PanelDescription, + ToolBarDescription, + AppletDescription, + ExternalApp, +) from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, ConfigLoaderError) + AbstractConfigLoader, + ConfigLoaderError, +) __all__ = ["XmlConfigLoader"] @@ -43,7 +49,7 @@ class XmlConfigLoader(AbstractConfigLoader): def __init__(self, confname): super(XmlConfigLoader, self).__init__(confname) - self._root = etree.fromstring('') + self._root = etree.fromstring("") def _get(self, nodename, default=None): """ @@ -64,7 +70,7 @@ def _get_objects(self, klass): if obj is not None: for child in obj: if child.tag == klass.__name__: - child_str = etree.tostring(child, encoding='unicode') + child_str = etree.tostring(child, encoding="unicode") o = klass.fromXml(child_str) if o is not None: objs.append(o) @@ -75,10 +81,12 @@ def load(self): Get the xml root node from the xml configuration file """ try: - with open(self._confname, 'r') as xmlFile: + with open(self._confname, "r") as xmlFile: self._root = etree.fromstring(xmlFile.read()) except IOError as e: - raise ConfigLoaderError("Problem with accessing config file: " + str(e)) + raise ConfigLoaderError( + "Problem with accessing config file: " + str(e) + ) except Exception as e: msg = 'Error reading the XML file: "%s"' % self._confname raise ConfigLoaderError(msg) From fb890cec95fc8fd51cf454d2312586e6599d5d7e Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 15 Jun 2020 21:22:56 +0200 Subject: [PATCH 27/99] Use entrypoints to discover and load config loader plugins --- .../qtgui/taurusgui/config_loader/__init__.py | 41 ++++++++++++------- setup.py | 7 ++++ 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index 1b9335eca..360981d1a 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -30,6 +30,8 @@ import os +import pkg_resources + __all__ = ["getLoader"] @@ -45,25 +47,19 @@ def getLoader(confname): """ if os.path.exists(confname): - if os.path.isfile(confname): - ext = os.path.splitext(confname)[-1] - # happy path, we got file - if ext == ".py": - from .pyconf import PyConfigLoader - - return PyConfigLoader(confname) - elif ext == ".xml": - from .xmlconf import XmlConfigLoader + if os.path.isfile(confname): # happy path, we got file - return XmlConfigLoader(confname) - elif ext == ".json": - from .jsonconf import JsonConfigLoader + # get file extension without dot + ext = os.path.splitext(confname)[-1][1:] - return JsonConfigLoader(confname) - else: + klass = _get_plugin_from_entrypoint(ext, "taurus.gui.loader") + if klass is None: raise NotImplementedError( "Not supported config file format: '%s'" % ext ) + else: + return klass(confname) + elif os.path.isdir(confname): # if it's directory, assume it's importable Python package from .pyconf import PyConfigLoader @@ -76,3 +72,20 @@ def getLoader(confname): from .pyconf import PyConfigLoader return PyConfigLoader(confname) + + +def _get_plugin_from_entrypoint(name, entry_point): + """ + Load value of entry point as plugin. + Exceptions are not caught on purpose - propagate them up the stack. + + :param name: name of plugin + :param entry_point: dotted name of entry-point loading space + :return: entry point value if found, None otherwise + """ + + for ep in pkg_resources.iter_entry_points(entry_point): + if ep.name == name: + ep_value = ep.load() + return ep_value + return None diff --git a/setup.py b/setup.py index ffaa8a661..5a0dc1c37 100644 --- a/setup.py +++ b/setup.py @@ -125,11 +125,18 @@ def get_release_info(): '{:.5f} = taurus.qt.qtgui.base:floatFormatter', ] +config_loaders = [ + 'py = taurus.qt.qtgui.taurusgui.config_loaders.pyconf:PyConfigLoader', + 'json = taurus.qt.qtgui.taurusgui.config_loaders.jsonconf:JsonConfigLoader', + 'xml = taurus.qt.qtgui.taurusgui.config_loaders.xmlconf:XmlConfigLoader', +] + entry_points = { 'console_scripts': console_scripts, 'taurus.cli.subcommands': taurus_subcommands, 'taurus.qt.qtgui.panel.TaurusModelSelector.items': model_selectors, 'taurus.qt.formatters': formatters, + 'taurus.gui.loaders': config_loaders, } classifiers = [ From 5f7fc7f072cd560a9b259c61048f36f54f9be607 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 15 Jun 2020 21:33:51 +0200 Subject: [PATCH 28/99] Return default value when reading config from Python module --- .../qtgui/taurusgui/config_loader/pyconf.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index d73ee5476..f37a2df52 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -122,31 +122,31 @@ def conf_dir(self): @property def app_name(self): - return getattr(self._mod, "GUI_NAME") + return getattr(self._mod, "GUI_NAME", None) @property def org_name(self): - return getattr(self._mod, "ORGANIZATION") + return getattr(self._mod, "ORGANIZATION", None) @property def custom_logo(self): - return getattr(self._mod, "CUSTOM_LOGO") + return getattr(self._mod, "CUSTOM_LOGO", None) @property def org_logo(self): - return getattr(self._mod, "ORGANIZATION_LOGO") + return getattr(self._mod, "ORGANIZATION_LOGO", None) @property def single_instance(self): - return getattr(self._mod, "SINGLE_INSTANCE") + return getattr(self._mod, "SINGLE_INSTANCE", None) @property def manual_uri(self): - return getattr(self._mod, "MANUAL_URI") + return getattr(self._mod, "MANUAL_URI", None) @property def ini_file(self): - return getattr(self._mod, "INIFILE") + return getattr(self._mod, "INIFILE", None) @property def extra_catalog_widgets(self): @@ -186,20 +186,20 @@ def external_apps(self): @property def macroserver_name(self): - return getattr(self._mod, "MACROSERVER_NAME") + return getattr(self._mod, "MACROSERVER_NAME", None) @property def macro_panels(self): - return getattr(self._mod, "MACRO_PANELS") + return getattr(self._mod, "MACRO_PANELS", None) @property def door_name(self): - return getattr(self._mod, "DOOR_NAME") + return getattr(self._mod, "DOOR_NAME", None) @property def macroeditors_path(self): - return getattr(self._mod, "MACROEDITORS_PATH") + return getattr(self._mod, "MACROEDITORS_PATH", None) @property def instruments_from_pool(self): - return getattr(self._mod, "INSTRUMENTS_FROM_POOL") + return getattr(self._mod, "INSTRUMENTS_FROM_POOL", None) From 10394bd85b53c439f4b00f22fee1fb3cab713503 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 15 Jun 2020 22:40:41 +0200 Subject: [PATCH 29/99] Fix issues with entrypoints --- lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py | 2 +- setup.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index 360981d1a..5b07cdc92 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -52,7 +52,7 @@ def getLoader(confname): # get file extension without dot ext = os.path.splitext(confname)[-1][1:] - klass = _get_plugin_from_entrypoint(ext, "taurus.gui.loader") + klass = _get_plugin_from_entrypoint(ext, "taurus.gui.loaders") if klass is None: raise NotImplementedError( "Not supported config file format: '%s'" % ext diff --git a/setup.py b/setup.py index 5a0dc1c37..8b8f50b89 100644 --- a/setup.py +++ b/setup.py @@ -126,9 +126,9 @@ def get_release_info(): ] config_loaders = [ - 'py = taurus.qt.qtgui.taurusgui.config_loaders.pyconf:PyConfigLoader', - 'json = taurus.qt.qtgui.taurusgui.config_loaders.jsonconf:JsonConfigLoader', - 'xml = taurus.qt.qtgui.taurusgui.config_loaders.xmlconf:XmlConfigLoader', + 'py = taurus.qt.qtgui.taurusgui.config_loader.pyconf:PyConfigLoader', + 'json = taurus.qt.qtgui.taurusgui.config_loader.jsonconf:JsonConfigLoader', + 'xml = taurus.qt.qtgui.taurusgui.config_loader.xmlconf:XmlConfigLoader', ] entry_points = { From 6736212b862a9769e0285ea44b85a294593bc434 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 15 Jun 2020 22:58:29 +0200 Subject: [PATCH 30/99] Add launcher for manual testing of config loader --- .../qtgui/taurusgui/config_loader/__main__.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py new file mode 100644 index 000000000..22f3c14c4 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py @@ -0,0 +1,31 @@ +import sys + +from . import getLoader + + +l = getLoader(sys.argv[1]) +l.load() +print("GUI_NAME: " + str(l.app_name)) +print("ORGANIZATION: " + str(l.org_name)) +print("CUSTOM_LOGO: " + str(l.custom_logo)) +print("ORGANIZATION_LOGO: " + str(l.org_logo)) +print("SINGLE_INSTANCE: " + str(l.single_instance)) +print("MANUAL_URI: " + str(l.manual_uri)) +print("INIFILE: " + str(l.ini_file)) +print("EXTRA_CATALOG_WIDGETS") +for w, i in l.extra_catalog_widgets: + print("\tWidget: " + str(w) + ", icon: " + str(i)) +print("SYNOPTIC: " + str(l.synoptics)) +print("CONSOLE: " + str(l.console)) +print("PanelDescriptions: ") +for p in l.panels: + print("\t" + str(p)) +print("ToolBarDescriptions: ") +for p in l.toolbars: + print("\t" + str(p)) +print("AppletDescriptions: ") +for p in l.applets: + print("\t" + str(p)) +print("ExternalApp: ") +for p in l.external_apps: + print("\t" + str(p)) From a6386b854e13c6214f433f5f2d7b1c3889c4e96a Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 15 Jun 2020 22:59:36 +0200 Subject: [PATCH 31/99] Add examples of configuration for Python and JSON file --- .../config_loader/examples/config.json | 69 ++++++++++++++++++ .../config_loader/examples/config.py | 70 +++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/examples/config.json create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/examples/config.py diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/examples/config.json b/lib/taurus/qt/qtgui/taurusgui/config_loader/examples/config.json new file mode 100644 index 000000000..95489ba1e --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/examples/config.json @@ -0,0 +1,69 @@ +{ + "GUI_NAME": "EXAMPLE 01", + "ORGANIZATION": "Taurus", + "MANUAL_URI": "http://www.taurus-scada.org", + "SYNOPTIC": ["images/example01.jdw", "images/syn2.jdw"], + "INSTRUMENTS_FROM_POOL": false, + "PanelDescriptions": [ + { + "name": "NeXus Browser", + "classname": "taurus.qt.qtgui.extra_nexus.TaurusNeXusBrowser" + }, + { + "name": "BigInstrument", + "classname": "taurus.qt.qtgui.panel.TaurusAttrForm", + "model": "sys/tg_test/1" + }, + { + "name": "NeXus Browser", + "classname": "taurus.qt.qtgui.extra_nexus.TaurusNeXusBrowser" + }, + { + "name": "instrument1", + "classname": "taurus.qt.qtgui.panel.TaurusForm", + "model": [ + "sys/tg_test/1/double_scalar", + "sys/tg_test/1/short_scalar_ro", + "sys/tg_test/1/float_spectrum_ro", + "sys/tg_test/1/double_spectrum" + ] + }, + { + "name": "instrument2", + "classname": "taurus.qt.qtgui.panel.TaurusForm", + "model": [ + "sys/tg_test/1/wave", + "sys/tg_test/1/boolean_scalar" + ] + }, + { + "name": "Selected Instrument", + "classname": "taurus.external.qt.Qt.QLineEdit", + "sharedDataRead": { + "SelectedInstrument": "setText" + }, + "sharedDataWrite": { + "SelectedInstrument": "textEdited" + } + } + ], + "ToolBarDescriptions": [ + { + "name": "Empty Toolbar", + "classname": "taurus.external.qt.Qt.QToolBar" + } + ], + "ExternalApps": [ + { + "name": "xterm", + "cmdargs": ["xterm", "spock"], + "text": "Spock", + "icon": "utilities-terminal" + } + ], + "EXTRA_CATALOG_WIDGETS": [ + ["taurus.external.qt.Qt.QLineEdit", "logos:taurus.png"], + ["taurus.external.qt.Qt.QSpinBox", "images/syn2.jpg"], + ["taurus.external.qt.Qt.QLabel", null] + ] +} \ No newline at end of file diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/examples/config.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/examples/config.py new file mode 100644 index 000000000..e00aecc26 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/examples/config.py @@ -0,0 +1,70 @@ + + +from taurus.qt.qtgui.taurusgui.utils import PanelDescription, ExternalApp, ToolBarDescription, AppletDescription + +GUI_NAME = 'EXAMPLE 01' +ORGANIZATION = 'Taurus' + +MANUAL_URI = 'http://www.taurus-scada.org' + +SYNOPTIC = ['images/example01.jdw', 'images/syn2.jdw'] + + +INSTRUMENTS_FROM_POOL = False + + +nxbrowser = PanelDescription( + 'NeXus Browser', + classname='taurus.qt.qtgui.extra_nexus.TaurusNeXusBrowser' +) + +i0 = PanelDescription( + 'BigInstrument', + classname='taurus.qt.qtgui.panel.TaurusAttrForm', + model='sys/tg_test/1' +) + +i1 = PanelDescription( + 'instrument1', + classname='taurus.qt.qtgui.panel.TaurusForm', + model=['sys/tg_test/1/double_scalar', + 'sys/tg_test/1/short_scalar_ro', + 'sys/tg_test/1/float_spectrum_ro', + 'sys/tg_test/1/double_spectrum'] +) + +i2 = PanelDescription( + 'instrument2', + classname='taurus.qt.qtgui.panel.TaurusForm', + model=['sys/tg_test/1/wave', + 'sys/tg_test/1/boolean_scalar'] +) + +trend = PanelDescription( + 'Trend', + classname='taurus.qt.qtgui.plot.TaurusTrend', + model=['sys/tg_test/1/double_scalar'] +) + +connectionDemo = PanelDescription( + 'Selected Instrument', + classname='taurus.external.qt.Qt.QLineEdit', # A pure Qt widget! + sharedDataRead={'SelectedInstrument': 'setText'}, + sharedDataWrite={'SelectedInstrument': 'textEdited'} +) + +dummytoolbar = ToolBarDescription( + 'Empty Toolbar', + classname='taurus.external.qt.Qt.QToolBar' +) + +xterm = ExternalApp( + cmdargs=['xterm', 'spock'], text="Spock", icon='utilities-terminal') +hdfview = ExternalApp(["hdfview"]) +pymca = ExternalApp(['pymca']) + +EXTRA_CATALOG_WIDGETS = [ + ('taurus.external.qt.Qt.QLineEdit', 'logos:taurus.png'), # a resource + ('taurus.external.qt.Qt.QSpinBox', 'images/syn2.jpg'), # relative + # ('taurus.external.Qt.QTextEdit','/tmp/foo.png'), # absolute + ('taurus.external.qt.Qt.QLabel', None)] # none From 402c829b1436572f8bab4f056222cf65fd9cc9d3 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Tue, 16 Jun 2020 20:51:00 +0200 Subject: [PATCH 32/99] Make quick launcher more structurized --- .../qtgui/taurusgui/config_loader/__main__.py | 77 ++++++++++++------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py index 22f3c14c4..9f240ced5 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py @@ -3,29 +3,54 @@ from . import getLoader -l = getLoader(sys.argv[1]) -l.load() -print("GUI_NAME: " + str(l.app_name)) -print("ORGANIZATION: " + str(l.org_name)) -print("CUSTOM_LOGO: " + str(l.custom_logo)) -print("ORGANIZATION_LOGO: " + str(l.org_logo)) -print("SINGLE_INSTANCE: " + str(l.single_instance)) -print("MANUAL_URI: " + str(l.manual_uri)) -print("INIFILE: " + str(l.ini_file)) -print("EXTRA_CATALOG_WIDGETS") -for w, i in l.extra_catalog_widgets: - print("\tWidget: " + str(w) + ", icon: " + str(i)) -print("SYNOPTIC: " + str(l.synoptics)) -print("CONSOLE: " + str(l.console)) -print("PanelDescriptions: ") -for p in l.panels: - print("\t" + str(p)) -print("ToolBarDescriptions: ") -for p in l.toolbars: - print("\t" + str(p)) -print("AppletDescriptions: ") -for p in l.applets: - print("\t" + str(p)) -print("ExternalApp: ") -for p in l.external_apps: - print("\t" + str(p)) +def print_component(p): + print("\n\tName: " + p.name) + print("\tClass name: " + p.classname) + print("\tModule name: " + p.modulename) + print("\tWidget name: " + str(p.widgetname)) + print("\tFloating: " + str(p.floating)) + print("\tShared data write: " + str(p.sharedDataWrite)) + print("\tShared data read: " + str(p.sharedDataRead)) + print("\tModel: " + str(p.model)) + + +def print_panel(p): + print_component(p) + print("\tInstrument key: " + str(p.instrumentkey)) + print("\tIcon: " + str(p.icon)) + print("\tModel in config: " + str(p.model_in_config)) + print("\tModifiable by user: " + str(p.modifiable_by_user)) + print("\tWidget formatter: " + str(p.widget_formatter)) + print("\tWidget properties: " + str(p.widget_properties)) + + +def main(conf): + l = getLoader(conf) + l.load() + print("GUI_NAME: " + str(l.app_name)) + print("ORGANIZATION: " + str(l.org_name)) + print("CUSTOM_LOGO: " + str(l.custom_logo)) + print("ORGANIZATION_LOGO: " + str(l.org_logo)) + print("SINGLE_INSTANCE: " + str(l.single_instance)) + print("MANUAL_URI: " + str(l.manual_uri)) + print("INIFILE: " + str(l.ini_file)) + print("EXTRA_CATALOG_WIDGETS") + for w, i in l.extra_catalog_widgets: + print("\tWidget: " + str(w) + ", icon: " + str(i)) + print("SYNOPTIC: " + str(l.synoptics)) + print("CONSOLE: " + str(l.console)) + print("PanelDescriptions: ") + for p in l.panels: + print_panel(p) + print("ToolBarDescriptions: ") + for p in l.toolbars: + print_component(p) + print("AppletDescriptions: ") + for p in l.applets: + print_component(p) + print("ExternalApp: ") + for p in l.external_apps: + print("\t" + str(p)) + + +main(sys.argv[1]) From d3af28774cc03b7ec734e5cf4208383471dfcc72 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Tue, 16 Jun 2020 21:48:20 +0200 Subject: [PATCH 33/99] Add new moethod for indicitaing if loader supports condifuration --- lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 24d102a0f..9e68f807a 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -52,6 +52,13 @@ class AbstractConfigLoader(abc.ABC): def __init__(self, confname): self._confname = confname + @abc.abstractmethod + def supports(self, confname): + """ + Return True or False for support of specific configuration passed + """ + return None + @abc.abstractmethod def load(self): """ From b5764a9e67afef4cbff6f27b3a9dbcda88aefb3d Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Tue, 16 Jun 2020 21:54:01 +0200 Subject: [PATCH 34/99] Implement supports method for all loaders --- .../qtgui/taurusgui/config_loader/jsonconf.py | 7 +++++++ .../qtgui/taurusgui/config_loader/pyconf.py | 19 +++++++++++++++++++ .../qtgui/taurusgui/config_loader/xmlconf.py | 7 +++++++ 3 files changed, 33 insertions(+) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index ed8274964..50ef2b002 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -61,6 +61,13 @@ def _get_objects(self, klass): objs.append(klass(**o)) return objs + def supports(self, confname): + if os.path.isfile(confname): + ext = os.path.splitext(confname)[-1] + if ext == ".json": + return True + return False + def load(self): try: with open(self._confname, "r") as fp: diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index f37a2df52..d0d2acbd8 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -24,6 +24,7 @@ """""" import os +import pkgutil import sys import types import inspect @@ -86,6 +87,24 @@ def _importConfiguration(self): sys.path = oldpath # restore the previous sys.path return mod + def supports(self, confname): + if os.path.exists(confname): + if os.path.isfile(confname): # happy path, we got file + ext = os.path.splitext(confname)[-1] + if ext == ".py": + return True + return False + + elif os.path.isdir(confname): + # if it's directory, assume it's importable Python package + return True + return False + else: + # not exisitng path, check if it is in top-level modules + if confname in list(pkgutil.iter_modules()): + return True + return False + def load(self): """Reads a configuration file diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index 9932f33ff..4c1f28f94 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -76,6 +76,13 @@ def _get_objects(self, klass): objs.append(o) return objs + def supports(self, confname): + if os.path.isfile(confname): + ext = os.path.splitext(confname)[-1] + if ext == ".xml": + return True + return False + def load(self): """ Get the xml root node from the xml configuration file From 7e5ff0ef7e10674ec7e74480579cd67df7828e87 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Tue, 16 Jun 2020 22:00:52 +0200 Subject: [PATCH 35/99] Make supports method static --- lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py | 3 ++- lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py | 3 ++- lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 50ef2b002..37223b277 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -61,7 +61,8 @@ def _get_objects(self, klass): objs.append(klass(**o)) return objs - def supports(self, confname): + @staticmethod + def supports(confname): if os.path.isfile(confname): ext = os.path.splitext(confname)[-1] if ext == ".json": diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index d0d2acbd8..9cb3457dd 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -87,7 +87,8 @@ def _importConfiguration(self): sys.path = oldpath # restore the previous sys.path return mod - def supports(self, confname): + @staticmethod + def supports(confname): if os.path.exists(confname): if os.path.isfile(confname): # happy path, we got file ext = os.path.splitext(confname)[-1] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index 4c1f28f94..64e6b9e94 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -76,7 +76,8 @@ def _get_objects(self, klass): objs.append(o) return objs - def supports(self, confname): + @staticmethod + def supports(confname): if os.path.isfile(confname): ext = os.path.splitext(confname)[-1] if ext == ".xml": From ae83efc231e5b0f2e7b9b07558927bc77d95929f Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Tue, 16 Jun 2020 22:13:43 +0200 Subject: [PATCH 36/99] Adapt getLoader emthod to support multiple loaders --- .../qtgui/taurusgui/config_loader/__init__.py | 63 ++++++------------- 1 file changed, 18 insertions(+), 45 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index 5b07cdc92..3d7d60412 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -28,10 +28,10 @@ taurus.qt.qtgui.taurusgui.config_loader.abstract """ -import os - import pkg_resources +from taurus import warning + __all__ = ["getLoader"] @@ -46,46 +46,19 @@ def getLoader(confname): :return: A AbstractConfigLoader subclass object """ - if os.path.exists(confname): - if os.path.isfile(confname): # happy path, we got file - - # get file extension without dot - ext = os.path.splitext(confname)[-1][1:] - - klass = _get_plugin_from_entrypoint(ext, "taurus.gui.loaders") - if klass is None: - raise NotImplementedError( - "Not supported config file format: '%s'" % ext - ) - else: - return klass(confname) - - elif os.path.isdir(confname): - # if it's directory, assume it's importable Python package - from .pyconf import PyConfigLoader - - return PyConfigLoader(confname) - else: - raise ValueError("Not file or directory: '%s'" % confname) - else: - # not path, assume it's importable Python package path - from .pyconf import PyConfigLoader - - return PyConfigLoader(confname) - - -def _get_plugin_from_entrypoint(name, entry_point): - """ - Load value of entry point as plugin. - Exceptions are not caught on purpose - propagate them up the stack. - - :param name: name of plugin - :param entry_point: dotted name of entry-point loading space - :return: entry point value if found, None otherwise - """ - - for ep in pkg_resources.iter_entry_points(entry_point): - if ep.name == name: - ep_value = ep.load() - return ep_value - return None + loaders = [] + for ep in pkg_resources.iter_entry_points("taurus.gui.loaders"): + try: + loader = ep.load() + if loader.supports(confname): + loaders.append(loader(confname)) + except Exception as e: + warning( + "Could not load config loader plugin '%s. Reason: '%s", + ep.name, + e, + ) + if not loaders: + raise NotImplementedError( + "Not supported config loader for '%s'" % confname + ) From 9bf4b545fa9af7aef6b97ad0b60487afad47833b Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Wed, 17 Jun 2020 10:19:53 +0200 Subject: [PATCH 37/99] m, typo --- lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index 3d7d60412..a75ef4361 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -60,5 +60,5 @@ def getLoader(confname): ) if not loaders: raise NotImplementedError( - "Not supported config loader for '%s'" % confname + "No supported config loader for '%s'" % confname ) From 5475327e9f50ce11a95bf7355dbcc7162448bff7 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 21:01:29 +0200 Subject: [PATCH 38/99] Add prefix for config loaders entrypoints --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 8b8f50b89..782138d07 100644 --- a/setup.py +++ b/setup.py @@ -126,9 +126,9 @@ def get_release_info(): ] config_loaders = [ - 'py = taurus.qt.qtgui.taurusgui.config_loader.pyconf:PyConfigLoader', - 'json = taurus.qt.qtgui.taurusgui.config_loader.jsonconf:JsonConfigLoader', - 'xml = taurus.qt.qtgui.taurusgui.config_loader.xmlconf:XmlConfigLoader', + 'taurus.py = taurus.qt.qtgui.taurusgui.config_loader.pyconf:PyConfigLoader', + 'taurus.json = taurus.qt.qtgui.taurusgui.config_loader.jsonconf:JsonConfigLoader', + 'taurus.xml = taurus.qt.qtgui.taurusgui.config_loader.xmlconf:XmlConfigLoader', ] entry_points = { From 1a3764ddb9346ee3b37219f7a2771d2be4601b64 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 21:03:37 +0200 Subject: [PATCH 39/99] Remove deprecated properties and Sardana-centred ones from mandatory abstract API --- .../qtgui/taurusgui/config_loader/abstract.py | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 9e68f807a..59787e279 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -117,11 +117,6 @@ def synoptics(self): """Sequence of paths to synoptic files""" return [] - @abc.abstractproperty - def console(self): - """Whether to add console widget or not""" - return None - @abc.abstractproperty def panels(self): """List of custom panels with widgets""" @@ -141,40 +136,3 @@ def applets(self): def external_apps(self): """List of external applications""" return [] - - # deprecated - @abc.abstractproperty - def monitor(self): - """ - ApplicationDescription object with TaurusTinyMonitor widget - and model set from config - """ - return None - - # SARDANA STUFF ON - @abc.abstractproperty - def macroserver_name(self): - """Name of MacroServer""" - return None - - @abc.abstractproperty - def macro_panels(self): - """Whether to enable Sardana macro panels or not""" - return None - - @abc.abstractproperty - def door_name(self): - """Name of MacroServer's Door""" - return None - - @abc.abstractproperty - def macroeditors_path(self): - """Path to macro editors (?)""" - return None - - @abc.abstractproperty - def instruments_from_pool(self): - """Whether to load instruments from Pool as panels or not""" - return None - - # SARDANA STUFF OFF From 9cd21780a451af2ec563594abc2e085b54dd66bb Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 21:04:06 +0200 Subject: [PATCH 40/99] Remove conf_dir from mandatory abstract API --- lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 59787e279..19fb472eb 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -65,13 +65,6 @@ def load(self): This method is meant to load actual data from file on disk """ - @abc.abstractproperty - def conf_dir(self): - """ - Absolute path to directory in which config file is placed - """ - return None - @abc.abstractproperty def app_name(self): """Name of the application""" From 5acc5c7fb8accb787de7ec9dc53642f84629787c Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 21:28:49 +0200 Subject: [PATCH 41/99] Use flexible dictionary with configuration instead of class fields --- .../qtgui/taurusgui/config_loader/abstract.py | 81 +++----------- .../qtgui/taurusgui/config_loader/jsonconf.py | 100 +++--------------- .../qtgui/taurusgui/config_loader/pyconf.py | 98 ++--------------- .../qtgui/taurusgui/config_loader/xmlconf.py | 91 ++-------------- 4 files changed, 48 insertions(+), 322 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 19fb472eb..76c296cee 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -49,6 +49,18 @@ class AbstractConfigLoader(abc.ABC): order for it to be ConfigLoader """ + CONFIG_VALUES = [ + "GUI_NAME", + "ORGANIZATION", + "CUSTOM_LOGO", + "ORGANIZATION_LOGO", + "SINGLE_INSTANCE", + "MANUAL_URI", + "INIFILE", + "EXTRA_CATALOG_WIDGETS", + "SYNOPTIC", + ] + def __init__(self, confname): self._confname = confname @@ -62,70 +74,7 @@ def supports(self, confname): @abc.abstractmethod def load(self): """ - This method is meant to load actual data from file on disk + This method is meant to load actual data from file on disk. + Return dictionary with configuration. """ - - @abc.abstractproperty - def app_name(self): - """Name of the application""" - return None - - @abc.abstractproperty - def org_name(self): - """Name of organization""" - return None - - @abc.abstractproperty - def custom_logo(self): - """Path to application's custom logo file""" - return None - - @abc.abstractproperty - def org_logo(self): - """Path to organization's custom logo file""" - return None - - @abc.abstractproperty - def single_instance(self): - """Whether more than one instance of application can be launched simultaously or not""" - return None - - @abc.abstractproperty - def manual_uri(self): - """URI pointing to application's manual""" - return None - - @abc.abstractproperty - def ini_file(self): - """Path to application's default INI file with settings""" - return None - - @abc.abstractproperty - def extra_catalog_widgets(self): - """Path to application's custom logo file""" - return [] - - @abc.abstractproperty - def synoptics(self): - """Sequence of paths to synoptic files""" - return [] - - @abc.abstractproperty - def panels(self): - """List of custom panels with widgets""" - return [] - - @abc.abstractproperty - def toolbars(self): - """List of custom toolbars""" - return [] - - @abc.abstractproperty - def applets(self): - """List of custom applets""" - return [] - - @abc.abstractproperty - def external_apps(self): - """List of external applications""" - return [] + return {} diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 37223b277..5a14aa0ee 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -82,90 +82,16 @@ def load(self): "Problem with config file decoding: " + str(e) ) - @property - def conf_dir(self): - return os.path.abspath(os.path.dirname(self._confname)) - - @property - def app_name(self): - return self._data.get("GUI_NAME") - - @property - def org_name(self): - return self._data.get("ORGANIZATION") - - @property - def custom_logo(self): - return self._data.get("CUSTOM_LOGO") - - @property - def org_logo(self): - return self._data.get("ORGANIZATION_LOGO") - - @property - def single_instance(self): - return self._data.get("SINGE_INSTANCE") - - @property - def manual_uri(self): - return self._data.get("MANUAL_URI") - - @property - def ini_file(self): - return self._data.get("INIFILE") - - @property - def extra_catalog_widgets(self): - return self._data.get("EXTRA_CATALOG_WIDGETS", []) - - @property - def synoptics(self): - return self._data.get("SYNOPTIC", []) - - @property - def console(self): - return self._data.get("CONSOLE") - - @property - def monitor(self): - return AppletDescription( - "monitor", - classname="TaurusMonitorTiny", - model=self._data.get("MONITOR"), - ) - - @property - def panels(self): - return self._get_objects(PanelDescription) - - @property - def toolbars(self): - return self._get_objects(ToolBarDescription) - - @property - def applets(self): - return self._get_objects(AppletDescription) - - @property - def external_apps(self): - return self._get_objects(ExternalApp) - - @property - def macroserver_name(self): - return self._data.get("MACROSERVER_NAME") - - @property - def macro_panels(self): - return self._data.get("MACRO_PANELS") - - @property - def door_name(self): - return self._data.get("DOOR_NAME") - - @property - def macroeditors_path(self): - return self._data.get("MACROEDITORS_PATH") - - @property - def instruments_from_pool(self): - return self._data.get("INSTRUMENTS_FROM_POOL") + tmp = {} + + for v in self.CONFIG_VALUES: + if v in self._data: + tmp[v] = self._data[v] + + for klass in (PanelDescription, ToolBarDescription, AppletDescription, ExternalApp): + tmp[klass.__name__ + "s"] = self._get_objects(klass) + self._data.update(tmp) + + self._data["CONF_DIR"] = os.path.abspath(os.path.dirname(self._confname)) + + return self._data diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 9cb3457dd..521a7842c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -136,90 +136,14 @@ def load(self): else: # if confname is not a dir name, we assume it is a module name in the python path self._mod = self._importConfiguration() - @property - def conf_dir(self): - return os.path.abspath(os.path.dirname(self._mod.__file__)) - - @property - def app_name(self): - return getattr(self._mod, "GUI_NAME", None) - - @property - def org_name(self): - return getattr(self._mod, "ORGANIZATION", None) - - @property - def custom_logo(self): - return getattr(self._mod, "CUSTOM_LOGO", None) - - @property - def org_logo(self): - return getattr(self._mod, "ORGANIZATION_LOGO", None) - - @property - def single_instance(self): - return getattr(self._mod, "SINGLE_INSTANCE", None) - - @property - def manual_uri(self): - return getattr(self._mod, "MANUAL_URI", None) - - @property - def ini_file(self): - return getattr(self._mod, "INIFILE", None) - - @property - def extra_catalog_widgets(self): - return getattr(self._mod, "EXTRA_CATALOG_WIDGETS", []) - - @property - def synoptics(self): - return getattr(self._mod, "SYNOPTIC", []) - - @property - def console(self): - return getattr(self._mod, "CONSOLE", []) - - @property - def monitor(self): - return AppletDescription( - "monitor", - classname="TaurusMonitorTiny", - model=getattr(self._mod, "MONITOR"), - ) - - @property - def panels(self): - return self._get_objects(PanelDescription) - - @property - def toolbars(self): - return self._get_objects(ToolBarDescription) - - @property - def applets(self): - return self._get_objects(AppletDescription) - - @property - def external_apps(self): - return self._get_objects(ExternalApp) - - @property - def macroserver_name(self): - return getattr(self._mod, "MACROSERVER_NAME", None) - - @property - def macro_panels(self): - return getattr(self._mod, "MACRO_PANELS", None) - - @property - def door_name(self): - return getattr(self._mod, "DOOR_NAME", None) - - @property - def macroeditors_path(self): - return getattr(self._mod, "MACROEDITORS_PATH", None) - - @property - def instruments_from_pool(self): - return getattr(self._mod, "INSTRUMENTS_FROM_POOL", None) + tmp = {} + tmp["CONF_DIR"] = os.path.abspath(os.path.dirname(self._mod.__file__)) + + for v in self.CONFIG_VALUES: + if hasattr(self._mod, v): + tmp[v] = getattr(self._mod, v) + + for klass in (PanelDescription, AppletDescription, ToolBarDescription, ExternalApp): + tmp[klass.__name__ + "s"] = self._get_objects(klass) + + return tmp diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index 64e6b9e94..bf7499b0c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -99,44 +99,19 @@ def load(self): msg = 'Error reading the XML file: "%s"' % self._confname raise ConfigLoaderError(msg) - @property - def conf_dir(self): - return os.path.abspath(os.path.dirname(self._confname)) - - @property - def app_name(self): - return self._get("GUI_NAME") - - @property - def org_name(self): - return self._get("ORGANIZATION") + tmp = {} - @property - def custom_logo(self): - return self._get("CUSTOM_LOGO") + for v in self.CONFIG_VALUES: + name = self._root.find(v) + if name is not None and name.text is not None: + tmp[v] = name.text - @property - def org_logo(self): - return self._get("ORGANIZATION_LOGO") + for klass in (PanelDescription, ToolBarDescription, AppletDescription, ExternalApp): + tmp[klass.__name__ + "s"] = self._get_objects(klass) - @property - def single_instance(self): - return self._get("SINGLE_INSTANCE") + tmp["CONF_DIR"] = os.path.abspath(os.path.dirname(self._confname)) - @property - def manual_uri(self): - return self._get("MANUAL_URI") - - @property - def ini_file(self): - return self._get("INIFILE") - - @property - def extra_catalog_widgets(self): - """ - Not implemented for now - """ - return [] + return tmp @property def synoptics(self): @@ -149,51 +124,3 @@ def synoptics(self): if s: synoptic.append(s) return synoptic - - @property - def console(self): - return self._get("CONSOLE") - - @property - def monitor(self): - return AppletDescription( - "monitor", - classname="TaurusMonitorTiny", - model=self._get("MONITOR"), - ) - - @property - def panels(self): - return self._get_objects(PanelDescription) - - @property - def toolbars(self): - return self._get_objects(ToolBarDescription) - - @property - def applets(self): - return self._get_objects(AppletDescription) - - @property - def external_apps(self): - return self._get_objects(ExternalApp) - - @property - def macroserver_name(self): - return self._get("MACROSERVER_NAME") - - @property - def macro_panels(self): - return self._get("MACRO_PANELS") - - @property - def door_name(self): - return self._get("DOOR_NAME") - - @property - def macroeditors_path(self): - return self._get("MACROEDITORS_PATH") - - @property - def instruments_from_pool(self): - return self._get("INSTRUMENTS_FROM_POOL") From 204a84d55d1db63cd64b2215df503ac45d9ac06e Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 21:31:21 +0200 Subject: [PATCH 42/99] Split logic responsible for loading data from formatting data --- lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py | 5 ++++- lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py | 5 ++++- lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 5a14aa0ee..39a5526d1 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -69,7 +69,7 @@ def supports(confname): return True return False - def load(self): + def _get_data(self): try: with open(self._confname, "r") as fp: self._data = json.load(fp) @@ -82,6 +82,9 @@ def load(self): "Problem with config file decoding: " + str(e) ) + def load(self): + self._get_data() + tmp = {} for v in self.CONFIG_VALUES: diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 521a7842c..65a1ed0b0 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -106,7 +106,7 @@ def supports(confname): return True return False - def load(self): + def _get_data(self): """Reads a configuration file :param confname: (str or None) the name of module located in the @@ -136,6 +136,9 @@ def load(self): else: # if confname is not a dir name, we assume it is a module name in the python path self._mod = self._importConfiguration() + def load(self): + self._get_data() + tmp = {} tmp["CONF_DIR"] = os.path.abspath(os.path.dirname(self._mod.__file__)) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index bf7499b0c..5aeb0259c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -84,7 +84,7 @@ def supports(confname): return True return False - def load(self): + def _get_data(self): """ Get the xml root node from the xml configuration file """ @@ -99,6 +99,9 @@ def load(self): msg = 'Error reading the XML file: "%s"' % self._confname raise ConfigLoaderError(msg) + def load(self): + self._get_data() + tmp = {} for v in self.CONFIG_VALUES: From 94ba5abd39ac6ec4809f6129d1885f87950443e8 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 21:43:54 +0200 Subject: [PATCH 43/99] Update loading values from configuration --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 74628d3e3..e3d200616 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -975,19 +975,19 @@ def createInstrumentsFromPool(self, macroservername): return ret def getConfigValue(self, conf, field, default=None): - value = getattr(conf, field) - if value is None: - return default - else: - return value + return conf.get(field, default) def loadConfiguration(self, confname): '''Reads a configuration file ''' + conf = {} try: - conf = getLoader(confname) - conf.load() - self._confDirectory = conf.conf_dir + for loader in getLoader(confname): + conf.update(loader.load()) + if "CONF_DIR" in conf: + self._confDirectory = conf["CONF_DIR"] + else: + self._confDirectory = os.path.expanduser("~") except Exception: import traceback msg = 'Error loading configuration: %s' % traceback.format_exc() # repr(e) @@ -1018,16 +1018,16 @@ def loadConfiguration(self, confname): self._loadIniFile(conf) def _loadAppName(self, conf, confname): - appname = self.getConfigValue(conf, "app_name") + appname = self.getConfigValue(conf, "GUI_NAME") Qt.qApp.setApplicationName(appname) self.setWindowTitle(appname) def _loadOrgName(self, conf): - orgname = self.getConfigValue(conf, "org_name", str(Qt.qApp.organizationName()) or 'Taurus') + orgname = self.getConfigValue(conf, "ORGANIZATION", str(Qt.qApp.organizationName()) or 'Taurus') Qt.qApp.setOrganizationName(orgname) def _loadCustomLogo(self, conf): - custom_logo = self.getConfigValue(conf, "custom_logo", 'logos:taurus.png') + custom_logo = self.getConfigValue(conf, "CUSTOM_LOGO", 'logos:taurus.png') if Qt.QFile.exists(custom_logo): custom_icon = Qt.QIcon(custom_logo) else: @@ -1041,7 +1041,7 @@ def _loadOrgLogo(self, conf): logo = getattr(tauruscustomsettings, "ORGANIZATION_LOGO", "logos:taurus.png") - org_logo = self.getConfigValue(conf, "org_logo", logo) + org_logo = self.getConfigValue(conf, "ORGANIZATION_LOGO", logo) if Qt.QFile.exists(org_logo): org_icon = Qt.QIcon(org_logo) else: @@ -1054,7 +1054,7 @@ def _loadSingleInstance(self, conf): """ if required, enforce that only one instance of this GUI can be run """ - single_inst = self.getConfigValue(conf, "single_instance", True) + single_inst = self.getConfigValue(conf, "SINGLE_INSTANCE", True) if single_inst: if not self.checkSingleInstance(): @@ -1070,7 +1070,7 @@ def _loadExtraCatalogWidgets(self, conf): get custom widget catalog entries """ # @todo: support also loading from xml - extra_catalog_widgets = self.getConfigValue(conf, "extra_catalog_widgets", []) + extra_catalog_widgets = self.getConfigValue(conf, "EXTRA_CATALOG_WIDGETS", []) self._extraCatalogWidgets = [] for class_name, pix_map_name in extra_catalog_widgets: # If a relative file name is given, the conf directory will be used @@ -1083,7 +1083,7 @@ def _loadManualUri(self, conf): """ manual panel """ - manual_uri = self.getConfigValue(conf, "manual_uri", taurus.Release.url) + manual_uri = self.getConfigValue(conf, "MANUAL_URI", taurus.Release.url) self.setHelpManualURI(manual_uri) if self.HELP_MENU_ENABLED: @@ -1145,7 +1145,7 @@ def _loadInstrumentsFromPool(self, conf, macro_server_name): def _loadSynoptic(self, conf): # Synoptics - synoptic = self.getConfigValue(conf, "synoptic", []) + synoptic = self.getConfigValue(conf, "SYNOPTIC", []) if isinstance(synoptic, string_types): # old config file style self.warning( 'Deprecated usage of synoptic keyword (now it expects a list of paths). Please update your configuration file to: "synoptic=[\'%s\']".' % synoptic) @@ -1169,7 +1169,7 @@ def _loadCustomPanels(self, conf, poolinstruments=None): create panels based on the panel descriptions """ - custom_panels = conf.panels + custom_panels = conf["PanelDescriptions"] for p in custom_panels + poolinstruments: try: @@ -1244,7 +1244,7 @@ def _loadCustomToolBars(self, conf): get custom toolbars descriptions from the python config file, xml config and create toolbars based on the descriptions """ - for d in conf.toolbars: + for d in conf["ToolbarDescriptinos"]: try: try: self.splashScreen().showMessage("Creating Toolbar %s" % d.name) @@ -1277,7 +1277,7 @@ def _loadCustomApplets(self, conf): get custom applet descriptions from the python config file, xml config and create applet based on the descriptions """ - custom_applets = conf.applets[:] + custom_applets = conf.["AppletDescriptions"][:] # for backwards compatibility monitor = self.getConfigValue(conf, "monitor", []) if monitor: @@ -1311,7 +1311,7 @@ def _loadExternalApps(self, conf): """ add external applications from both the python and the xml config files """ - for a in conf.external_apps: + for a in conf["ExternalApps"]: self._external_app_names.append(str(a.getAction().text())) self.addExternalAppLauncher(a.getAction()) @@ -1320,7 +1320,7 @@ def _loadIniFile(self, conf): get the "factory settings" filename. By default, it is called "default.ini" and resides in the configuration dir """ - ini_file = self.getConfigValue(conf, "ini_file", "default.ini") + ini_file = self.getConfigValue(conf, "INIFILE", "default.ini") # if a relative name is given, the conf dir is used as the root path ini_file_name = os.path.join(self._confDirectory, ini_file) From d98275fc06736e4454a28b5be658a87c7c20fbb1 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 22:09:47 +0200 Subject: [PATCH 44/99] Add BckCompatConfigLoader --- .../taurusgui/config_loader/back_compat.py | 63 +++++++++++++++++++ setup.py | 1 + 2 files changed, 64 insertions(+) create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py new file mode 100644 index 000000000..2524b9318 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -0,0 +1,63 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + +"""""" + +from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( + AbstractConfigLoader, +) +from taurus.qt.qtgui.taurusgui.config_loader.pyconf import ( + PyConfigLoader +) +from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import ( + XmlConfigLoader +) + +__all__ = ["BckCompatConfigLoader"] + + +class BckCompatConfigLoader(AbstractConfigLoader): + """ + Config loader which provides backward compatibility + """ + + DEPRECATED_VALUES = ["MONITOR", "CONSOLE"] + + @staticmethod + def supports(confname): + return PyConfigLoader.supports(confname) or XmlConfigLoader.supports(confname) + + def load(self): + tmp = {} + + if PyConfigLoader.supports(self._confname): + py = PyConfigLoader(self._confname) + py.CONFIG_VALUES + self.DEPRECATED_VALUES + tmp.update(py.load()) + + if XmlConfigLoader.supports(self._confname): + xml = XmlConfigLoader(self._confname) + xml.CONFIG_VALUES + self.DEPRECATED_VALUES + tmp.update(xml.load()) + + return tmp diff --git a/setup.py b/setup.py index 782138d07..59e8379b0 100644 --- a/setup.py +++ b/setup.py @@ -129,6 +129,7 @@ def get_release_info(): 'taurus.py = taurus.qt.qtgui.taurusgui.config_loader.pyconf:PyConfigLoader', 'taurus.json = taurus.qt.qtgui.taurusgui.config_loader.jsonconf:JsonConfigLoader', 'taurus.xml = taurus.qt.qtgui.taurusgui.config_loader.xmlconf:XmlConfigLoader', + 'taurus.bck_compat = taurus.qt.qtgui.taurusgui.config_loader.back_compat:BckCompatConfigLoader', ] entry_points = { From fc8d1e23282fb04e2e77cc8b494727432e2a5e43 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 22:16:15 +0200 Subject: [PATCH 45/99] Add config loader for Sardana --- .../qtgui/taurusgui/config_loader/sardana.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py new file mode 100644 index 000000000..5b6bb4545 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -0,0 +1,64 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + +"""""" + +from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( + AbstractConfigLoader, +) +from taurus.qt.qtgui.taurusgui.config_loader.pyconf import ( + PyConfigLoader +) +from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import ( + XmlConfigLoader +) + +__all__ = ["SardanaConfigLoader"] + + +class SardanaConfigLoader(AbstractConfigLoader): + """ + Config loader which loads Sardana-related values. + This lives as a hack for manupulating AbstracLoader.CONFIG_VALUES. + It does not laod anything by itself, just injects new values into + CONFIG_VALUES so other laoders will load them. + """ + + SARDANA_VALUES = [ + "MACROSERVER_NAME", + "MACRO_PANELS", + "DOOR_NAME", + "MACROEDITORS_PATH", + "INSTRUMENTS_FROM_POOL", + ] + + def __init__(self, confname): + super(SardanaConfigLoader, self).__init__(confname) + AbstractConfigLoader.CONFIG_VALUES + self.SARDANA_VALUES + + @staticmethod + def supports(confname): + return False + + def load(self): + return {} From 435e250efd593226d76361a67835eca5c3506653 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 22:18:24 +0200 Subject: [PATCH 46/99] Allow loading deprecated and Sardana-related config values --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index e3d200616..5a0de8e05 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -1105,21 +1105,21 @@ def _loadSardanaOptions(self, conf): return pool_instruments def _loadMacroServerName(self, conf): - macro_server_name = self.getConfigValue(conf, "macroserver_name") + macro_server_name = self.getConfigValue(conf, "MACROSERVER_NAME") if macro_server_name: self.macroserverNameChanged.emit(macro_server_name) return macro_server_name def _loadMacroPanels(self, conf): - return self.getConfigValue(conf, "macro_panels", True) + return self.getConfigValue(conf, "MACRO_PANELS", True) def _loadDoorName(self, conf): - door_name = self.getConfigValue(conf, "door_name", True) + door_name = self.getConfigValue(conf, "DOOR_NAME", True) if door_name: self.doorNameChanged.emit(door_name) def _loadMacroEditorsPath(self, conf): - macro_editors_path = self.getConfigValue(conf, "macroeditors_path", True) + macro_editors_path = self.getConfigValue(conf, "MACRO_EDITORS_PATH", True) if macro_editors_path: from sardana.taurus.qt.qtgui.extra_macroexecutor.macroparameterseditor.macroparameterseditor import \ ParamEditorManager @@ -1130,7 +1130,7 @@ def _loadInstrumentsFromPool(self, conf, macro_server_name): """ Get panel descriptions from pool if required """ - instruments_from_pool = self.getConfigValue(conf, "instruments_from_pool", False) + instruments_from_pool = self.getConfigValue(conf, "INSTRUMENTS_FROM_POOL", False) if instruments_from_pool: try: self.splashScreen().showMessage("Gathering Instrument info from Pool") @@ -1159,7 +1159,7 @@ def _loadConsole(self, conf): Panel with a `silx.gui.console.IPythonWidget` """ # TODO: remove this method when making deprecation efective - console = self.getConfigValue(conf, "console", []) + console = self.getConfigValue(conf, "CONSOLE", []) if console: self.createConsole([]) @@ -1279,7 +1279,7 @@ def _loadCustomApplets(self, conf): """ custom_applets = conf.["AppletDescriptions"][:] # for backwards compatibility - monitor = self.getConfigValue(conf, "monitor", []) + monitor = self.getConfigValue(conf, "MONITOR", []) if monitor: custom_applets.append(monitor) From e48b285e318ab91792646e2fb4b0226e63df8732 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 22:18:39 +0200 Subject: [PATCH 47/99] Fix syntax --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 5a0de8e05..476874a6b 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -1277,7 +1277,7 @@ def _loadCustomApplets(self, conf): get custom applet descriptions from the python config file, xml config and create applet based on the descriptions """ - custom_applets = conf.["AppletDescriptions"][:] + custom_applets = conf["AppletDescriptions"][:] # for backwards compatibility monitor = self.getConfigValue(conf, "MONITOR", []) if monitor: From 16a41b79893380cc8e773965b442e4f67913bdce Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 22:25:53 +0200 Subject: [PATCH 48/99] Add hooks list to abstract interface --- lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py | 9 +++++++++ .../qt/qtgui/taurusgui/config_loader/back_compat.py | 4 ++++ lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py | 4 ++++ lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py | 4 ++++ lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py | 4 ++++ lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py | 4 ++++ 6 files changed, 29 insertions(+) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 76c296cee..2be6737e3 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -78,3 +78,12 @@ def load(self): Return dictionary with configuration. """ return {} + + @abc.abstractproperty + def hooks(self): + """ + List of hooks called at the end of 'TaurusGui.loadConfiguration' + method. Each of them shall be called with 'TaurusGui' instance as + first argument and dictionary with configuration as second. + """ + return [] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py index 2524b9318..3afb14c10 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -61,3 +61,7 @@ def load(self): tmp.update(xml.load()) return tmp + + @property + def hooks(self): + return [] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 39a5526d1..c7a6d0d89 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -98,3 +98,7 @@ def load(self): self._data["CONF_DIR"] = os.path.abspath(os.path.dirname(self._confname)) return self._data + + @property + def hooks(self): + return [] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 65a1ed0b0..41a6032dc 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -150,3 +150,7 @@ def load(self): tmp[klass.__name__ + "s"] = self._get_objects(klass) return tmp + + @property + def hooks(self): + return [] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index 5b6bb4545..9eefbbf92 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -62,3 +62,7 @@ def supports(confname): def load(self): return {} + + @property + def hooks(self): + return [] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index 5aeb0259c..d19411e99 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -127,3 +127,7 @@ def synoptics(self): if s: synoptic.append(s) return synoptic + + @property + def hooks(self): + return [] From 42689bad09f2c40db0b417be1f5565449a196ffc Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 22:51:28 +0200 Subject: [PATCH 49/99] Add hooks for backward compatible changes --- .../taurusgui/config_loader/back_compat.py | 59 ++++++++++++++++++- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 33 +---------- 2 files changed, 59 insertions(+), 33 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py index 3afb14c10..3011d9fd9 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -22,7 +22,11 @@ ########################################################################### """""" +import sys +import taurus +from taurus.external.qt import Qt +from taurus.qt.qtgui.taurusgui.utils import AppletDescription from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( AbstractConfigLoader, ) @@ -64,4 +68,57 @@ def load(self): @property def hooks(self): - return [] + return self.loadConsole, self.loadMonitor + + @staticmethod + def loadMonitor(gui, conf): + monitor_model = gui.getConfigValue(conf, "MONITOR") + if monitor_model is None: + return + + try: + try: + gui.splashScreen().showMessage("Creating applet monitor") + except AttributeError: + pass + + from taurus.qt.qtgui.qwt5.monitor import TaurusMonitorTiny + + w = TaurusMonitorTiny() + w.setModel(monitor_model) + # add the widget to the applets toolbar + gui.jorgsBar.addWidget(w) + # register the toolbar as delegate + gui.registerConfigDelegate(w, "monitor") + except Exception as e: + msg = "Cannot add applet 'monitor'" + gui.error(msg) + gui.traceback(level=taurus.Info) + result = Qt.QMessageBox.critical(gui, "Initialization error", "%s\n\n%s" % ( + msg, repr(e)), Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore) + if result == Qt.QMessageBox.Abort: + sys.exit() + + @staticmethod + def loadConsole(gui, conf): + """ + Deprecated CONSOLE command (if you need a IPython Console, just add a + Panel with a `silx.gui.console.IPythonWidget` + """ + # TODO: remove this method when making deprecation efective + if not gui.getConfigValue(conf, "CONSOLE", []): + return + + msg = ('createConsole() and the "CONSOLE" configuration key are ' + + 'deprecated since 4.0.4. Add a panel with a ' + + 'silx.gui.console.IPythonWidget widdget instead') + gui.deprecated(msg) + try: + from silx.gui.console import IPythonWidget + except ImportError: + gui.warning('Cannot import taurus.qt.qtgui.console. ' + + 'The Console Panel will not be available') + return + console = IPythonWidget() + gui.createPanel(console, "Console", permanent=True, + icon=Qt.QIcon.fromTheme('utilities-terminal')) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 476874a6b..7926269b9 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -906,21 +906,6 @@ def createMainSynoptic(self, synopticname): toggleSynopticAction = synopticpanel.toggleViewAction() self.quickAccessToolBar.addAction(toggleSynopticAction) - def createConsole(self, kernels): - msg = ('createConsole() and the "CONSOLE" configuration key are ' + - 'deprecated since 4.0.4. Add a panel with a ' + - 'silx.gui.console.IPythonWidget widdget instead') - self.deprecated(msg) - try: - from silx.gui.console import IPythonWidget - except ImportError: - self.warning('Cannot import taurus.qt.qtgui.console. ' + - 'The Console Panel will not be available') - return - console = IPythonWidget() - self.createPanel(console, "Console", permanent=True, - icon=Qt.QIcon.fromTheme('utilities-terminal')) - def createInstrumentsFromPool(self, macroservername): ''' Creates a list of instrument panel descriptions by gathering the info @@ -1153,16 +1138,6 @@ def _loadSynoptic(self, conf): for s in synoptic: self.createMainSynoptic(s) - def _loadConsole(self, conf): - """ - Deprecated CONSOLE command (if you need a IPython Console, just add a - Panel with a `silx.gui.console.IPythonWidget` - """ - # TODO: remove this method when making deprecation efective - console = self.getConfigValue(conf, "CONSOLE", []) - if console: - self.createConsole([]) - def _loadCustomPanels(self, conf, poolinstruments=None): """ get custom panel descriptions from the python config file, xml config and @@ -1277,13 +1252,7 @@ def _loadCustomApplets(self, conf): get custom applet descriptions from the python config file, xml config and create applet based on the descriptions """ - custom_applets = conf["AppletDescriptions"][:] - # for backwards compatibility - monitor = self.getConfigValue(conf, "MONITOR", []) - if monitor: - custom_applets.append(monitor) - - for d in custom_applets: + for d in conf["AppletDescriptions"]: try: try: self.splashScreen().showMessage("Creating applet %s" % d.name) From 3b566445065d0a0d103a656bd7a1e6b598e524a8 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 23:36:39 +0200 Subject: [PATCH 50/99] Add Sardana custom laoder with hooks --- .../qtgui/taurusgui/config_loader/sardana.py | 122 +++++++++++++++++- 1 file changed, 115 insertions(+), 7 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index 9eefbbf92..7b6bcbe04 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -23,15 +23,15 @@ """""" +import sys + +import taurus +from taurus.external.qt import Qt +from taurus.qt.qtgui.taurusgui.utils import PanelDescription from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( AbstractConfigLoader, ) -from taurus.qt.qtgui.taurusgui.config_loader.pyconf import ( - PyConfigLoader -) -from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import ( - XmlConfigLoader -) + __all__ = ["SardanaConfigLoader"] @@ -65,4 +65,112 @@ def load(self): @property def hooks(self): - return [] + return self._loadMacroServerName, self._loadMacroBroker, self._loadDoorName, self._loadMacroEditorsPath, self._loadInstrumentsFromPool + + @staticmethod + def _loadMacroServerName(gui, conf): + macro_server_name = gui.getConfigValue(conf, "MACROSERVER_NAME") + if macro_server_name: + gui.macroserverNameChanged.emit(macro_server_name) + return macro_server_name + + @staticmethod + def _loadMacroBroker(gui, conf): + """configure macro infrastructure""" + ms = gui.getConfigValue(conf, "MACROSERVER_NAME") + mp = gui.getConfigValue(conf, "MACRO_PANELS", True) + # macro infrastructure will only be created if MACROSERVER_NAME is set + if ms is not None and mp is True: + from sardana.taurus.qt.qtgui.macrolistener import MacroBroker + gui.__macroBroker = MacroBroker(gui) + + @staticmethod + def _loadDoorName(gui, conf): + door_name = gui.getConfigValue(conf, "DOOR_NAME", True) + if door_name: + gui.doorNameChanged.emit(door_name) + + @staticmethod + def _loadMacroEditorsPath(gui, conf): + macro_editors_path = gui.getConfigValue(conf, "MACRO_EDITORS_PATH", True) + if macro_editors_path: + from sardana.taurus.qt.qtgui.extra_macroexecutor.macroparameterseditor.macroparameterseditor import \ + ParamEditorManager + ParamEditorManager().parsePaths(macro_editors_path) + ParamEditorManager().browsePaths() + + def _loadInstrumentsFromPool(self, gui, conf): + """ + Get panel descriptions from pool if required + """ + #todo: needs heavy refactor + ms = gui.getConfigValue(conf, "MACROSERVER_NAME") + + instruments_from_pool = gui.getConfigValue(conf, "INSTRUMENTS_FROM_POOL", False) + if instruments_from_pool: + try: + gui.splashScreen().showMessage("Gathering Instrument info from Pool") + except AttributeError: + pass + pool_instruments = self.createInstrumentsFromPool(ms) # auto create instruments from pool + else: + pool_instruments = [] + + if pool_instruments: + gui._loadCustomPanels(conf, pool_instruments) + return pool_instruments + + @staticmethod + def createInstrumentsFromPool(gui, macroservername): + ''' + Creates a list of instrument panel descriptions by gathering the info + from the Pool. Each panel is a TaurusForm grouping together all those + elements that belong to the same instrument according to the Pool info + + :return: (list) + ''' + #todo: needs heavy refactor + instrument_dict = {} + try: + ms = taurus.Device(macroservername) + instruments = ms.getElementsOfType('Instrument') + if instruments is None: + raise Exception() + except Exception as e: + msg = 'Could not fetch Instrument list from "%s"' % macroservername + gui.error(msg) + result = Qt.QMessageBox.critical(gui, 'Initialization error', '%s\n\n%s' % ( + msg, repr(e)), Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore) + if result == Qt.QMessageBox.Abort: + sys.exit() + return [] + for i in instruments.values(): + i_name = i.full_name + #i_name, i_unknown, i_type, i_pools = i.split() + i_view = PanelDescription( + i_name, classname='TaurusForm', floating=False, model=[]) + instrument_dict[i_name] = i_view + + from operator import attrgetter + pool_elements = sorted(ms.getElementsWithInterface( + 'Moveable').values(), key=attrgetter('name')) + pool_elements += sorted(ms.getElementsWithInterface( + 'ExpChannel').values(), key=attrgetter('name')) + pool_elements += sorted(ms.getElementsWithInterface( + 'IORegister').values(), key=attrgetter('name')) + for elem in pool_elements: + instrument = elem.instrument + if instrument: + i_name = instrument + # ----------------------------------------------------------- + # Support sardana v<2.4 (which used tango names instead of + # taurus full names + e_name = elem.full_name + if not e_name.startswith("tango://"): + e_name = "tango://%s" % e_name + # ----------------------------------------------------------- + instrument_dict[i_name].model.append(e_name) + # filter out empty panels + ret = [instrument for instrument in instrument_dict.values() + if len(instrument.model) > 0] + return ret From 5b5992802abb0447d7cbf3f08e163026c710e3eb Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 23:39:27 +0200 Subject: [PATCH 51/99] Update _loadCustomPanels method to laod panels from configuration or Pool instruments --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 7926269b9..c43ec0716 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -1143,10 +1143,12 @@ def _loadCustomPanels(self, conf, poolinstruments=None): get custom panel descriptions from the python config file, xml config and create panels based on the panel descriptions """ + if poolinstruments is None: + custom_panels = conf["PanelDescriptions"] + else: + custom_panels = poolinstruments - custom_panels = conf["PanelDescriptions"] - - for p in custom_panels + poolinstruments: + for p in custom_panels: try: try: self.splashScreen().showMessage("Creating panel %s" % p.name) @@ -1192,7 +1194,8 @@ def _loadCustomPanels(self, conf, poolinstruments=None): icon = p.icon # the pool instruments may change when the pool config changes, # so we do not store their config - registerconfig = p not in poolinstruments + if poolinstruments is None: + registerconfig = False # create a panel self.createPanel( From a97404ecbfdfc94841cac21b086693a1dcebe5df Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 23:40:51 +0200 Subject: [PATCH 52/99] Remove Sardana-related config loader methods --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 111 +-------------------- 1 file changed, 1 insertion(+), 110 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index c43ec0716..8833850cb 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -906,59 +906,6 @@ def createMainSynoptic(self, synopticname): toggleSynopticAction = synopticpanel.toggleViewAction() self.quickAccessToolBar.addAction(toggleSynopticAction) - def createInstrumentsFromPool(self, macroservername): - ''' - Creates a list of instrument panel descriptions by gathering the info - from the Pool. Each panel is a TaurusForm grouping together all those - elements that belong to the same instrument according to the Pool info - - :return: (list) - ''' - instrument_dict = {} - try: - ms = taurus.Device(macroservername) - instruments = ms.getElementsOfType('Instrument') - if instruments is None: - raise Exception() - except Exception as e: - msg = 'Could not fetch Instrument list from "%s"' % macroservername - self.error(msg) - result = Qt.QMessageBox.critical(self, 'Initialization error', '%s\n\n%s' % ( - msg, repr(e)), Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore) - if result == Qt.QMessageBox.Abort: - sys.exit() - return [] - for i in instruments.values(): - i_name = i.full_name - #i_name, i_unknown, i_type, i_pools = i.split() - i_view = PanelDescription( - i_name, classname='TaurusForm', floating=False, model=[]) - instrument_dict[i_name] = i_view - - from operator import attrgetter - pool_elements = sorted(ms.getElementsWithInterface( - 'Moveable').values(), key=attrgetter('name')) - pool_elements += sorted(ms.getElementsWithInterface( - 'ExpChannel').values(), key=attrgetter('name')) - pool_elements += sorted(ms.getElementsWithInterface( - 'IORegister').values(), key=attrgetter('name')) - for elem in pool_elements: - instrument = elem.instrument - if instrument: - i_name = instrument - # ----------------------------------------------------------- - # Support sardana v<2.4 (which used tango names instead of - # taurus full names - e_name = elem.full_name - if not e_name.startswith("tango://"): - e_name = "tango://%s" % e_name - # ----------------------------------------------------------- - instrument_dict[i_name].model.append(e_name) - # filter out empty panels - ret = [instrument for instrument in instrument_dict.values() - if len(instrument.model) > 0] - return ret - def getConfigValue(self, conf, field, default=None): return conf.get(field, default) @@ -991,12 +938,9 @@ def loadConfiguration(self, confname): self._loadExtraCatalogWidgets(conf) self._loadManualUri(conf) - POOLINSTRUMENTS = self._loadSardanaOptions(conf) self._loadSynoptic(conf) - # TODO: remove deprecated _loadConsole - self._loadConsole(conf) - self._loadCustomPanels(conf, POOLINSTRUMENTS) + self._loadCustomPanels(conf) self._loadCustomToolBars(conf) self._loadCustomApplets(conf) self._loadExternalApps(conf) @@ -1074,59 +1018,6 @@ def _loadManualUri(self, conf): if self.HELP_MENU_ENABLED: self.createPanel(self.helpManualBrowser, 'Manual', permanent=True, icon=Qt.QIcon.fromTheme('help-browser')) - - ### SARDANA MACRO STUFF ON - def _loadSardanaOptions(self, conf): - """configure macro infrastructure""" - ms = self._loadMacroServerName(conf) - mp = self._loadMacroPanels(conf) - # macro infrastructure will only be created if MACROSERVER_NAME is set - if ms is not None and mp is True: - from sardana.taurus.qt.qtgui.macrolistener import MacroBroker - self.__macroBroker = MacroBroker(self) - self._loadDoorName(conf) - self._loadMacroEditorsPath(conf) - pool_instruments = self._loadInstrumentsFromPool(conf, ms) - return pool_instruments - - def _loadMacroServerName(self, conf): - macro_server_name = self.getConfigValue(conf, "MACROSERVER_NAME") - if macro_server_name: - self.macroserverNameChanged.emit(macro_server_name) - return macro_server_name - - def _loadMacroPanels(self, conf): - return self.getConfigValue(conf, "MACRO_PANELS", True) - - def _loadDoorName(self, conf): - door_name = self.getConfigValue(conf, "DOOR_NAME", True) - if door_name: - self.doorNameChanged.emit(door_name) - - def _loadMacroEditorsPath(self, conf): - macro_editors_path = self.getConfigValue(conf, "MACRO_EDITORS_PATH", True) - if macro_editors_path: - from sardana.taurus.qt.qtgui.extra_macroexecutor.macroparameterseditor.macroparameterseditor import \ - ParamEditorManager - ParamEditorManager().parsePaths(macro_editors_path) - ParamEditorManager().browsePaths() - - def _loadInstrumentsFromPool(self, conf, macro_server_name): - """ - Get panel descriptions from pool if required - """ - instruments_from_pool = self.getConfigValue(conf, "INSTRUMENTS_FROM_POOL", False) - if instruments_from_pool: - try: - self.splashScreen().showMessage("Gathering Instrument info from Pool") - except AttributeError: - pass - pool_instruments = self.createInstrumentsFromPool( - macro_server_name) # auto create instruments from pool - else: - pool_instruments = [] - return pool_instruments - ### SARDANA MACRO STUFF OFF def _loadSynoptic(self, conf): # Synoptics From b883df647eadc1157c566b93a821d4d5e81a427a Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 23:42:14 +0200 Subject: [PATCH 53/99] Execute registered config loader hooks --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 8833850cb..da1427851 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -914,7 +914,8 @@ def loadConfiguration(self, confname): ''' conf = {} try: - for loader in getLoader(confname): + loaders = getLoader(confname) + for loader in loaders: conf.update(loader.load()) if "CONF_DIR" in conf: self._confDirectory = conf["CONF_DIR"] @@ -946,6 +947,10 @@ def loadConfiguration(self, confname): self._loadExternalApps(conf) self._loadIniFile(conf) + for loader in loaders: + for hook in loader.hooks: + hook(self, conf) + def _loadAppName(self, conf, confname): appname = self.getConfigValue(conf, "GUI_NAME") Qt.qApp.setApplicationName(appname) From b8910fbcea9172b283d171a01cd78dabc2da3200 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 23:50:28 +0200 Subject: [PATCH 54/99] PEP8 --- .../qtgui/taurusgui/config_loader/__init__.py | 1 - .../taurusgui/config_loader/back_compat.py | 44 ++++++---- .../qtgui/taurusgui/config_loader/jsonconf.py | 25 +++--- .../qtgui/taurusgui/config_loader/pyconf.py | 23 +++-- .../qtgui/taurusgui/config_loader/sardana.py | 88 +++++++++++++------ .../qtgui/taurusgui/config_loader/xmlconf.py | 22 +++-- 6 files changed, 120 insertions(+), 83 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index a75ef4361..3d3dec46d 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -32,7 +32,6 @@ from taurus import warning - __all__ = ["getLoader"] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py index 3011d9fd9..deb3e915b 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -26,16 +26,12 @@ import taurus from taurus.external.qt import Qt -from taurus.qt.qtgui.taurusgui.utils import AppletDescription from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( AbstractConfigLoader, ) -from taurus.qt.qtgui.taurusgui.config_loader.pyconf import ( - PyConfigLoader -) -from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import ( - XmlConfigLoader -) +from taurus.qt.qtgui.taurusgui.config_loader.pyconf import PyConfigLoader +from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import XmlConfigLoader +from taurus.qt.qtgui.taurusgui.utils import AppletDescription __all__ = ["BckCompatConfigLoader"] @@ -49,7 +45,9 @@ class BckCompatConfigLoader(AbstractConfigLoader): @staticmethod def supports(confname): - return PyConfigLoader.supports(confname) or XmlConfigLoader.supports(confname) + return PyConfigLoader.supports(confname) or XmlConfigLoader.supports( + confname + ) def load(self): tmp = {} @@ -94,8 +92,12 @@ def loadMonitor(gui, conf): msg = "Cannot add applet 'monitor'" gui.error(msg) gui.traceback(level=taurus.Info) - result = Qt.QMessageBox.critical(gui, "Initialization error", "%s\n\n%s" % ( - msg, repr(e)), Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore) + result = Qt.QMessageBox.critical( + gui, + "Initialization error", + "%s\n\n%s" % (msg, repr(e)), + Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore, + ) if result == Qt.QMessageBox.Abort: sys.exit() @@ -109,16 +111,24 @@ def loadConsole(gui, conf): if not gui.getConfigValue(conf, "CONSOLE", []): return - msg = ('createConsole() and the "CONSOLE" configuration key are ' + - 'deprecated since 4.0.4. Add a panel with a ' + - 'silx.gui.console.IPythonWidget widdget instead') + msg = ( + "createConsole() and the 'CONSOLE' configuration key are " + + "deprecated since 4.0.4. Add a panel with a " + + "silx.gui.console.IPythonWidget widdget instead" + ) gui.deprecated(msg) try: from silx.gui.console import IPythonWidget except ImportError: - gui.warning('Cannot import taurus.qt.qtgui.console. ' + - 'The Console Panel will not be available') + gui.warning( + "Cannot import taurus.qt.qtgui.console. " + + "The Console Panel will not be available" + ) return console = IPythonWidget() - gui.createPanel(console, "Console", permanent=True, - icon=Qt.QIcon.fromTheme('utilities-terminal')) + gui.createPanel( + console, + "Console", + permanent=True, + icon=Qt.QIcon.fromTheme("utilities-terminal"), + ) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index c7a6d0d89..ae23b9128 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -26,17 +26,11 @@ import json import os -from taurus.qt.qtgui.taurusgui.utils import ( - PanelDescription, - ToolBarDescription, - AppletDescription, - ExternalApp, -) from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, - ConfigLoaderError, -) - + AbstractConfigLoader, ConfigLoaderError) +from taurus.qt.qtgui.taurusgui.utils import (AppletDescription, ExternalApp, + PanelDescription, + ToolBarDescription) __all__ = ["JsonConfigLoader"] @@ -91,11 +85,18 @@ def load(self): if v in self._data: tmp[v] = self._data[v] - for klass in (PanelDescription, ToolBarDescription, AppletDescription, ExternalApp): + for klass in ( + PanelDescription, + ToolBarDescription, + AppletDescription, + ExternalApp, + ): tmp[klass.__name__ + "s"] = self._get_objects(klass) self._data.update(tmp) - self._data["CONF_DIR"] = os.path.abspath(os.path.dirname(self._confname)) + self._data["CONF_DIR"] = os.path.abspath( + os.path.dirname(self._confname) + ) return self._data diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 41a6032dc..889de5aa1 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -23,23 +23,17 @@ """""" +import inspect import os import pkgutil import sys import types -import inspect -from taurus.qt.qtgui.taurusgui.utils import ( - PanelDescription, - AppletDescription, - ToolBarDescription, - ExternalApp, -) from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, - ConfigLoaderError, -) - + AbstractConfigLoader, ConfigLoaderError) +from taurus.qt.qtgui.taurusgui.utils import (AppletDescription, ExternalApp, + PanelDescription, + ToolBarDescription) __all__ = ["PyConfigLoader"] @@ -146,7 +140,12 @@ def load(self): if hasattr(self._mod, v): tmp[v] = getattr(self._mod, v) - for klass in (PanelDescription, AppletDescription, ToolBarDescription, ExternalApp): + for klass in ( + PanelDescription, + AppletDescription, + ToolBarDescription, + ExternalApp, + ): tmp[klass.__name__ + "s"] = self._get_objects(klass) return tmp diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index 7b6bcbe04..e24dae9cb 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -27,11 +27,9 @@ import taurus from taurus.external.qt import Qt +from taurus.qt.qtgui.taurusgui.config_loader.abstract import \ + AbstractConfigLoader from taurus.qt.qtgui.taurusgui.utils import PanelDescription -from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, -) - __all__ = ["SardanaConfigLoader"] @@ -65,7 +63,13 @@ def load(self): @property def hooks(self): - return self._loadMacroServerName, self._loadMacroBroker, self._loadDoorName, self._loadMacroEditorsPath, self._loadInstrumentsFromPool + return ( + self._loadMacroServerName, + self._loadMacroBroker, + self._loadDoorName, + self._loadMacroEditorsPath, + self._loadInstrumentsFromPool, + ) @staticmethod def _loadMacroServerName(gui, conf): @@ -82,6 +86,7 @@ def _loadMacroBroker(gui, conf): # macro infrastructure will only be created if MACROSERVER_NAME is set if ms is not None and mp is True: from sardana.taurus.qt.qtgui.macrolistener import MacroBroker + gui.__macroBroker = MacroBroker(gui) @staticmethod @@ -92,10 +97,14 @@ def _loadDoorName(gui, conf): @staticmethod def _loadMacroEditorsPath(gui, conf): - macro_editors_path = gui.getConfigValue(conf, "MACRO_EDITORS_PATH", True) + macro_editors_path = gui.getConfigValue( + conf, "MACRO_EDITORS_PATH", True + ) if macro_editors_path: - from sardana.taurus.qt.qtgui.extra_macroexecutor.macroparameterseditor.macroparameterseditor import \ - ParamEditorManager + from sardana.taurus.qt.qtgui.extra_macroexecutor.macroparameterseditor.macroparameterseditor import ( + ParamEditorManager, + ) + ParamEditorManager().parsePaths(macro_editors_path) ParamEditorManager().browsePaths() @@ -103,16 +112,22 @@ def _loadInstrumentsFromPool(self, gui, conf): """ Get panel descriptions from pool if required """ - #todo: needs heavy refactor + # todo: needs heavy refactor ms = gui.getConfigValue(conf, "MACROSERVER_NAME") - instruments_from_pool = gui.getConfigValue(conf, "INSTRUMENTS_FROM_POOL", False) + instruments_from_pool = gui.getConfigValue( + conf, "INSTRUMENTS_FROM_POOL", False + ) if instruments_from_pool: try: - gui.splashScreen().showMessage("Gathering Instrument info from Pool") + gui.splashScreen().showMessage( + "Gathering Instrument info from Pool" + ) except AttributeError: pass - pool_instruments = self.createInstrumentsFromPool(ms) # auto create instruments from pool + pool_instruments = self.createInstrumentsFromPool( + ms + ) # auto create instruments from pool else: pool_instruments = [] @@ -122,48 +137,60 @@ def _loadInstrumentsFromPool(self, gui, conf): @staticmethod def createInstrumentsFromPool(gui, macroservername): - ''' + """ Creates a list of instrument panel descriptions by gathering the info from the Pool. Each panel is a TaurusForm grouping together all those elements that belong to the same instrument according to the Pool info :return: (list) - ''' - #todo: needs heavy refactor + """ + # todo: needs heavy refactor instrument_dict = {} try: ms = taurus.Device(macroservername) - instruments = ms.getElementsOfType('Instrument') + instruments = ms.getElementsOfType("Instrument") if instruments is None: raise Exception() except Exception as e: msg = 'Could not fetch Instrument list from "%s"' % macroservername gui.error(msg) - result = Qt.QMessageBox.critical(gui, 'Initialization error', '%s\n\n%s' % ( - msg, repr(e)), Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore) + result = Qt.QMessageBox.critical( + gui, + "Initialization error", + "%s\n\n%s" % (msg, repr(e)), + Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore, + ) if result == Qt.QMessageBox.Abort: sys.exit() return [] for i in instruments.values(): i_name = i.full_name - #i_name, i_unknown, i_type, i_pools = i.split() + # i_name, i_unknown, i_type, i_pools = i.split() i_view = PanelDescription( - i_name, classname='TaurusForm', floating=False, model=[]) + i_name, classname="TaurusForm", floating=False, model=[] + ) instrument_dict[i_name] = i_view from operator import attrgetter - pool_elements = sorted(ms.getElementsWithInterface( - 'Moveable').values(), key=attrgetter('name')) - pool_elements += sorted(ms.getElementsWithInterface( - 'ExpChannel').values(), key=attrgetter('name')) - pool_elements += sorted(ms.getElementsWithInterface( - 'IORegister').values(), key=attrgetter('name')) + + pool_elements = sorted( + ms.getElementsWithInterface("Moveable").values(), + key=attrgetter("name"), + ) + pool_elements += sorted( + ms.getElementsWithInterface("ExpChannel").values(), + key=attrgetter("name"), + ) + pool_elements += sorted( + ms.getElementsWithInterface("IORegister").values(), + key=attrgetter("name"), + ) for elem in pool_elements: instrument = elem.instrument if instrument: i_name = instrument # ----------------------------------------------------------- - # Support sardana v<2.4 (which used tango names instead of + # Support sardana v<2.4 (which used tango names instead of # taurus full names e_name = elem.full_name if not e_name.startswith("tango://"): @@ -171,6 +198,9 @@ def createInstrumentsFromPool(gui, macroservername): # ----------------------------------------------------------- instrument_dict[i_name].model.append(e_name) # filter out empty panels - ret = [instrument for instrument in instrument_dict.values() - if len(instrument.model) > 0] + ret = [ + instrument + for instrument in instrument_dict.values() + if len(instrument.model) > 0 + ] return ret diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index d19411e99..5933332db 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -26,18 +26,11 @@ import os from lxml import etree - -from taurus.qt.qtgui.taurusgui.utils import ( - PanelDescription, - ToolBarDescription, - AppletDescription, - ExternalApp, -) from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, - ConfigLoaderError, -) - + AbstractConfigLoader, ConfigLoaderError) +from taurus.qt.qtgui.taurusgui.utils import (AppletDescription, ExternalApp, + PanelDescription, + ToolBarDescription) __all__ = ["XmlConfigLoader"] @@ -109,7 +102,12 @@ def load(self): if name is not None and name.text is not None: tmp[v] = name.text - for klass in (PanelDescription, ToolBarDescription, AppletDescription, ExternalApp): + for klass in ( + PanelDescription, + ToolBarDescription, + AppletDescription, + ExternalApp, + ): tmp[klass.__name__ + "s"] = self._get_objects(klass) tmp["CONF_DIR"] = os.path.abspath(os.path.dirname(self._confname)) From 5be97c59a5128bd4b1d89e0357f33bfe05358e0d Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 23:52:55 +0200 Subject: [PATCH 55/99] Add missing entry point for Sardana config loader --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 59e8379b0..b8f7a7ae2 100644 --- a/setup.py +++ b/setup.py @@ -130,6 +130,7 @@ def get_release_info(): 'taurus.json = taurus.qt.qtgui.taurusgui.config_loader.jsonconf:JsonConfigLoader', 'taurus.xml = taurus.qt.qtgui.taurusgui.config_loader.xmlconf:XmlConfigLoader', 'taurus.bck_compat = taurus.qt.qtgui.taurusgui.config_loader.back_compat:BckCompatConfigLoader', + 'taurus.sardana = taurus.qt.qtgui.taurusgui.config_loader.sardana:SardanaConfigLoader', ] entry_points = { From edda3b99a8397845cfdcc71bdab2dcb55d6f1666 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 23:53:36 +0200 Subject: [PATCH 56/99] Fix typo --- lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index e24dae9cb..e40a3f083 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -38,7 +38,7 @@ class SardanaConfigLoader(AbstractConfigLoader): """ Config loader which loads Sardana-related values. This lives as a hack for manupulating AbstracLoader.CONFIG_VALUES. - It does not laod anything by itself, just injects new values into + It does not load anything by itself, just injects new values into CONFIG_VALUES so other laoders will load them. """ From 085e8afe9579905048527a28c05df14ee0d9473d Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Wed, 17 Jun 2020 23:53:55 +0200 Subject: [PATCH 57/99] Always try to laod Sardana config values --- lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index e40a3f083..be4b79d70 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -56,7 +56,7 @@ def __init__(self, confname): @staticmethod def supports(confname): - return False + return True def load(self): return {} From 1f4247fc31d9c70f1fc41ca56f13ba47f7db963b Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Thu, 18 Jun 2020 11:06:57 +0200 Subject: [PATCH 58/99] m, typos --- lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index be4b79d70..878036877 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -37,7 +37,7 @@ class SardanaConfigLoader(AbstractConfigLoader): """ Config loader which loads Sardana-related values. - This lives as a hack for manupulating AbstracLoader.CONFIG_VALUES. + This lives as a hack for manipulating AbstractLoader.CONFIG_VALUES. It does not load anything by itself, just injects new values into CONFIG_VALUES so other laoders will load them. """ From deb7c9a227e30e08fd2174ab5c8f8fc5435e1244 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Thu, 18 Jun 2020 11:08:02 +0200 Subject: [PATCH 59/99] m, typo --- lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index 878036877..12f222a78 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -39,7 +39,7 @@ class SardanaConfigLoader(AbstractConfigLoader): Config loader which loads Sardana-related values. This lives as a hack for manipulating AbstractLoader.CONFIG_VALUES. It does not load anything by itself, just injects new values into - CONFIG_VALUES so other laoders will load them. + CONFIG_VALUES so other loaders will load them. """ SARDANA_VALUES = [ From 55bab0b15d74123280cc75580d095f74b4a6aa87 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:16:40 +0200 Subject: [PATCH 60/99] Retiurn loaders list from loader function --- lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index 3d3dec46d..25bebf677 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -61,3 +61,5 @@ def getLoader(confname): raise NotImplementedError( "No supported config loader for '%s'" % confname ) + else: + return loaders From 1d08b0fabcc5e047ac63d4c24b1a3129c25afb33 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:17:26 +0200 Subject: [PATCH 61/99] getLoader -> getLoaders --- lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py | 2 +- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index 25bebf677..e675cf5d8 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -35,7 +35,7 @@ __all__ = ["getLoader"] -def getLoader(confname): +def getLoaders(confname): """ Discover proper config loader based on passed string. It can be either path to file or directory or Python diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index da1427851..7ab157580 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -49,7 +49,7 @@ from taurus.qt.qtgui.util.ui import UILoadable from taurus.qt.qtgui.taurusgui.utils import ExternalAppAction from taurus.core.util.log import deprecation_decorator -from taurus.qt.qtgui.taurusgui.config_loader import getLoader +from taurus.qt.qtgui.taurusgui.config_loader import getLoaders __all__ = ["DockWidgetPanel", "TaurusGui"] @@ -914,7 +914,7 @@ def loadConfiguration(self, confname): ''' conf = {} try: - loaders = getLoader(confname) + loaders = getLoaders(confname) for loader in loaders: conf.update(loader.load()) if "CONF_DIR" in conf: From 00a24d6975982b7ff2f269718e4ee71482fae418 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:19:50 +0200 Subject: [PATCH 62/99] Move getLoaders function to its own module --- .../qtgui/taurusgui/config_loader/__init__.py | 40 +---------- .../qt/qtgui/taurusgui/config_loader/util.py | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+), 39 deletions(-) create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/util.py diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py index e675cf5d8..2d954c2f8 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py @@ -22,44 +22,6 @@ ########################################################################### """ -This module provides factory 'getLoader' for proper ConfigLoader object -detected from 'confname' string. Each config loader has to implement interface -defined by AbstractConfigLoader class in -taurus.qt.qtgui.taurusgui.config_loader.abstract """ -import pkg_resources - -from taurus import warning - -__all__ = ["getLoader"] - - -def getLoaders(confname): - """ - Discover proper config loader based on passed string. - It can be either path to file or directory or Python - abolute path to module with configuration. - - :param confname: name of configuration - :return: A AbstractConfigLoader subclass object - """ - - loaders = [] - for ep in pkg_resources.iter_entry_points("taurus.gui.loaders"): - try: - loader = ep.load() - if loader.supports(confname): - loaders.append(loader(confname)) - except Exception as e: - warning( - "Could not load config loader plugin '%s. Reason: '%s", - ep.name, - e, - ) - if not loaders: - raise NotImplementedError( - "No supported config loader for '%s'" % confname - ) - else: - return loaders +from .util import getLoaders diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py new file mode 100644 index 000000000..e2ba4d3b1 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py @@ -0,0 +1,67 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + +""" +This module provides factory 'getLoader' for proper ConfigLoader object +detected from 'confname' string. Each config loader has to implement interface +defined by AbstractConfigLoader class in +taurus.qt.qtgui.taurusgui.config_loader.abstract +""" + + +import pkg_resources + +from taurus import warning + + +__all__ = ["getLoaders"] + + +def getLoaders(confname): + """ + Discover proper config loader based on passed string. + It can be either path to file or directory or Python + abolute path to module with configuration. + + :param confname: name of configuration + :return: A AbstractConfigLoader subclass object + """ + + loaders = [] + for ep in pkg_resources.iter_entry_points("taurus.gui.loaders"): + try: + loader = ep.load() + if loader.supports(confname): + loaders.append(loader(confname)) + except Exception as e: + warning( + "Could not load config loader plugin '%s. Reason: '%s", + ep.name, + e, + ) + if not loaders: + raise NotImplementedError( + "No supported config loader for '%s'" % confname + ) + else: + return loaders From edf38f69ab945f5d014bdc8de105bcd30488f44a Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:25:46 +0200 Subject: [PATCH 63/99] USe variable with entry point name for easier testing --- lib/taurus/qt/qtgui/taurusgui/config_loader/util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py index e2ba4d3b1..1b4bbc87d 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py @@ -47,8 +47,10 @@ def getLoaders(confname): :return: A AbstractConfigLoader subclass object """ + EP_GROUP_LOADERS = "taurus.gui.loaders" + loaders = [] - for ep in pkg_resources.iter_entry_points("taurus.gui.loaders"): + for ep in pkg_resources.iter_entry_points(EP_GROUP_LOADERS): try: loader = ep.load() if loader.supports(confname): From fd8b344b418fa7dbf839cc77d4c8c2a84ca2d17d Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:33:20 +0200 Subject: [PATCH 64/99] Create instrument panels completely in config loader hook --- .../qtgui/taurusgui/config_loader/sardana.py | 58 ++++++++++++++++--- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 15 +---- 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index be4b79d70..74d5f14c0 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -125,15 +125,10 @@ def _loadInstrumentsFromPool(self, gui, conf): ) except AttributeError: pass - pool_instruments = self.createInstrumentsFromPool( - ms - ) # auto create instruments from pool - else: - pool_instruments = [] - if pool_instruments: - gui._loadCustomPanels(conf, pool_instruments) - return pool_instruments + pool_instruments = self.createInstrumentsFromPool(ms) + if pool_instruments: + self.loadInstrumentPanels(gui, pool_instruments) @staticmethod def createInstrumentsFromPool(gui, macroservername): @@ -204,3 +199,50 @@ def createInstrumentsFromPool(gui, macroservername): if len(instrument.model) > 0 ] return ret + + @staticmethod + def loadInstrumentPanels(gui, poolinstruments): + """ + get custom panel descriptions from the python config file, xml config and + create panels based on the panel descriptions + """ + + for p in poolinstruments: + try: + try: + gui.splashScreen().showMessage("Creating instrument panel %s" % p.name) + except AttributeError: + pass + from taurus.qt.qtgui.panel.taurusform import TaurusForm + w = TaurusForm() + + # ------------------------------------------------------------- + # Backwards-compat. Remove when removing CW map support + if gui._customWidgetMap: + w.setCustomWidgetMap(gui._customWidgetMap) + # ------------------------------------------------------------- + w.setModel(p.model) + instrumentkey = gui.IMPLICIT_ASSOCIATION + + # the pool instruments may change when the pool config changes, + # so we do not store their config + registerconfig = False + # create a panel + + gui.createPanel( + w, + p.name, + floating=False, + registerconfig=False, + instrumentkey=instrumentkey, + permanent=True, + ) + except Exception as e: + msg = "Cannot create instrument panel %s" % getattr( + p, "name", "__Unknown__") + gui.error(msg) + gui.traceback(level=taurus.Info) + result = Qt.QMessageBox.critical(gui, "Initialization error", "%s\n\n%s" % ( + msg, repr(e)), Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore) + if result == Qt.QMessageBox.Abort: + sys.exit() diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 7ab157580..7316394d9 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -1034,17 +1034,12 @@ def _loadSynoptic(self, conf): for s in synoptic: self.createMainSynoptic(s) - def _loadCustomPanels(self, conf, poolinstruments=None): + def _loadCustomPanels(self, conf): """ get custom panel descriptions from the python config file, xml config and create panels based on the panel descriptions """ - if poolinstruments is None: - custom_panels = conf["PanelDescriptions"] - else: - custom_panels = poolinstruments - - for p in custom_panels: + for p in conf["PanelDescriptions"]: try: try: self.splashScreen().showMessage("Creating panel %s" % p.name) @@ -1088,17 +1083,13 @@ def _loadCustomPanels(self, conf, poolinstruments=None): w.setFormat(p.widget_formatter) icon = p.icon - # the pool instruments may change when the pool config changes, - # so we do not store their config - if poolinstruments is None: - registerconfig = False # create a panel self.createPanel( w, p.name, floating=p.floating, - registerconfig=registerconfig, + registerconfig=True, instrumentkey=instrumentkey, permanent=True, icon=icon From f8433f74dfaa01632a1c45bd6d96cff36a7df595 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:50:13 +0200 Subject: [PATCH 65/99] Protect against expections raised while executing config hooks --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 7316394d9..b0dc3fb4c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -50,6 +50,7 @@ from taurus.qt.qtgui.taurusgui.utils import ExternalAppAction from taurus.core.util.log import deprecation_decorator from taurus.qt.qtgui.taurusgui.config_loader import getLoaders +from taurus.qt.qtgui.taurusgui.config_loader.abstract import HookLoaderError __all__ = ["DockWidgetPanel", "TaurusGui"] @@ -947,9 +948,22 @@ def loadConfiguration(self, confname): self._loadExternalApps(conf) self._loadIniFile(conf) - for loader in loaders: - for hook in loader.hooks: - hook(self, conf) + try: + for loader in loaders: + for hook in loader.hooks: + hook(self, conf) + except Exception as e: + msg = "Error while executing config hooks: " + repr(e) + self.error(msg) + self.traceback(level=taurus.Info) # use traceback module? + result = Qt.QMessageBox.critical( + self, + "Initialization error", + "%s\n\n%s" % (msg, repr(e)), + Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore, + ) + if result == Qt.QMessageBox.Abort: + sys.exit() def _loadAppName(self, conf, confname): appname = self.getConfigValue(conf, "GUI_NAME") From b0a09e89237bb162adab67d09affd91caee25788 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:50:35 +0200 Subject: [PATCH 66/99] Add new exception speicifc for hooks --- .../qt/qtgui/taurusgui/config_loader/abstract.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 2be6737e3..8ae54487d 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -29,7 +29,7 @@ setattr(abc, "ABC", abc.ABCMeta("ABC", (object,), {})) -__all__ = ["AbstractConfigLoader", "ConfigLoaderError"] +__all__ = ["AbstractConfigLoader", "ConfigLoaderError", "HookLoaderError"] class ConfigLoaderError(Exception): @@ -42,6 +42,16 @@ def __init__(self, message): super(ConfigLoaderError, self).__init__(message) +class HookLoaderError(ConfigLoaderError): + """ + Exception raised by config loader hooks + """ + + def __init__(self, message): + message = "Exception raised while executing config loader hookhook: " + message + super(HookLoaderError, self).__init__(message) + + class AbstractConfigLoader(abc.ABC): """ Abstract class for config loaders. From 21c5b95a9de87bde2d0d158b5ae328da49c9405d Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:54:13 +0200 Subject: [PATCH 67/99] Simplify handling of errors --- .../taurusgui/config_loader/back_compat.py | 17 ++-------- .../qtgui/taurusgui/config_loader/sardana.py | 34 ++++++------------- 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py index deb3e915b..ee6337d17 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -22,16 +22,13 @@ ########################################################################### """""" -import sys - -import taurus from taurus.external.qt import Qt from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( AbstractConfigLoader, + HookLoaderError, ) from taurus.qt.qtgui.taurusgui.config_loader.pyconf import PyConfigLoader from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import XmlConfigLoader -from taurus.qt.qtgui.taurusgui.utils import AppletDescription __all__ = ["BckCompatConfigLoader"] @@ -89,17 +86,7 @@ def loadMonitor(gui, conf): # register the toolbar as delegate gui.registerConfigDelegate(w, "monitor") except Exception as e: - msg = "Cannot add applet 'monitor'" - gui.error(msg) - gui.traceback(level=taurus.Info) - result = Qt.QMessageBox.critical( - gui, - "Initialization error", - "%s\n\n%s" % (msg, repr(e)), - Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore, - ) - if result == Qt.QMessageBox.Abort: - sys.exit() + raise HookLoaderError(str(e)) @staticmethod def loadConsole(gui, conf): diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index 74d5f14c0..ff6f9675a 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -23,12 +23,11 @@ """""" -import sys - import taurus -from taurus.external.qt import Qt -from taurus.qt.qtgui.taurusgui.config_loader.abstract import \ - AbstractConfigLoader +from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( + AbstractConfigLoader, + HookLoaderError, +) from taurus.qt.qtgui.taurusgui.utils import PanelDescription __all__ = ["SardanaConfigLoader"] @@ -147,17 +146,9 @@ def createInstrumentsFromPool(gui, macroservername): if instruments is None: raise Exception() except Exception as e: - msg = 'Could not fetch Instrument list from "%s"' % macroservername - gui.error(msg) - result = Qt.QMessageBox.critical( - gui, - "Initialization error", - "%s\n\n%s" % (msg, repr(e)), - Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore, - ) - if result == Qt.QMessageBox.Abort: - sys.exit() - return [] + msg = 'Could not fetch Instrument list from "%s": %s' % (macroservername, str(e)) + raise HookLoaderError(msg) + for i in instruments.values(): i_name = i.full_name # i_name, i_unknown, i_type, i_pools = i.split() @@ -238,11 +229,6 @@ def loadInstrumentPanels(gui, poolinstruments): permanent=True, ) except Exception as e: - msg = "Cannot create instrument panel %s" % getattr( - p, "name", "__Unknown__") - gui.error(msg) - gui.traceback(level=taurus.Info) - result = Qt.QMessageBox.critical(gui, "Initialization error", "%s\n\n%s" % ( - msg, repr(e)), Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore) - if result == Qt.QMessageBox.Abort: - sys.exit() + msg = "Cannot create instrument panel %s: %s" % (getattr( + p, "name", "__Unknown__"), str(e)) + raise HookLoaderError(msg) From c6a6a6805a021e1f97c4f401fc7bdcf34c9abdb0 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:54:47 +0200 Subject: [PATCH 68/99] Import just Device --- lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index ff6f9675a..87a3267f7 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -23,7 +23,7 @@ """""" -import taurus +from taurus import Device from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( AbstractConfigLoader, HookLoaderError, @@ -141,7 +141,7 @@ def createInstrumentsFromPool(gui, macroservername): # todo: needs heavy refactor instrument_dict = {} try: - ms = taurus.Device(macroservername) + ms = Device(macroservername) instruments = ms.getElementsOfType("Instrument") if instruments is None: raise Exception() From e0b658215ccb92546fc54f296822c20fbe0fd695 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:58:43 +0200 Subject: [PATCH 69/99] Move custom exceptions to util module --- .../qtgui/taurusgui/config_loader/abstract.py | 22 +------------------ .../taurusgui/config_loader/back_compat.py | 4 ++-- .../qtgui/taurusgui/config_loader/jsonconf.py | 4 +++- .../qtgui/taurusgui/config_loader/pyconf.py | 4 +++- .../qtgui/taurusgui/config_loader/sardana.py | 2 +- .../qt/qtgui/taurusgui/config_loader/util.py | 22 ++++++++++++++++++- .../qtgui/taurusgui/config_loader/xmlconf.py | 4 +++- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 2 +- 8 files changed, 35 insertions(+), 29 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 8ae54487d..50c86e51c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -29,27 +29,7 @@ setattr(abc, "ABC", abc.ABCMeta("ABC", (object,), {})) -__all__ = ["AbstractConfigLoader", "ConfigLoaderError", "HookLoaderError"] - - -class ConfigLoaderError(Exception): - """ - Base exception raised by ConfigLoader - """ - - def __init__(self, message): - message = "Exception raised while loading configuration: " + message - super(ConfigLoaderError, self).__init__(message) - - -class HookLoaderError(ConfigLoaderError): - """ - Exception raised by config loader hooks - """ - - def __init__(self, message): - message = "Exception raised while executing config loader hookhook: " + message - super(HookLoaderError, self).__init__(message) +__all__ = ["AbstractConfigLoader"] class AbstractConfigLoader(abc.ABC): diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py index ee6337d17..491b8753e 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -24,11 +24,11 @@ """""" from taurus.external.qt import Qt from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, - HookLoaderError, + AbstractConfigLoader ) from taurus.qt.qtgui.taurusgui.config_loader.pyconf import PyConfigLoader from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import XmlConfigLoader +from taurus.qt.qtgui.taurusgui.config_loader.util import HookLoaderError __all__ = ["BckCompatConfigLoader"] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index ae23b9128..917e1e86d 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -27,7 +27,9 @@ import os from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, ConfigLoaderError) + AbstractConfigLoader +) +from taurus.qt.qtgui.taurusgui.config_loader.util import ConfigLoaderError from taurus.qt.qtgui.taurusgui.utils import (AppletDescription, ExternalApp, PanelDescription, ToolBarDescription) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 889de5aa1..ae2766db0 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -30,7 +30,9 @@ import types from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, ConfigLoaderError) + AbstractConfigLoader +) +from taurus.qt.qtgui.taurusgui.config_loader.util import ConfigLoaderError from taurus.qt.qtgui.taurusgui.utils import (AppletDescription, ExternalApp, PanelDescription, ToolBarDescription) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index 87a3267f7..6945573d3 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -26,8 +26,8 @@ from taurus import Device from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( AbstractConfigLoader, - HookLoaderError, ) +from taurus.qt.qtgui.taurusgui.config_loader.util import HookLoaderError from taurus.qt.qtgui.taurusgui.utils import PanelDescription __all__ = ["SardanaConfigLoader"] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py index 1b4bbc87d..89c992cd8 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py @@ -34,7 +34,27 @@ from taurus import warning -__all__ = ["getLoaders"] +__all__ = ["getLoaders", "ConfigLoaderError", "HookLoaderError"] + + +class ConfigLoaderError(Exception): + """ + Base exception raised by ConfigLoader + """ + + def __init__(self, message): + message = "Exception raised while loading configuration: " + message + super(ConfigLoaderError, self).__init__(message) + + +class HookLoaderError(ConfigLoaderError): + """ + Exception raised by config loader hooks + """ + + def __init__(self, message): + message = "Exception raised while executing config loader hookhook: " + message + super(HookLoaderError, self).__init__(message) def getLoaders(confname): diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index 5933332db..3c3ba5d7c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -27,7 +27,9 @@ from lxml import etree from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, ConfigLoaderError) + AbstractConfigLoader +) +from taurus.qt.qtgui.taurusgui.config_loader.util import ConfigLoaderError from taurus.qt.qtgui.taurusgui.utils import (AppletDescription, ExternalApp, PanelDescription, ToolBarDescription) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index b0dc3fb4c..4f2886d2b 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -50,7 +50,7 @@ from taurus.qt.qtgui.taurusgui.utils import ExternalAppAction from taurus.core.util.log import deprecation_decorator from taurus.qt.qtgui.taurusgui.config_loader import getLoaders -from taurus.qt.qtgui.taurusgui.config_loader.abstract import HookLoaderError +from taurus.qt.qtgui.taurusgui.config_loader.util import HookLoaderError __all__ = ["DockWidgetPanel", "TaurusGui"] From a4a5e1ee2c37e9bb3966b00f92fdbd28a7ebe16f Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 18:59:34 +0200 Subject: [PATCH 70/99] Remove unused import --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 4f2886d2b..c9df52266 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -50,7 +50,6 @@ from taurus.qt.qtgui.taurusgui.utils import ExternalAppAction from taurus.core.util.log import deprecation_decorator from taurus.qt.qtgui.taurusgui.config_loader import getLoaders -from taurus.qt.qtgui.taurusgui.config_loader.util import HookLoaderError __all__ = ["DockWidgetPanel", "TaurusGui"] From fdff9ccb60af3ec6a37b80f809f538070b4a5341 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 19:12:18 +0200 Subject: [PATCH 71/99] Provide concrete config loader classes for Python and XML configuration format --- .../qtgui/taurusgui/config_loader/sardana.py | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index 6945573d3..4050b514d 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -27,13 +27,19 @@ from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( AbstractConfigLoader, ) +from taurus.qt.qtgui.taurusgui.config_loader.pyconf import ( + PyConfigLoader, +) +from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import ( + XmlConfigLoader, +) from taurus.qt.qtgui.taurusgui.config_loader.util import HookLoaderError from taurus.qt.qtgui.taurusgui.utils import PanelDescription -__all__ = ["SardanaConfigLoader"] +__all__ = ["PySardanaConfigLoader", "XmlSardanaConfigLoader"] -class SardanaConfigLoader(AbstractConfigLoader): +class BaseSardanaConfigLoader(AbstractConfigLoader): """ Config loader which loads Sardana-related values. This lives as a hack for manupulating AbstracLoader.CONFIG_VALUES. @@ -50,15 +56,10 @@ class SardanaConfigLoader(AbstractConfigLoader): ] def __init__(self, confname): - super(SardanaConfigLoader, self).__init__(confname) - AbstractConfigLoader.CONFIG_VALUES + self.SARDANA_VALUES - - @staticmethod - def supports(confname): - return True - - def load(self): - return {} + super(BaseSardanaConfigLoader, self).__init__(confname) + # explicit copy of AbstractConfigLoader.CONFIG_VALUES is made on purpose + # this way we avoid problems about changing it for other derived classes + self.CONFIG_VALUES = AbstractConfigLoader.CONFIG_VALUES[:] + self.SARDANA_VALUES @property def hooks(self): @@ -232,3 +233,11 @@ def loadInstrumentPanels(gui, poolinstruments): msg = "Cannot create instrument panel %s: %s" % (getattr( p, "name", "__Unknown__"), str(e)) raise HookLoaderError(msg) + + +class PySardanaConfigLoader(PyConfigLoader, BaseSardanaConfigLoader): + pass + + +class XmlSardanaConfigLoader(XmlConfigLoader, BaseSardanaConfigLoader): + pass From 4a402e21d44e43e5f48d404ecae07c6cb92339e0 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 19:13:05 +0200 Subject: [PATCH 72/99] Add new Sardana config laoders to entry point --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b8f7a7ae2..0493fcef5 100644 --- a/setup.py +++ b/setup.py @@ -130,7 +130,8 @@ def get_release_info(): 'taurus.json = taurus.qt.qtgui.taurusgui.config_loader.jsonconf:JsonConfigLoader', 'taurus.xml = taurus.qt.qtgui.taurusgui.config_loader.xmlconf:XmlConfigLoader', 'taurus.bck_compat = taurus.qt.qtgui.taurusgui.config_loader.back_compat:BckCompatConfigLoader', - 'taurus.sardana = taurus.qt.qtgui.taurusgui.config_loader.sardana:SardanaConfigLoader', + 'taurus.sardana.py = taurus.qt.qtgui.taurusgui.config_loader.sardana:PySardanaConfigLoader', + 'taurus.sardana.xml = taurus.qt.qtgui.taurusgui.config_loader.sardana:XmlSardanaConfigLoader', ] entry_points = { From 9bd06cda43afad0be616d1b991cc7ada72ce57b3 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 19:16:35 +0200 Subject: [PATCH 73/99] Update docstring --- lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index 4050b514d..4d1a02c66 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -195,8 +195,7 @@ def createInstrumentsFromPool(gui, macroservername): @staticmethod def loadInstrumentPanels(gui, poolinstruments): """ - get custom panel descriptions from the python config file, xml config and - create panels based on the panel descriptions + Create GUI panels from Sardana Pool instruments """ for p in poolinstruments: From 2428a08f644e3e6ab4827a873b74991b1d917fa1 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 19:40:05 +0200 Subject: [PATCH 74/99] Refactor loading instruments from Pool --- .../qtgui/taurusgui/config_loader/sardana.py | 85 +++++++++---------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index 4d1a02c66..c50f48569 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -22,6 +22,7 @@ ########################################################################### """""" +from operator import attrgetter from taurus import Device from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( @@ -34,7 +35,6 @@ XmlConfigLoader, ) from taurus.qt.qtgui.taurusgui.config_loader.util import HookLoaderError -from taurus.qt.qtgui.taurusgui.utils import PanelDescription __all__ = ["PySardanaConfigLoader", "XmlSardanaConfigLoader"] @@ -126,18 +126,22 @@ def _loadInstrumentsFromPool(self, gui, conf): except AttributeError: pass - pool_instruments = self.createInstrumentsFromPool(ms) + pool_instruments = self._getInstrumentsFromPool(ms) if pool_instruments: - self.loadInstrumentPanels(gui, pool_instruments) + self._createInstrumentPanels(gui, pool_instruments) @staticmethod - def createInstrumentsFromPool(gui, macroservername): + def _getInstrumentsFromPool(gui, macroservername): """ - Creates a list of instrument panel descriptions by gathering the info - from the Pool. Each panel is a TaurusForm grouping together all those - elements that belong to the same instrument according to the Pool info + Get Instruments information form Pool. Return models for + each instrument. - :return: (list) + :param TaurusGui gui: instance of TaurusGui + :param str macroservername: name of MacroServer + + :return: Dicionary with Pool instruments where values are lists + of models + :rtype: dict()>) """ # todo: needs heavy refactor instrument_dict = {} @@ -151,31 +155,18 @@ def createInstrumentsFromPool(gui, macroservername): raise HookLoaderError(msg) for i in instruments.values(): - i_name = i.full_name - # i_name, i_unknown, i_type, i_pools = i.split() - i_view = PanelDescription( - i_name, classname="TaurusForm", floating=False, model=[] - ) - instrument_dict[i_name] = i_view + instrument_dict[i.full_name] = [] - from operator import attrgetter + pool_elements = [] + for kls in ("Moveable", "ExpChannel", "IORegister"): + pool_elements += sorted( + ms.getElementsWithInterface(kls).values(), + key=attrgetter("name"), + ) - pool_elements = sorted( - ms.getElementsWithInterface("Moveable").values(), - key=attrgetter("name"), - ) - pool_elements += sorted( - ms.getElementsWithInterface("ExpChannel").values(), - key=attrgetter("name"), - ) - pool_elements += sorted( - ms.getElementsWithInterface("IORegister").values(), - key=attrgetter("name"), - ) for elem in pool_elements: instrument = elem.instrument if instrument: - i_name = instrument # ----------------------------------------------------------- # Support sardana v<2.4 (which used tango names instead of # taurus full names @@ -183,25 +174,34 @@ def createInstrumentsFromPool(gui, macroservername): if not e_name.startswith("tango://"): e_name = "tango://%s" % e_name # ----------------------------------------------------------- - instrument_dict[i_name].model.append(e_name) + instrument_dict[instrument].append(e_name) # filter out empty panels ret = [ - instrument - for instrument in instrument_dict.values() - if len(instrument.model) > 0 + i + for i in instrument_dict + if len(instrument_dict[i]) > 0 ] return ret @staticmethod - def loadInstrumentPanels(gui, poolinstruments): + def _createInstrumentPanels(gui, poolinstruments): """ - Create GUI panels from Sardana Pool instruments + Create GUI panels from Sardana Pool instruments. Each panel is a + TaurusForm grouping together all those elements that belong to + the same instrument according to the Pool info + + :param TaurusGui gui: isntance of TaurusGui + :param dict()) poolinstruments: dictionary where keys + are panel names and + values are lists of + models + :return: None """ - for p in poolinstruments: + for name, model in poolinstruments.items(): try: try: - gui.splashScreen().showMessage("Creating instrument panel %s" % p.name) + gui.splashScreen().showMessage("Creating instrument panel %s" % name) except AttributeError: pass from taurus.qt.qtgui.panel.taurusform import TaurusForm @@ -212,25 +212,20 @@ def loadInstrumentPanels(gui, poolinstruments): if gui._customWidgetMap: w.setCustomWidgetMap(gui._customWidgetMap) # ------------------------------------------------------------- - w.setModel(p.model) - instrumentkey = gui.IMPLICIT_ASSOCIATION + w.setModel(model) # the pool instruments may change when the pool config changes, # so we do not store their config - registerconfig = False - # create a panel - gui.createPanel( w, - p.name, + name, floating=False, registerconfig=False, - instrumentkey=instrumentkey, + instrumentkey=gui.IMPLICIT_ASSOCIATION, permanent=True, ) except Exception as e: - msg = "Cannot create instrument panel %s: %s" % (getattr( - p, "name", "__Unknown__"), str(e)) + msg = "Cannot create instrument panel %s: %s" % (name, str(e)) raise HookLoaderError(msg) From 6bff4ed07cb9233fea8a02b704a607978e8f55a2 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 19:43:15 +0200 Subject: [PATCH 75/99] PEP8 --- .../taurusgui/config_loader/back_compat.py | 4 +-- .../qtgui/taurusgui/config_loader/jsonconf.py | 11 +++++--- .../qtgui/taurusgui/config_loader/pyconf.py | 11 +++++--- .../qtgui/taurusgui/config_loader/sardana.py | 28 +++++++++---------- .../qt/qtgui/taurusgui/config_loader/util.py | 6 ++-- .../qtgui/taurusgui/config_loader/xmlconf.py | 11 +++++--- 6 files changed, 41 insertions(+), 30 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py index 491b8753e..6660e2bb8 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -24,11 +24,11 @@ """""" from taurus.external.qt import Qt from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader + AbstractConfigLoader, ) from taurus.qt.qtgui.taurusgui.config_loader.pyconf import PyConfigLoader -from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import XmlConfigLoader from taurus.qt.qtgui.taurusgui.config_loader.util import HookLoaderError +from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import XmlConfigLoader __all__ = ["BckCompatConfigLoader"] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 917e1e86d..8344cc781 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -27,12 +27,15 @@ import os from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader + AbstractConfigLoader, ) from taurus.qt.qtgui.taurusgui.config_loader.util import ConfigLoaderError -from taurus.qt.qtgui.taurusgui.utils import (AppletDescription, ExternalApp, - PanelDescription, - ToolBarDescription) +from taurus.qt.qtgui.taurusgui.utils import ( + AppletDescription, + ExternalApp, + PanelDescription, + ToolBarDescription, +) __all__ = ["JsonConfigLoader"] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index ae2766db0..58d74e76e 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -30,12 +30,15 @@ import types from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader + AbstractConfigLoader, ) from taurus.qt.qtgui.taurusgui.config_loader.util import ConfigLoaderError -from taurus.qt.qtgui.taurusgui.utils import (AppletDescription, ExternalApp, - PanelDescription, - ToolBarDescription) +from taurus.qt.qtgui.taurusgui.utils import ( + AppletDescription, + ExternalApp, + PanelDescription, + ToolBarDescription, +) __all__ = ["PyConfigLoader"] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index c50f48569..b947122e2 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -28,13 +28,9 @@ from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( AbstractConfigLoader, ) -from taurus.qt.qtgui.taurusgui.config_loader.pyconf import ( - PyConfigLoader, -) -from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import ( - XmlConfigLoader, -) +from taurus.qt.qtgui.taurusgui.config_loader.pyconf import PyConfigLoader from taurus.qt.qtgui.taurusgui.config_loader.util import HookLoaderError +from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import XmlConfigLoader __all__ = ["PySardanaConfigLoader", "XmlSardanaConfigLoader"] @@ -59,7 +55,9 @@ def __init__(self, confname): super(BaseSardanaConfigLoader, self).__init__(confname) # explicit copy of AbstractConfigLoader.CONFIG_VALUES is made on purpose # this way we avoid problems about changing it for other derived classes - self.CONFIG_VALUES = AbstractConfigLoader.CONFIG_VALUES[:] + self.SARDANA_VALUES + self.CONFIG_VALUES = ( + AbstractConfigLoader.CONFIG_VALUES[:] + self.SARDANA_VALUES + ) @property def hooks(self): @@ -151,7 +149,10 @@ def _getInstrumentsFromPool(gui, macroservername): if instruments is None: raise Exception() except Exception as e: - msg = 'Could not fetch Instrument list from "%s": %s' % (macroservername, str(e)) + msg = 'Could not fetch Instrument list from "%s": %s' % ( + macroservername, + str(e), + ) raise HookLoaderError(msg) for i in instruments.values(): @@ -176,11 +177,7 @@ def _getInstrumentsFromPool(gui, macroservername): # ----------------------------------------------------------- instrument_dict[instrument].append(e_name) # filter out empty panels - ret = [ - i - for i in instrument_dict - if len(instrument_dict[i]) > 0 - ] + ret = [i for i in instrument_dict if len(instrument_dict[i]) > 0] return ret @staticmethod @@ -201,10 +198,13 @@ def _createInstrumentPanels(gui, poolinstruments): for name, model in poolinstruments.items(): try: try: - gui.splashScreen().showMessage("Creating instrument panel %s" % name) + gui.splashScreen().showMessage( + "Creating instrument panel %s" % name + ) except AttributeError: pass from taurus.qt.qtgui.panel.taurusform import TaurusForm + w = TaurusForm() # ------------------------------------------------------------- diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py index 89c992cd8..b647270c4 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py @@ -33,7 +33,6 @@ from taurus import warning - __all__ = ["getLoaders", "ConfigLoaderError", "HookLoaderError"] @@ -53,7 +52,10 @@ class HookLoaderError(ConfigLoaderError): """ def __init__(self, message): - message = "Exception raised while executing config loader hookhook: " + message + message = ( + "Exception raised while executing config loader hookhook: " + + message + ) super(HookLoaderError, self).__init__(message) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index 3c3ba5d7c..c9c35ffb3 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -27,12 +27,15 @@ from lxml import etree from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader + AbstractConfigLoader, ) from taurus.qt.qtgui.taurusgui.config_loader.util import ConfigLoaderError -from taurus.qt.qtgui.taurusgui.utils import (AppletDescription, ExternalApp, - PanelDescription, - ToolBarDescription) +from taurus.qt.qtgui.taurusgui.utils import ( + AppletDescription, + ExternalApp, + PanelDescription, + ToolBarDescription, +) __all__ = ["XmlConfigLoader"] From bc2ab07c3870122d8a18655f8925ecc38510eccc Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 19:56:17 +0200 Subject: [PATCH 76/99] Simplify printing configuration --- .../qtgui/taurusgui/config_loader/__main__.py | 55 +++---------------- 1 file changed, 7 insertions(+), 48 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py index 9f240ced5..9fd010b33 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py @@ -1,56 +1,15 @@ import sys +from pprint import pprint -from . import getLoader - - -def print_component(p): - print("\n\tName: " + p.name) - print("\tClass name: " + p.classname) - print("\tModule name: " + p.modulename) - print("\tWidget name: " + str(p.widgetname)) - print("\tFloating: " + str(p.floating)) - print("\tShared data write: " + str(p.sharedDataWrite)) - print("\tShared data read: " + str(p.sharedDataRead)) - print("\tModel: " + str(p.model)) - - -def print_panel(p): - print_component(p) - print("\tInstrument key: " + str(p.instrumentkey)) - print("\tIcon: " + str(p.icon)) - print("\tModel in config: " + str(p.model_in_config)) - print("\tModifiable by user: " + str(p.modifiable_by_user)) - print("\tWidget formatter: " + str(p.widget_formatter)) - print("\tWidget properties: " + str(p.widget_properties)) +from .util import getLoaders def main(conf): - l = getLoader(conf) - l.load() - print("GUI_NAME: " + str(l.app_name)) - print("ORGANIZATION: " + str(l.org_name)) - print("CUSTOM_LOGO: " + str(l.custom_logo)) - print("ORGANIZATION_LOGO: " + str(l.org_logo)) - print("SINGLE_INSTANCE: " + str(l.single_instance)) - print("MANUAL_URI: " + str(l.manual_uri)) - print("INIFILE: " + str(l.ini_file)) - print("EXTRA_CATALOG_WIDGETS") - for w, i in l.extra_catalog_widgets: - print("\tWidget: " + str(w) + ", icon: " + str(i)) - print("SYNOPTIC: " + str(l.synoptics)) - print("CONSOLE: " + str(l.console)) - print("PanelDescriptions: ") - for p in l.panels: - print_panel(p) - print("ToolBarDescriptions: ") - for p in l.toolbars: - print_component(p) - print("AppletDescriptions: ") - for p in l.applets: - print_component(p) - print("ExternalApp: ") - for p in l.external_apps: - print("\t" + str(p)) + cfg = {} + loaders = getLoaders(conf) + for loader in loaders: + cfg.update(loader.load()) + pprint(cfg) main(sys.argv[1]) From 5afc4e9948d93fba21e151f3076ad04d79eadd67 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 20:05:29 +0200 Subject: [PATCH 77/99] Add method to cast TaurusGuiComponent to dictionary --- lib/taurus/qt/qtgui/taurusgui/utils.py | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/taurus/qt/qtgui/taurusgui/utils.py b/lib/taurus/qt/qtgui/taurusgui/utils.py index a1d9ade0c..563730b9c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/utils.py +++ b/lib/taurus/qt/qtgui/taurusgui/utils.py @@ -343,6 +343,23 @@ def fromXml(xmlstring): floating=floating, sharedDataWrite=sharedDataWrite, sharedDataRead=sharedDataRead, model=model) + def to_dict(self): + """ + Return dictionary representation of data + """ + tmp = { + "name": self.name, + "classname": self.classname, + "modulename": self.modulename, + "widgetname": self.widgetname, + "floating": self.floating, + "sharedDataWrite": self.sharedDataWrite, + "sharedDataRead": self.sharedDataRead, + "model": self.model, + } + + return tmp + #========================================================================= # Properties #========================================================================= @@ -433,6 +450,22 @@ def fromPanel(panel): widget_properties=panel.widget_properties ) + def to_dict(self): + """ + Return dictionary representation of data + """ + from_parent = TaurusGuiComponentDescription.to_dict(self) + custom = { + "instrumentkey": self.instrumentkey, + "icon": self.icon, + "model_in_config": self.model_in_config, + "modifiable_by_user": self.modifiable_by_user, + "widget_formatter": self.widget_formatter, + "widget_properties": self.widget_properties, + } + + return from_parent.update(custom) + class ToolBarDescription(TaurusGuiComponentDescription): ''' From 6b1622bfbc466ea50480754dd9c92bf6cb175a0d Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 20:12:58 +0200 Subject: [PATCH 78/99] Cast description obejcts to dictionaries to simplify printing --- lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py index 9fd010b33..7fc3b2748 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py @@ -9,6 +9,10 @@ def main(conf): loaders = getLoaders(conf) for loader in loaders: cfg.update(loader.load()) + cfg["PanelDescriptions"] = [p.to_dict() for p in cfg.get("PanelDescriptions", [])] + cfg["ToolbarDescriptions"] = [p.to_dict() for p in cfg.get("ToolbarDescriptions", [])] + cfg["AppletDescriptions"] = [p.to_dict() for p in cfg.get("AppletDescriptions", [])] + cfg["ExternalApps"] = [p.to_dict() for p in cfg.get("ExternalApps", [])] pprint(cfg) From a229e6c4bd7a6eda143167a01f6d20e0dfbca03f Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 20:22:54 +0200 Subject: [PATCH 79/99] Return dictionary, not result of 'update' call (None) --- lib/taurus/qt/qtgui/taurusgui/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/utils.py b/lib/taurus/qt/qtgui/taurusgui/utils.py index 563730b9c..e6baf4a7c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/utils.py +++ b/lib/taurus/qt/qtgui/taurusgui/utils.py @@ -463,8 +463,8 @@ def to_dict(self): "widget_formatter": self.widget_formatter, "widget_properties": self.widget_properties, } - - return from_parent.update(custom) + from_parent.update(custom) + return from_parent class ToolBarDescription(TaurusGuiComponentDescription): From b10acbc22411a8581a8688d70c4ba9a4ffc35315 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 20:23:14 +0200 Subject: [PATCH 80/99] Fix printing description objects --- .../qtgui/taurusgui/config_loader/__main__.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py index 7fc3b2748..09e7e2bc2 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py @@ -9,10 +9,19 @@ def main(conf): loaders = getLoaders(conf) for loader in loaders: cfg.update(loader.load()) - cfg["PanelDescriptions"] = [p.to_dict() for p in cfg.get("PanelDescriptions", [])] - cfg["ToolbarDescriptions"] = [p.to_dict() for p in cfg.get("ToolbarDescriptions", [])] - cfg["AppletDescriptions"] = [p.to_dict() for p in cfg.get("AppletDescriptions", [])] - cfg["ExternalApps"] = [p.to_dict() for p in cfg.get("ExternalApps", [])] + # pprint(cfg) + panels = [p.to_dict() for p in cfg.get("PanelDescriptions", [])] + cfg["PanelDescriptions"] = panels + + toolbars = [p.to_dict() for p in cfg.get("ToolBarDescriptions", [])] + cfg["ToolBarDescriptions"] = toolbars + + applets = [p.to_dict() for p in cfg.get("AppletDescriptions", [])] + cfg["AppletDescriptions"] = applets + + # ext_app = [p.to_dict() for p in cfg.get("ExternalApps", [])] + # cfg["ExternalApps"] = ext_app + pprint(cfg) From 372c8e523888bb434c4e9d87d3e795e30d42a3d5 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 20:26:17 +0200 Subject: [PATCH 81/99] Allow easy printing of ExternalApp objects --- lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py | 4 ++-- lib/taurus/qt/qtgui/taurusgui/utils.py | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py index 09e7e2bc2..715b1cdc4 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py @@ -19,8 +19,8 @@ def main(conf): applets = [p.to_dict() for p in cfg.get("AppletDescriptions", [])] cfg["AppletDescriptions"] = applets - # ext_app = [p.to_dict() for p in cfg.get("ExternalApps", [])] - # cfg["ExternalApps"] = ext_app + ext_app = [p.to_dict() for p in cfg.get("ExternalApps", [])] + cfg["ExternalApps"] = ext_app pprint(cfg) diff --git a/lib/taurus/qt/qtgui/taurusgui/utils.py b/lib/taurus/qt/qtgui/taurusgui/utils.py index e6baf4a7c..8b54eead9 100644 --- a/lib/taurus/qt/qtgui/taurusgui/utils.py +++ b/lib/taurus/qt/qtgui/taurusgui/utils.py @@ -113,6 +113,14 @@ def fromXml(xmlstring): return ExternalApp(" ".join((command, params)), text=text, icon=icon) + def to_dict(self): + tmp = { + "args": self.args, + "kwargs": self.kwargs, + } + + return tmp + class TaurusGuiComponentDescription(object): ''' From 94f9030294c68afadec34f737279524229a84c16 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 22:29:35 +0200 Subject: [PATCH 82/99] Move default values to DEFAULT_CONFIG variable --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 55 +++++++++++++--------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index c975a67e4..2295d6bb6 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -293,6 +293,23 @@ class TaurusGui(TaurusMainWindow): #: wether to add the Quick access Toolbar (empty by default) QUICK_ACCESS_TOOLBAR_ENABLED = True + # default gui configuration, GUI_NAME is mandatory so not present here + DEFAULT_CONFIG = { + "ORGANIZATION": str(Qt.qApp.organizationName()) or 'Taurus', + "CUSTOM_LOGO": 'logos:taurus.png', + "ORGANIZATION_LOGO": getattr(tauruscustomsettings, "ORGANIZATION_LOGO", "logos:taurus.png"), + "SINGLE_INSTANCE": True, + "EXTRA_CATALOG_WIDGETS": [], + "MANUAL_URI": taurus.Release.url, + "SYNOPTIC": [], + "CONF_DIR": os.path.expanduser("~"), # maybe '~/.config' ? + "INIFILE": os.path.join(os.path.expanduser("~", "default.ini")), + "PanelDescriptions": [], + "ToolbarDescriptions": [], + "AppletDescriptions": [], + "ExternalApps": [], + } + def __init__(self, parent=None, confname=None, configRecursionDepth=None, settingsname=None): TaurusMainWindow.__init__(self, parent, False, True) @@ -906,21 +923,21 @@ def createMainSynoptic(self, synopticname): toggleSynopticAction = synopticpanel.toggleViewAction() self.quickAccessToolBar.addAction(toggleSynopticAction) - def getConfigValue(self, conf, field, default=None): - return conf.get(field, default) + def getConfigValue(self, conf, field): + return conf[field] def loadConfiguration(self, confname): '''Reads a configuration file ''' - conf = {} + conf = copy.deepcopy(self.DEFAULT_CONFIG) # maybe no need for deep copy try: loaders = getLoaders(confname) for loader in loaders: conf.update(loader.load()) - if "CONF_DIR" in conf: - self._confDirectory = conf["CONF_DIR"] - else: - self._confDirectory = os.path.expanduser("~") + self._confDirectory = self.getConfigValue(conf, "CONF_DIR") + + if "GUI_NAME" not in conf: + raise Exception("Configuration missing required field 'GUI_NAME") except Exception: import traceback msg = 'Error loading configuration: %s' % traceback.format_exc() # repr(e) @@ -975,11 +992,11 @@ def _loadAppName(self, conf, confname): self.setWindowTitle(appname) def _loadOrgName(self, conf): - orgname = self.getConfigValue(conf, "ORGANIZATION", str(Qt.qApp.organizationName()) or 'Taurus') + orgname = self.getConfigValue(conf, "ORGANIZATION") Qt.qApp.setOrganizationName(orgname) def _loadCustomLogo(self, conf): - custom_logo = self.getConfigValue(conf, "CUSTOM_LOGO", 'logos:taurus.png') + custom_logo = self.getConfigValue(conf, "CUSTOM_LOGO") if Qt.QFile.exists(custom_logo): custom_icon = Qt.QIcon(custom_logo) else: @@ -990,10 +1007,7 @@ def _loadCustomLogo(self, conf): self.jorgsBar.addAction(custom_icon, Qt.qApp.applicationName()) def _loadOrgLogo(self, conf): - logo = getattr(tauruscustomsettings, - "ORGANIZATION_LOGO", - "logos:taurus.png") - org_logo = self.getConfigValue(conf, "ORGANIZATION_LOGO", logo) + org_logo = self.getConfigValue(conf, "ORGANIZATION_LOGO") if Qt.QFile.exists(org_logo): org_icon = Qt.QIcon(org_logo) else: @@ -1006,7 +1020,7 @@ def _loadSingleInstance(self, conf): """ if required, enforce that only one instance of this GUI can be run """ - single_inst = self.getConfigValue(conf, "SINGLE_INSTANCE", True) + single_inst = self.getConfigValue(conf, "SINGLE_INSTANCE") if single_inst: if not self.checkSingleInstance(): @@ -1022,7 +1036,7 @@ def _loadExtraCatalogWidgets(self, conf): get custom widget catalog entries """ # @todo: support also loading from xml - extra_catalog_widgets = self.getConfigValue(conf, "EXTRA_CATALOG_WIDGETS", []) + extra_catalog_widgets = self.getConfigValue(conf, "EXTRA_CATALOG_WIDGETS") self._extraCatalogWidgets = [] for class_name, pix_map_name in extra_catalog_widgets: # If a relative file name is given, the conf directory will be used @@ -1035,7 +1049,7 @@ def _loadManualUri(self, conf): """ manual panel """ - manual_uri = self.getConfigValue(conf, "MANUAL_URI", taurus.Release.url) + manual_uri = self.getConfigValue(conf, "MANUAL_URI") self.setHelpManualURI(manual_uri) if self.HELP_MENU_ENABLED: @@ -1044,7 +1058,7 @@ def _loadManualUri(self, conf): def _loadSynoptic(self, conf): # Synoptics - synoptic = self.getConfigValue(conf, "SYNOPTIC", []) + synoptic = self.getConfigValue(conf, "SYNOPTIC") if isinstance(synoptic, string_types): # old config file style self.warning( 'Deprecated usage of synoptic keyword (now it expects a list of paths). Please update your configuration file to: "synoptic=[\'%s\']".' % synoptic) @@ -1197,10 +1211,7 @@ def _loadIniFile(self, conf): get the "factory settings" filename. By default, it is called "default.ini" and resides in the configuration dir """ - ini_file = self.getConfigValue(conf, "INIFILE", "default.ini") - - # if a relative name is given, the conf dir is used as the root path - ini_file_name = os.path.join(self._confDirectory, ini_file) + ini_file = self.getConfigValue(conf, "INIFILE") # read the settings (or the factory settings if the regular file is not # found) @@ -1211,7 +1222,7 @@ def _loadIniFile(self, conf): self.splashScreen().showMessage(msg) except AttributeError: pass - self.loadSettings(factorySettingsFileName=ini_file_name) + self.loadSettings(factorySettingsFileName=ini_file) def setLockView(self, locked): self.setModifiableByUser(not locked) From 5dee71ae1da826ec4748d2d567c8ccbbfbc51dd6 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 22:31:14 +0200 Subject: [PATCH 83/99] Use unified way of refering to configuration fields --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 2295d6bb6..83b722343 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -1071,7 +1071,7 @@ def _loadCustomPanels(self, conf): get custom panel descriptions from the python config file, xml config and create panels based on the panel descriptions """ - for p in conf["PanelDescriptions"]: + for p in self.getConfigValue("PanelDescriptions"): try: try: self.splashScreen().showMessage("Creating panel %s" % p.name) @@ -1141,7 +1141,7 @@ def _loadCustomToolBars(self, conf): get custom toolbars descriptions from the python config file, xml config and create toolbars based on the descriptions """ - for d in conf["ToolbarDescriptinos"]: + for d in self.getConfigValue("ToolbarDescriptinos"): try: try: self.splashScreen().showMessage("Creating Toolbar %s" % d.name) @@ -1174,7 +1174,7 @@ def _loadCustomApplets(self, conf): get custom applet descriptions from the python config file, xml config and create applet based on the descriptions """ - for d in conf["AppletDescriptions"]: + for d in self.getConfigValue("AppletDescriptions"): try: try: self.splashScreen().showMessage("Creating applet %s" % d.name) @@ -1202,7 +1202,7 @@ def _loadExternalApps(self, conf): """ add external applications from both the python and the xml config files """ - for a in conf["ExternalApps"]: + for a in self.getConfigValue("ExternalApps"): self._external_app_names.append(str(a.getAction().text())) self.addExternalAppLauncher(a.getAction()) From da9893dcc5a0f5e164db784db44d381cd31288b1 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 22:45:54 +0200 Subject: [PATCH 84/99] Make conf private variable --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 91 +++++++++++----------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 83b722343..7dc67f7d7 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -293,23 +293,6 @@ class TaurusGui(TaurusMainWindow): #: wether to add the Quick access Toolbar (empty by default) QUICK_ACCESS_TOOLBAR_ENABLED = True - # default gui configuration, GUI_NAME is mandatory so not present here - DEFAULT_CONFIG = { - "ORGANIZATION": str(Qt.qApp.organizationName()) or 'Taurus', - "CUSTOM_LOGO": 'logos:taurus.png', - "ORGANIZATION_LOGO": getattr(tauruscustomsettings, "ORGANIZATION_LOGO", "logos:taurus.png"), - "SINGLE_INSTANCE": True, - "EXTRA_CATALOG_WIDGETS": [], - "MANUAL_URI": taurus.Release.url, - "SYNOPTIC": [], - "CONF_DIR": os.path.expanduser("~"), # maybe '~/.config' ? - "INIFILE": os.path.join(os.path.expanduser("~", "default.ini")), - "PanelDescriptions": [], - "ToolbarDescriptions": [], - "AppletDescriptions": [], - "ExternalApps": [], - } - def __init__(self, parent=None, confname=None, configRecursionDepth=None, settingsname=None): TaurusMainWindow.__init__(self, parent, False, True) @@ -317,6 +300,23 @@ def __init__(self, parent=None, confname=None, configRecursionDepth=None, if configRecursionDepth is not None: self.defaultConfigRecursionDepth = configRecursionDepth + # default gui configuration, GUI_NAME is mandatory so not present here + self.__conf = { + "ORGANIZATION": str(Qt.qApp.organizationName()) or 'Taurus', + "CUSTOM_LOGO": 'logos:taurus.png', + "ORGANIZATION_LOGO": getattr(tauruscustomsettings, "ORGANIZATION_LOGO", "logos:taurus.png"), + "SINGLE_INSTANCE": True, + "EXTRA_CATALOG_WIDGETS": [], + "MANUAL_URI": taurus.Release.url, + "SYNOPTIC": [], + "CONF_DIR": os.path.expanduser("~"), # maybe '~/.config' ? + "INIFILE": os.path.join(os.path.expanduser("~", "default.ini")), + "PanelDescriptions": [], + "ToolbarDescriptions": [], + "AppletDescriptions": [], + "ExternalApps": [], + } + self.__panels = {} self.__external_app = {} self.__external_app_actions = {} @@ -923,20 +923,19 @@ def createMainSynoptic(self, synopticname): toggleSynopticAction = synopticpanel.toggleViewAction() self.quickAccessToolBar.addAction(toggleSynopticAction) - def getConfigValue(self, conf, field): - return conf[field] + def getConfigValue(self, field): + return self.__conf[field] def loadConfiguration(self, confname): '''Reads a configuration file ''' - conf = copy.deepcopy(self.DEFAULT_CONFIG) # maybe no need for deep copy try: loaders = getLoaders(confname) for loader in loaders: - conf.update(loader.load()) - self._confDirectory = self.getConfigValue(conf, "CONF_DIR") + self.__conf.update(loader.load()) + self._confDirectory = self.getConfigValue("CONF_DIR") - if "GUI_NAME" not in conf: + if "GUI_NAME" not in self.__conf: raise Exception("Configuration missing required field 'GUI_NAME") except Exception: import traceback @@ -972,7 +971,7 @@ def loadConfiguration(self, confname): try: for loader in loaders: for hook in loader.hooks: - hook(self, conf) + hook(self, self.__conf) except Exception as e: msg = "Error while executing config hooks: " + repr(e) self.error(msg) @@ -986,17 +985,17 @@ def loadConfiguration(self, confname): if result == Qt.QMessageBox.Abort: sys.exit() - def _loadAppName(self, conf, confname): - appname = self.getConfigValue(conf, "GUI_NAME") + def _loadAppName(self, confname): + appname = self.getConfigValue("GUI_NAME") Qt.qApp.setApplicationName(appname) self.setWindowTitle(appname) - def _loadOrgName(self, conf): - orgname = self.getConfigValue(conf, "ORGANIZATION") + def _loadOrgName(self): + orgname = self.getConfigValue("ORGANIZATION") Qt.qApp.setOrganizationName(orgname) - def _loadCustomLogo(self, conf): - custom_logo = self.getConfigValue(conf, "CUSTOM_LOGO") + def _loadCustomLogo(self): + custom_logo = self.getConfigValue("CUSTOM_LOGO") if Qt.QFile.exists(custom_logo): custom_icon = Qt.QIcon(custom_logo) else: @@ -1006,8 +1005,8 @@ def _loadCustomLogo(self, conf): if self.APPLETS_TOOLBAR_ENABLED: self.jorgsBar.addAction(custom_icon, Qt.qApp.applicationName()) - def _loadOrgLogo(self, conf): - org_logo = self.getConfigValue(conf, "ORGANIZATION_LOGO") + def _loadOrgLogo(self): + org_logo = self.getConfigValue("ORGANIZATION_LOGO") if Qt.QFile.exists(org_logo): org_icon = Qt.QIcon(org_logo) else: @@ -1016,11 +1015,11 @@ def _loadOrgLogo(self, conf): if self.APPLETS_TOOLBAR_ENABLED: self.jorgsBar.addAction(org_icon, Qt.qApp.organizationName()) - def _loadSingleInstance(self, conf): + def _loadSingleInstance(self): """ if required, enforce that only one instance of this GUI can be run """ - single_inst = self.getConfigValue(conf, "SINGLE_INSTANCE") + single_inst = self.getConfigValue("SINGLE_INSTANCE") if single_inst: if not self.checkSingleInstance(): @@ -1031,12 +1030,12 @@ def _loadSingleInstance(self, conf): self, 'Multiple copies', msg, Qt.QMessageBox.Abort) sys.exit(1) - def _loadExtraCatalogWidgets(self, conf): + def _loadExtraCatalogWidgets(self): """ get custom widget catalog entries """ # @todo: support also loading from xml - extra_catalog_widgets = self.getConfigValue(conf, "EXTRA_CATALOG_WIDGETS") + extra_catalog_widgets = self.getConfigValue("EXTRA_CATALOG_WIDGETS") self._extraCatalogWidgets = [] for class_name, pix_map_name in extra_catalog_widgets: # If a relative file name is given, the conf directory will be used @@ -1045,20 +1044,20 @@ def _loadExtraCatalogWidgets(self, conf): pix_map_name = os.path.join(self._confDirectory, pix_map_name) self._extraCatalogWidgets.append((class_name, pix_map_name)) - def _loadManualUri(self, conf): + def _loadManualUri(self): """ manual panel """ - manual_uri = self.getConfigValue(conf, "MANUAL_URI") + manual_uri = self.getConfigValue("MANUAL_URI") self.setHelpManualURI(manual_uri) if self.HELP_MENU_ENABLED: self.createPanel(self.helpManualBrowser, 'Manual', permanent=True, icon=Qt.QIcon.fromTheme('help-browser')) - def _loadSynoptic(self, conf): + def _loadSynoptic(self): # Synoptics - synoptic = self.getConfigValue(conf, "SYNOPTIC") + synoptic = self.getConfigValue("SYNOPTIC") if isinstance(synoptic, string_types): # old config file style self.warning( 'Deprecated usage of synoptic keyword (now it expects a list of paths). Please update your configuration file to: "synoptic=[\'%s\']".' % synoptic) @@ -1066,7 +1065,7 @@ def _loadSynoptic(self, conf): for s in synoptic: self.createMainSynoptic(s) - def _loadCustomPanels(self, conf): + def _loadCustomPanels(self): """ get custom panel descriptions from the python config file, xml config and create panels based on the panel descriptions @@ -1136,7 +1135,7 @@ def _loadCustomPanels(self, conf): if result == Qt.QMessageBox.Abort: sys.exit() - def _loadCustomToolBars(self, conf): + def _loadCustomToolBars(self): """ get custom toolbars descriptions from the python config file, xml config and create toolbars based on the descriptions @@ -1169,7 +1168,7 @@ def _loadCustomToolBars(self, conf): if result == Qt.QMessageBox.Abort: sys.exit() - def _loadCustomApplets(self, conf): + def _loadCustomApplets(self): """ get custom applet descriptions from the python config file, xml config and create applet based on the descriptions @@ -1198,7 +1197,7 @@ def _loadCustomApplets(self, conf): if result == Qt.QMessageBox.Abort: sys.exit() - def _loadExternalApps(self, conf): + def _loadExternalApps(self): """ add external applications from both the python and the xml config files """ @@ -1206,12 +1205,12 @@ def _loadExternalApps(self, conf): self._external_app_names.append(str(a.getAction().text())) self.addExternalAppLauncher(a.getAction()) - def _loadIniFile(self, conf): + def _loadIniFile(self): """ get the "factory settings" filename. By default, it is called "default.ini" and resides in the configuration dir """ - ini_file = self.getConfigValue(conf, "INIFILE") + ini_file = self.getConfigValue("INIFILE") # read the settings (or the factory settings if the regular file is not # found) From cc9e428e1d7c565727a66608d5b2042d4aa40d1b Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 22:54:27 +0200 Subject: [PATCH 85/99] Adapt loaders to new API --- .../taurusgui/config_loader/back_compat.py | 6 ++-- .../qtgui/taurusgui/config_loader/sardana.py | 18 ++++++----- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 30 ++++++++++--------- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py index 6660e2bb8..d801841c8 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -67,8 +67,8 @@ def hooks(self): @staticmethod def loadMonitor(gui, conf): - monitor_model = gui.getConfigValue(conf, "MONITOR") - if monitor_model is None: + monitor_model = gui.getConfigValue("MONITOR", "") + if not monitor_model: return try: @@ -95,7 +95,7 @@ def loadConsole(gui, conf): Panel with a `silx.gui.console.IPythonWidget` """ # TODO: remove this method when making deprecation efective - if not gui.getConfigValue(conf, "CONSOLE", []): + if not gui.getConfigValue("CONSOLE", []): return msg = ( diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index ce11b450e..a18be82b5 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -71,7 +71,7 @@ def hooks(self): @staticmethod def _loadMacroServerName(gui, conf): - macro_server_name = gui.getConfigValue(conf, "MACROSERVER_NAME") + macro_server_name = gui.getConfigValue("MACROSERVER_NAME", "") if macro_server_name: gui.macroserverNameChanged.emit(macro_server_name) return macro_server_name @@ -79,24 +79,24 @@ def _loadMacroServerName(gui, conf): @staticmethod def _loadMacroBroker(gui, conf): """configure macro infrastructure""" - ms = gui.getConfigValue(conf, "MACROSERVER_NAME") - mp = gui.getConfigValue(conf, "MACRO_PANELS", True) + ms = gui.getConfigValue("MACROSERVER_NAME", "") + mp = gui.getConfigValue("MACRO_PANELS", True) # macro infrastructure will only be created if MACROSERVER_NAME is set - if ms is not None and mp is True: + if ms and mp is True: from sardana.taurus.qt.qtgui.macrolistener import MacroBroker gui.__macroBroker = MacroBroker(gui) @staticmethod def _loadDoorName(gui, conf): - door_name = gui.getConfigValue(conf, "DOOR_NAME", True) + door_name = gui.getConfigValue("DOOR_NAME", True) if door_name: gui.doorNameChanged.emit(door_name) @staticmethod def _loadMacroEditorsPath(gui, conf): macro_editors_path = gui.getConfigValue( - conf, "MACRO_EDITORS_PATH", True + "MACRO_EDITORS_PATH", True ) if macro_editors_path: from sardana.taurus.qt.qtgui.extra_macroexecutor.macroparameterseditor.macroparameterseditor import ( @@ -111,10 +111,12 @@ def _loadInstrumentsFromPool(self, gui, conf): Get panel descriptions from pool if required """ # todo: needs heavy refactor - ms = gui.getConfigValue(conf, "MACROSERVER_NAME") + ms = gui.getConfigValue("MACROSERVER_NAME", "") + if not ms: + return instruments_from_pool = gui.getConfigValue( - conf, "INSTRUMENTS_FROM_POOL", False + "INSTRUMENTS_FROM_POOL", False ) if instruments_from_pool: try: diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 7dc67f7d7..c3af2c6bd 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -923,7 +923,9 @@ def createMainSynoptic(self, synopticname): toggleSynopticAction = synopticpanel.toggleViewAction() self.quickAccessToolBar.addAction(toggleSynopticAction) - def getConfigValue(self, field): + def getConfigValue(self, field, default=None): + if default is not None: + return self.__conf.get(field, default) return self.__conf[field] def loadConfiguration(self, confname): @@ -945,28 +947,28 @@ def loadConfiguration(self, confname): self, 'Initialization error', msg, Qt.QMessageBox.Abort) sys.exit() - self._loadAppName(conf, confname) - self._loadOrgName(conf) - self._loadCustomLogo(conf) + self._loadAppName(confname) + self._loadOrgName() + self._loadCustomLogo() # do some extra config if we have a TaurusApplication _app = Qt.QApplication.instance() if hasattr(_app, 'basicConfig'): _app.basicConfig() - self._loadOrgLogo(conf) + self._loadOrgLogo() - self._loadSingleInstance(conf) + self._loadSingleInstance() - self._loadExtraCatalogWidgets(conf) - self._loadManualUri(conf) - self._loadSynoptic(conf) + self._loadExtraCatalogWidgets() + self._loadManualUri() + self._loadSynoptic() - self._loadCustomPanels(conf) - self._loadCustomToolBars(conf) - self._loadCustomApplets(conf) - self._loadExternalApps(conf) - self._loadIniFile(conf) + self._loadCustomPanels() + self._loadCustomToolBars() + self._loadCustomApplets() + self._loadExternalApps() + self._loadIniFile() try: for loader in loaders: From 6e89719db4e4881439db795269fbd7c88357d948 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Thu, 18 Jun 2020 22:56:13 +0200 Subject: [PATCH 86/99] Do not pass conf instance to hooks --- .../qt/qtgui/taurusgui/config_loader/abstract.py | 2 +- .../qt/qtgui/taurusgui/config_loader/back_compat.py | 4 ++-- lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py | 10 +++++----- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 50c86e51c..9b7470ad8 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -74,6 +74,6 @@ def hooks(self): """ List of hooks called at the end of 'TaurusGui.loadConfiguration' method. Each of them shall be called with 'TaurusGui' instance as - first argument and dictionary with configuration as second. + only argument. """ return [] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py index d801841c8..0485f750e 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -66,7 +66,7 @@ def hooks(self): return self.loadConsole, self.loadMonitor @staticmethod - def loadMonitor(gui, conf): + def loadMonitor(gui): monitor_model = gui.getConfigValue("MONITOR", "") if not monitor_model: return @@ -89,7 +89,7 @@ def loadMonitor(gui, conf): raise HookLoaderError(str(e)) @staticmethod - def loadConsole(gui, conf): + def loadConsole(gui): """ Deprecated CONSOLE command (if you need a IPython Console, just add a Panel with a `silx.gui.console.IPythonWidget` diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py index a18be82b5..6e40d9c76 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py @@ -70,14 +70,14 @@ def hooks(self): ) @staticmethod - def _loadMacroServerName(gui, conf): + def _loadMacroServerName(gui): macro_server_name = gui.getConfigValue("MACROSERVER_NAME", "") if macro_server_name: gui.macroserverNameChanged.emit(macro_server_name) return macro_server_name @staticmethod - def _loadMacroBroker(gui, conf): + def _loadMacroBroker(gui): """configure macro infrastructure""" ms = gui.getConfigValue("MACROSERVER_NAME", "") mp = gui.getConfigValue("MACRO_PANELS", True) @@ -88,13 +88,13 @@ def _loadMacroBroker(gui, conf): gui.__macroBroker = MacroBroker(gui) @staticmethod - def _loadDoorName(gui, conf): + def _loadDoorName(gui): door_name = gui.getConfigValue("DOOR_NAME", True) if door_name: gui.doorNameChanged.emit(door_name) @staticmethod - def _loadMacroEditorsPath(gui, conf): + def _loadMacroEditorsPath(gui): macro_editors_path = gui.getConfigValue( "MACRO_EDITORS_PATH", True ) @@ -106,7 +106,7 @@ def _loadMacroEditorsPath(gui, conf): ParamEditorManager().parsePaths(macro_editors_path) ParamEditorManager().browsePaths() - def _loadInstrumentsFromPool(self, gui, conf): + def _loadInstrumentsFromPool(self, gui): """ Get panel descriptions from pool if required """ diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index c3af2c6bd..d316c0fde 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -973,7 +973,7 @@ def loadConfiguration(self, confname): try: for loader in loaders: for hook in loader.hooks: - hook(self, self.__conf) + hook(self) except Exception as e: msg = "Error while executing config hooks: " + repr(e) self.error(msg) From 4ccdf92e3ebc17b3afc84d1908b842073e725a02 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 20 Jun 2020 20:40:45 +0200 Subject: [PATCH 87/99] Fix extending CONFIG_VALUES list --- lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py index 0485f750e..bb087fe8c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -51,12 +51,12 @@ def load(self): if PyConfigLoader.supports(self._confname): py = PyConfigLoader(self._confname) - py.CONFIG_VALUES + self.DEPRECATED_VALUES + py.CONFIG_VALUES += self.DEPRECATED_VALUES tmp.update(py.load()) if XmlConfigLoader.supports(self._confname): xml = XmlConfigLoader(self._confname) - xml.CONFIG_VALUES + self.DEPRECATED_VALUES + xml.CONFIG_VALUES += self.DEPRECATED_VALUES tmp.update(xml.load()) return tmp From c96d2eb6aa3b7cc5431d4397e9aeac010d7d1fe6 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 20 Jun 2020 20:46:46 +0200 Subject: [PATCH 88/99] Add support for XML_CONFIG field --- .../qt/qtgui/taurusgui/config_loader/back_compat.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py index bb087fe8c..681f9b85e 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py @@ -22,6 +22,8 @@ ########################################################################### """""" +import os + from taurus.external.qt import Qt from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( AbstractConfigLoader, @@ -38,7 +40,7 @@ class BckCompatConfigLoader(AbstractConfigLoader): Config loader which provides backward compatibility """ - DEPRECATED_VALUES = ["MONITOR", "CONSOLE"] + DEPRECATED_VALUES = ["MONITOR", "CONSOLE", "XML_CONFIG"] @staticmethod def supports(confname): @@ -59,6 +61,15 @@ def load(self): xml.CONFIG_VALUES += self.DEPRECATED_VALUES tmp.update(xml.load()) + xml_config = tmp.get("XML_CONFIG") + conf_dir = tmp.get("CONF_DIR") + if xml_config is not None: + if not os.path.isabs(xml_config) and conf_dir is not None: + xml_config = os.path.join(conf_dir, xml_config) + xml2 = XmlConfigLoader(xml_config) + xml2.CONFIG_VALUES += self.DEPRECATED_VALUES + tmp.update(xml2.load()) + return tmp @property From d41ccacd365956e8707fe825ee596371ae642087 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 20 Jun 2020 21:01:59 +0200 Subject: [PATCH 89/99] MAke GUI_NAME optional (default to confname) --- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index d316c0fde..81e2ef08b 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -300,8 +300,9 @@ def __init__(self, parent=None, confname=None, configRecursionDepth=None, if configRecursionDepth is not None: self.defaultConfigRecursionDepth = configRecursionDepth - # default gui configuration, GUI_NAME is mandatory so not present here + # default gui configuration self.__conf = { + "GUI_NAME": confname, "ORGANIZATION": str(Qt.qApp.organizationName()) or 'Taurus', "CUSTOM_LOGO": 'logos:taurus.png', "ORGANIZATION_LOGO": getattr(tauruscustomsettings, "ORGANIZATION_LOGO", "logos:taurus.png"), @@ -936,9 +937,6 @@ def loadConfiguration(self, confname): for loader in loaders: self.__conf.update(loader.load()) self._confDirectory = self.getConfigValue("CONF_DIR") - - if "GUI_NAME" not in self.__conf: - raise Exception("Configuration missing required field 'GUI_NAME") except Exception: import traceback msg = 'Error loading configuration: %s' % traceback.format_exc() # repr(e) From c9b26e7f0771250a48f7c0090120f2bfd1058db2 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 20 Jun 2020 23:24:35 +0200 Subject: [PATCH 90/99] Addd list of all Description classes along with configuration sections --- .../qt/qtgui/taurusgui/config_loader/abstract.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 9b7470ad8..78eb6ce06 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -24,6 +24,13 @@ """""" import abc +from taurus.qt.qtgui.taurusgui.utils import ( + AppletDescription, + ExternalApp, + PanelDescription, + ToolBarDescription, +) + # Python 2/3 compatibility if not hasattr(abc, "ABC"): setattr(abc, "ABC", abc.ABCMeta("ABC", (object,), {})) @@ -51,6 +58,13 @@ class AbstractConfigLoader(abc.ABC): "SYNOPTIC", ] + DESCRIPTIONS = [ + (AppletDescription, "AppletDescriptions"), + (ExternalApp, "ExternalApps"), + (PanelDescription, "PanelDescriptions"), + (ToolBarDescription, "ToolBarDescriptions"), + ] + def __init__(self, confname): self._confname = confname From f3b9adfba4c68aef850d967fe7c5ad82952dbb99 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 20 Jun 2020 23:26:08 +0200 Subject: [PATCH 91/99] Add helper method for generating pure Python dictionary from configuration dictionary --- .../qt/qtgui/taurusgui/config_loader/__main__.py | 12 +----------- .../qt/qtgui/taurusgui/config_loader/abstract.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py index 715b1cdc4..c3d609195 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py @@ -9,18 +9,8 @@ def main(conf): loaders = getLoaders(conf) for loader in loaders: cfg.update(loader.load()) - # pprint(cfg) - panels = [p.to_dict() for p in cfg.get("PanelDescriptions", [])] - cfg["PanelDescriptions"] = panels - toolbars = [p.to_dict() for p in cfg.get("ToolBarDescriptions", [])] - cfg["ToolBarDescriptions"] = toolbars - - applets = [p.to_dict() for p in cfg.get("AppletDescriptions", [])] - cfg["AppletDescriptions"] = applets - - ext_app = [p.to_dict() for p in cfg.get("ExternalApps", [])] - cfg["ExternalApps"] = ext_app + cfg = loaders[0].to_dict(cfg) pprint(cfg) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 78eb6ce06..d4764fb1c 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -91,3 +91,14 @@ def hooks(self): only argument. """ return [] + + def to_dict(self, conf): + """ + Generate pure Python dictionary from conf + """ + + for _, section in self.DESCRIPTIONS: + objs = [o.to_dict() for o in conf.get(section, [])] + conf[section] = objs + + return conf From 24b5651e16b0c6179396ccc508e7da065889b33e Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 20 Jun 2020 23:29:34 +0200 Subject: [PATCH 92/99] Use existing DESCRIPTIONS list --- .../qtgui/taurusgui/config_loader/jsonconf.py | 20 ++++--------------- .../qtgui/taurusgui/config_loader/pyconf.py | 15 ++------------ .../qtgui/taurusgui/config_loader/xmlconf.py | 13 ++++-------- 3 files changed, 10 insertions(+), 38 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 8344cc781..65279fbb7 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -30,12 +30,6 @@ AbstractConfigLoader, ) from taurus.qt.qtgui.taurusgui.config_loader.util import ConfigLoaderError -from taurus.qt.qtgui.taurusgui.utils import ( - AppletDescription, - ExternalApp, - PanelDescription, - ToolBarDescription, -) __all__ = ["JsonConfigLoader"] @@ -49,13 +43,12 @@ def __init__(self, confname): super(JsonConfigLoader, self).__init__(confname) self._data = {} - def _get_objects(self, klass): + def _get_objects(self, klass, section): """ Helper function to get list of Python objects from dictionary """ objs = [] - classname = klass.__name__ + "s" # 's' is for plural form - for o in self._data.get(classname, []): + for o in self._data.get(section, []): if isinstance(o, dict): objs.append(klass(**o)) return objs @@ -90,13 +83,8 @@ def load(self): if v in self._data: tmp[v] = self._data[v] - for klass in ( - PanelDescription, - ToolBarDescription, - AppletDescription, - ExternalApp, - ): - tmp[klass.__name__ + "s"] = self._get_objects(klass) + for klass, section in self.DESCRIPTIONS: + tmp[section] = self._get_objects(klass, section) self._data.update(tmp) self._data["CONF_DIR"] = os.path.abspath( diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 58d74e76e..631f0eb5e 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -33,12 +33,6 @@ AbstractConfigLoader, ) from taurus.qt.qtgui.taurusgui.config_loader.util import ConfigLoaderError -from taurus.qt.qtgui.taurusgui.utils import ( - AppletDescription, - ExternalApp, - PanelDescription, - ToolBarDescription, -) __all__ = ["PyConfigLoader"] @@ -145,13 +139,8 @@ def load(self): if hasattr(self._mod, v): tmp[v] = getattr(self._mod, v) - for klass in ( - PanelDescription, - AppletDescription, - ToolBarDescription, - ExternalApp, - ): - tmp[klass.__name__ + "s"] = self._get_objects(klass) + for klass, section in self.DESCRIPTIONS: + tmp[section] = self._get_objects(klass) return tmp diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index c9c35ffb3..c3e4f1e85 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -59,12 +59,12 @@ def _get(self, nodename, default=None): else: return name.text - def _get_objects(self, klass): + def _get_objects(self, klass, section): """ Helper method to get list of objects of given Python class """ objs = [] - obj = self._root.find(klass.__name__ + "s") # 's' is for plural form + obj = self._root.find(section) # 's' is for plural form if obj is not None: for child in obj: if child.tag == klass.__name__: @@ -107,13 +107,8 @@ def load(self): if name is not None and name.text is not None: tmp[v] = name.text - for klass in ( - PanelDescription, - ToolBarDescription, - AppletDescription, - ExternalApp, - ): - tmp[klass.__name__ + "s"] = self._get_objects(klass) + for klass, section in self.DESCRIPTIONS: + tmp[section] = self._get_objects(klass, section) tmp["CONF_DIR"] = os.path.abspath(os.path.dirname(self._confname)) From 19b22a0c55b9694a38cb0db7b9842e0d12d0d456 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Sat, 20 Jun 2020 23:30:05 +0200 Subject: [PATCH 93/99] Fix JSON loader --- lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 65279fbb7..5ab5373a3 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -85,13 +85,12 @@ def load(self): for klass, section in self.DESCRIPTIONS: tmp[section] = self._get_objects(klass, section) - self._data.update(tmp) - self._data["CONF_DIR"] = os.path.abspath( + tmp["CONF_DIR"] = os.path.abspath( os.path.dirname(self._confname) ) - return self._data + return tmp @property def hooks(self): From 8dcca4689ac37246b72725bc93949fe1df74999a Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 22 Jun 2020 20:35:18 +0200 Subject: [PATCH 94/99] Add skeleton of tests for PYthon configuration --- .../qtgui/taurusgui/test/test_configs/good.py | 22 ++++++++++++++++ .../taurusgui/test/test_python_config.py | 26 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 lib/taurus/qt/qtgui/taurusgui/test/test_configs/good.py create mode 100644 lib/taurus/qt/qtgui/taurusgui/test/test_python_config.py diff --git a/lib/taurus/qt/qtgui/taurusgui/test/test_configs/good.py b/lib/taurus/qt/qtgui/taurusgui/test/test_configs/good.py new file mode 100644 index 000000000..749e02dda --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/test/test_configs/good.py @@ -0,0 +1,22 @@ +from taurus.qt.qtgui.taurusgui import utils + + +GUI_NAME = "TestGUI" +ORGANIZATION = "TestOrg" +CUSTOM_LOGO = "" +ORGANIZATION_LOGO = "" +SINGLE_INSTANCE = False +MANUAL_URI = "http://example.com" +INIFILE = "" + +p1 = utils.PanelDescription( + "testpanel1", + classname="taurus.qt.qtgui.panel.TaurusForm", + model=["eval:1"], +) + +p2 = utils.PanelDescription( + "testpanel2", + classname="taurus.qt.qtgui.panel.TaurusForm", + model=["eval:2"], +) diff --git a/lib/taurus/qt/qtgui/taurusgui/test/test_python_config.py b/lib/taurus/qt/qtgui/taurusgui/test/test_python_config.py new file mode 100644 index 000000000..c72d6dfcc --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/test/test_python_config.py @@ -0,0 +1,26 @@ +import os + +from taurus.qt.qtgui.taurusgui import TaurusGui +from taurus.qt.qtgui.panel import TaurusForm + + +def test_good_config(qtbot): + conf = os.path.join(os.path.abspath(__file__), "test_configs", "good.py") + gui = TaurusGui(confname=conf, configRecursionDepth=0) + + qtbot.addWidget(gui) + assert gui.getConfigValue("GUI_NAME") == "TestGUI" + assert gui.getConfigValue("ORGANIZATION") == "TestOrg" + assert gui.getConfigValue("CUSTOM_LOGO") == "" + assert gui.getConfigValue("ORGANIZATION_LOGO") == "" + assert gui.getConfigValue("SINGLE_INSTANCE") is False + assert gui.getConfigValue("MANUAL_URI") == "http://example.com" + assert gui.getConfigValue("INIFILE") == "" + + w1 = gui.getPanel('testpanel1').widget() + qtbot.addWidget(w1) + assert isinstance(w1, TaurusForm) + + w2 = gui.getPanel('testpanel2').widget() + qtbot.addWidget(w2) + assert isinstance(w2, TaurusForm) From f352cba5da5a748c0d4d9af293d8a2454c4dd1f6 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 8 Feb 2021 00:15:09 +0100 Subject: [PATCH 95/99] Add new entrypoint for loading custom config properties --- .../taurusgui/config_properties/__init__.py | 22 ++ .../taurusgui/config_properties/bck_compat.py | 42 ++++ .../taurusgui/config_properties/deprecated.py | 80 ++++++++ .../taurusgui/config_properties/jdraw.py | 62 ++++++ .../taurusgui/config_properties/sardana.py | 191 ++++++++++++++++++ lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 56 ----- setup.py | 11 + 7 files changed, 408 insertions(+), 56 deletions(-) create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_properties/__init__.py create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_properties/bck_compat.py create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_properties/deprecated.py create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_properties/jdraw.py create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_properties/sardana.py diff --git a/lib/taurus/qt/qtgui/taurusgui/config_properties/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_properties/__init__.py new file mode 100644 index 000000000..28cbba72e --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_properties/__init__.py @@ -0,0 +1,22 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### diff --git a/lib/taurus/qt/qtgui/taurusgui/config_properties/bck_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_properties/bck_compat.py new file mode 100644 index 000000000..5474b815f --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_properties/bck_compat.py @@ -0,0 +1,42 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + + +""" +Module for backwards-compatible configuration loading +""" + + +def loadXmlConf(gui): + xml_conf = gui.getConfigValue("XML_CONF") + if xml_conf is None: + return + + try: + from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import XmlConfigLoader + + xcl = XmlConfigLoader(xml_conf) + cfg = xcl.load() + gui.__config.update(cfg) + except Exception as e: + gui.warning("Could not load configuration from XML_CONF=%s" % xml_conf) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_properties/deprecated.py b/lib/taurus/qt/qtgui/taurusgui/config_properties/deprecated.py new file mode 100644 index 000000000..3b52ed767 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_properties/deprecated.py @@ -0,0 +1,80 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + +""" +Provide loading of deprecated TaurusGUI config properties +""" + +from taurus.external.qt import Qt + + +def loadMonitor(gui): + monitor_model = gui.getConfigValue("MONITOR", "") + if not monitor_model: + return + + try: + gui.splashScreen().showMessage("Creating applet monitor") + except AttributeError: + pass + + from taurus.qt.qtgui.qwt5.monitor import TaurusMonitorTiny + + w = TaurusMonitorTiny() + w.setModel(monitor_model) + # add the widget to the applets toolbar + gui.jorgsBar.addWidget(w) + # register the toolbar as delegate + gui.registerConfigDelegate(w, "monitor") + + +def loadConsole(gui): + """ + Deprecated CONSOLE command (if you need a IPython Console, just add a + Panel with a `silx.gui.console.IPythonWidget` + """ + # TODO: remove this method when making deprecation efective + if not gui.getConfigValue("CONSOLE", []): + return + + msg = ( + "createConsole() and the 'CONSOLE' configuration key are " + + "deprecated since 4.0.4. Add a panel with a " + + "silx.gui.console.IPythonWidget widdget instead" + ) + gui.deprecated(msg) + try: + from silx.gui.console import IPythonWidget + except ImportError: + gui.warning( + "Cannot import taurus.qt.qtgui.console. " + + "The Console Panel will not be available" + ) + return + console = IPythonWidget() + gui.createPanel( + console, + "Console", + permanent=True, + icon=Qt.QIcon.fromTheme("utilities-terminal"), + ) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_properties/jdraw.py b/lib/taurus/qt/qtgui/taurusgui/config_properties/jdraw.py new file mode 100644 index 000000000..c0ab807e0 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_properties/jdraw.py @@ -0,0 +1,62 @@ +import os +import sys + +from future.utils import string_types +import taurus +from taurus.external.qt import Qt + + +def loadSynoptic(gui): + # Synoptics + synoptic = gui.getConfigValue("SYNOPTIC") + if isinstance(synoptic, string_types): # old config file style + gui.warning( + 'Deprecated usage of synoptic keyword (now it expects a list of paths). Please update your configuration file to: "synoptic=[\'%s\']".' % synoptic) + synoptic = [synoptic] + for s in synoptic: + _createMainSynoptic(gui, s) + + +def _createMainSynoptic(gui, synopticname): + ''' + Creates a synoptic panel and registers it as "SelectedInstrument" + reader and writer (allowing selecting instruments from synoptic + ''' + try: + jdwFileName = os.path.join(gui._confDirectory, synopticname) + from taurus.qt.qtgui.graphic import TaurusJDrawSynopticsView + synoptic = TaurusJDrawSynopticsView() + synoptic.setModel(jdwFileName) + gui.__synoptics.append(synoptic) + except Exception as e: + # print repr(e) + msg = 'Error loading synoptic file "%s".\nSynoptic won\'t be available' % jdwFileName + gui.error(msg) + gui.traceback(level=taurus.Info) + result = Qt.QMessageBox.critical(gui, 'Initialization error', '%s\n\n%s' % ( + msg, repr(e)), Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore) + if result == Qt.QMessageBox.Abort: + sys.exit() + + Qt.qApp.SDM.connectWriter( + "SelectedInstrument", synoptic, "graphicItemSelected") + Qt.qApp.SDM.connectReader( + "SelectedInstrument", synoptic.selectGraphicItem) + + # find an unique (and short) name + name = os.path.splitext(os.path.basename(synopticname))[0] + if len(name) > 10: + name = 'Syn' + i = 2 + prefix = name + while name in gui.__panels: + name = '%s_%i' % (prefix, i) + i += 1 + + synopticpanel = gui.createPanel(synoptic, name, permanent=True, + icon=Qt.QIcon.fromTheme( + 'image-x-generic')) + + if gui.QUICK_ACCESS_TOOLBAR_ENABLED: + toggleSynopticAction = synopticpanel.toggleViewAction() + gui.quickAccessToolBar.addAction(toggleSynopticAction) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_properties/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_properties/sardana.py new file mode 100644 index 000000000..3e55b21cc --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_properties/sardana.py @@ -0,0 +1,191 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + +""" +Module for loading Sardana-specific config properties +""" + +from operator import attrgetter + +from taurus import Device + + +def loadMacroServerName(gui): + macro_server_name = gui.getConfigValue("MACROSERVER_NAME", "") + if macro_server_name: + gui.macroserverNameChanged.emit(macro_server_name) + return macro_server_name + + +def loadMacroBroker(gui): + """configure macro infrastructure""" + ms = gui.getConfigValue("MACROSERVER_NAME", "") + mp = gui.getConfigValue("MACRO_PANELS", True) + # macro infrastructure will only be created if MACROSERVER_NAME is set + if ms and mp is True: + from sardana.taurus.qt.qtgui.macrolistener import MacroBroker + + gui.__macroBroker = MacroBroker(gui) + + +def loadDoorName(gui): + door_name = gui.getConfigValue("DOOR_NAME", True) + if door_name: + gui.doorNameChanged.emit(door_name) + + @staticmethod + def _loadMacroEditorsPath(gui): + macro_editors_path = gui.getConfigValue( + "MACRO_EDITORS_PATH", True + ) + if macro_editors_path: + from sardana.taurus.qt.qtgui.extra_macroexecutor.macroparameterseditor.macroparameterseditor import ( + ParamEditorManager, + ) + + ParamEditorManager().parsePaths(macro_editors_path) + ParamEditorManager().browsePaths() + +def loadInstrumentsFromPool(self, gui): + """ + Get panel descriptions from pool if required + """ + # todo: needs heavy refactor + ms = gui.getConfigValue("MACROSERVER_NAME", "") + if not ms: + return + + instruments_from_pool = gui.getConfigValue( + "INSTRUMENTS_FROM_POOL", False + ) + if instruments_from_pool: + try: + gui.splashScreen().showMessage( + "Gathering Instrument info from Pool" + ) + except AttributeError: + pass + + pool_instruments = _getInstrumentsFromPool(gui, ms) + if pool_instruments: + _createInstrumentPanels(gui, pool_instruments) + + +def _getInstrumentsFromPool(gui, macroservername): + """ + Get Instruments information form Pool. Return models for + each instrument. + + :param TaurusGui gui: instance of TaurusGui + :param str macroservername: name of MacroServer + + :return: Dicionary with Pool instruments where values are lists + of models + :rtype: dict()>) + """ + # todo: needs heavy refactor + instrument_dict = {} + try: + ms = Device(macroservername) + instruments = ms.getElementsOfType("Instrument") + if instruments is None: + raise Exception() + except Exception as e: + msg = 'Could not fetch Instrument list from "%s": %s' % ( + macroservername, + str(e), + ) + raise type(e)(msg) + + for i in instruments.values(): + instrument_dict[i.full_name] = [] + + pool_elements = [] + for kls in ("Moveable", "ExpChannel", "IORegister"): + pool_elements += sorted( + ms.getElementsWithInterface(kls).values(), + key=attrgetter("name"), + ) + + for elem in pool_elements: + instrument = elem.instrument + if instrument: + # ----------------------------------------------------------- + # Support sardana v<2.4 (which used tango names instead of + # taurus full names + e_name = elem.full_name + if not e_name.startswith("tango://"): + e_name = "tango://%s" % e_name + # ----------------------------------------------------------- + instrument_dict[instrument].append(e_name) + # filter out empty panels + ret = [i for i in instrument_dict if len(instrument_dict[i]) > 0] + return ret + + +def _createInstrumentPanels(gui, poolinstruments): + """ + Create GUI panels from Sardana Pool instruments. Each panel is a + TaurusForm grouping together all those elements that belong to + the same instrument according to the Pool info + + :param TaurusGui gui: isntance of TaurusGui + :param dict()) poolinstruments: dictionary where keys + are panel names and + values are lists of + models + :return: None + """ + + for name, model in poolinstruments.items(): + try: + try: + gui.splashScreen().showMessage( + "Creating instrument panel %s" % name + ) + except AttributeError: + pass + from taurus.qt.qtgui.panel.taurusform import TaurusForm + + w = TaurusForm() + + # ------------------------------------------------------------- + # Backwards-compat. Remove when removing CW map support + if gui._customWidgetMap: + w.setCustomWidgetMap(gui._customWidgetMap) + # ------------------------------------------------------------- + w.setModel(model) + + # the pool instruments may change when the pool config changes, + # so we do not store their config + gui.createPanel( + w, + name, + floating=False, + registerconfig=False, + instrumentkey=gui.IMPLICIT_ASSOCIATION, + permanent=True, + ) + except Exception as e: + msg = "Cannot create instrument panel %s: %s" % (name, str(e)) + raise type(e)(msg) diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 81e2ef08b..f1385c9aa 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -34,7 +34,6 @@ import click import weakref -from future.utils import string_types from lxml import etree import taurus @@ -880,50 +879,6 @@ def createCustomPanel(self, paneldesc=None): msg = 'Panel %s created. Drag items to it or use the context menu to customize it' % w.name self.newShortMessage.emit(msg) - def createMainSynoptic(self, synopticname): - ''' - Creates a synoptic panel and registers it as "SelectedInstrument" - reader and writer (allowing selecting instruments from synoptic - ''' - try: - jdwFileName = os.path.join(self._confDirectory, synopticname) - from taurus.qt.qtgui.graphic import TaurusJDrawSynopticsView - synoptic = TaurusJDrawSynopticsView() - synoptic.setModel(jdwFileName) - self.__synoptics.append(synoptic) - except Exception as e: - # print repr(e) - msg = 'Error loading synoptic file "%s".\nSynoptic won\'t be available' % jdwFileName - self.error(msg) - self.traceback(level=taurus.Info) - result = Qt.QMessageBox.critical(self, 'Initialization error', '%s\n\n%s' % ( - msg, repr(e)), Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore) - if result == Qt.QMessageBox.Abort: - sys.exit() - - Qt.qApp.SDM.connectWriter( - "SelectedInstrument", synoptic, "graphicItemSelected") - Qt.qApp.SDM.connectReader( - "SelectedInstrument", synoptic.selectGraphicItem) - - # find an unique (and short) name - name = os.path.splitext(os.path.basename(synopticname))[0] - if len(name) > 10: - name = 'Syn' - i = 2 - prefix = name - while name in self.__panels: - name = '%s_%i' % (prefix, i) - i += 1 - - synopticpanel = self.createPanel(synoptic, name, permanent=True, - icon=Qt.QIcon.fromTheme( - 'image-x-generic')) - - if self.QUICK_ACCESS_TOOLBAR_ENABLED: - toggleSynopticAction = synopticpanel.toggleViewAction() - self.quickAccessToolBar.addAction(toggleSynopticAction) - def getConfigValue(self, field, default=None): if default is not None: return self.__conf.get(field, default) @@ -960,7 +915,6 @@ def loadConfiguration(self, confname): self._loadExtraCatalogWidgets() self._loadManualUri() - self._loadSynoptic() self._loadCustomPanels() self._loadCustomToolBars() @@ -1054,16 +1008,6 @@ def _loadManualUri(self): if self.HELP_MENU_ENABLED: self.createPanel(self.helpManualBrowser, 'Manual', permanent=True, icon=Qt.QIcon.fromTheme('help-browser')) - - def _loadSynoptic(self): - # Synoptics - synoptic = self.getConfigValue("SYNOPTIC") - if isinstance(synoptic, string_types): # old config file style - self.warning( - 'Deprecated usage of synoptic keyword (now it expects a list of paths). Please update your configuration file to: "synoptic=[\'%s\']".' % synoptic) - synoptic = [synoptic] - for s in synoptic: - self.createMainSynoptic(s) def _loadCustomPanels(self): """ diff --git a/setup.py b/setup.py index 0493fcef5..e6257f26c 100644 --- a/setup.py +++ b/setup.py @@ -134,6 +134,17 @@ def get_release_info(): 'taurus.sardana.xml = taurus.qt.qtgui.taurusgui.config_loader.sardana:XmlSardanaConfigLoader', ] +config_properties = [ + 'DOOR_NAME = taurus.qt.qtgui.taurusgui.config_properties.sardana:loadDoorName', + 'MACROSERVER_NAME = taurus.qt.qtgui.taurusgui.config_properties.sardana:loadMacroServerName', + 'MACRO_PANELS = taurus.qt.qtgui.taurusgui.config_properties.sardana:loadMacroBroker', + 'INSTRUMENTS_FROM_POOL = taurus.qt.qtgui.taurusgui.config_properties.sardana:loadInstrumentsFromPool', + 'MONITOR = taurus.qt.qtgui.taurusgui.config_properties.deprecated:loadMonitor', + 'CONSOLE = taurus.qt.qtgui.taurusgui.config_properties.deprecated:loadConsole', + 'XML_CONF = taurus.qt.qtgui.taurusgui.config_properties.bck_compat:loadXmlConf', + 'SYNOPTIC = taurus.qt.qtgui.taurusgui.config_properties.jdraw:loadSynoptic' +] + entry_points = { 'console_scripts': console_scripts, 'taurus.cli.subcommands': taurus_subcommands, From eee64412f1572d76e576c9b89828eb40c05b87cf Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 8 Feb 2021 00:16:23 +0100 Subject: [PATCH 96/99] Remove redundant config loaders --- .../taurusgui/config_loader/back_compat.py | 132 ---------- .../qtgui/taurusgui/config_loader/sardana.py | 239 ------------------ setup.py | 3 - 3 files changed, 374 deletions(-) delete mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py delete mode 100644 lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py deleted file mode 100644 index 681f9b85e..000000000 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/back_compat.py +++ /dev/null @@ -1,132 +0,0 @@ -############################################################################# -## -# This file is part of Taurus -## -# http://taurus-scada.org -## -# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain -## -# Taurus is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -## -# Taurus is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -## -# You should have received a copy of the GNU Lesser General Public License -# along with Taurus. If not, see . -## -########################################################################### - -"""""" -import os - -from taurus.external.qt import Qt -from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, -) -from taurus.qt.qtgui.taurusgui.config_loader.pyconf import PyConfigLoader -from taurus.qt.qtgui.taurusgui.config_loader.util import HookLoaderError -from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import XmlConfigLoader - -__all__ = ["BckCompatConfigLoader"] - - -class BckCompatConfigLoader(AbstractConfigLoader): - """ - Config loader which provides backward compatibility - """ - - DEPRECATED_VALUES = ["MONITOR", "CONSOLE", "XML_CONFIG"] - - @staticmethod - def supports(confname): - return PyConfigLoader.supports(confname) or XmlConfigLoader.supports( - confname - ) - - def load(self): - tmp = {} - - if PyConfigLoader.supports(self._confname): - py = PyConfigLoader(self._confname) - py.CONFIG_VALUES += self.DEPRECATED_VALUES - tmp.update(py.load()) - - if XmlConfigLoader.supports(self._confname): - xml = XmlConfigLoader(self._confname) - xml.CONFIG_VALUES += self.DEPRECATED_VALUES - tmp.update(xml.load()) - - xml_config = tmp.get("XML_CONFIG") - conf_dir = tmp.get("CONF_DIR") - if xml_config is not None: - if not os.path.isabs(xml_config) and conf_dir is not None: - xml_config = os.path.join(conf_dir, xml_config) - xml2 = XmlConfigLoader(xml_config) - xml2.CONFIG_VALUES += self.DEPRECATED_VALUES - tmp.update(xml2.load()) - - return tmp - - @property - def hooks(self): - return self.loadConsole, self.loadMonitor - - @staticmethod - def loadMonitor(gui): - monitor_model = gui.getConfigValue("MONITOR", "") - if not monitor_model: - return - - try: - try: - gui.splashScreen().showMessage("Creating applet monitor") - except AttributeError: - pass - - from taurus.qt.qtgui.qwt5.monitor import TaurusMonitorTiny - - w = TaurusMonitorTiny() - w.setModel(monitor_model) - # add the widget to the applets toolbar - gui.jorgsBar.addWidget(w) - # register the toolbar as delegate - gui.registerConfigDelegate(w, "monitor") - except Exception as e: - raise HookLoaderError(str(e)) - - @staticmethod - def loadConsole(gui): - """ - Deprecated CONSOLE command (if you need a IPython Console, just add a - Panel with a `silx.gui.console.IPythonWidget` - """ - # TODO: remove this method when making deprecation efective - if not gui.getConfigValue("CONSOLE", []): - return - - msg = ( - "createConsole() and the 'CONSOLE' configuration key are " - + "deprecated since 4.0.4. Add a panel with a " - + "silx.gui.console.IPythonWidget widdget instead" - ) - gui.deprecated(msg) - try: - from silx.gui.console import IPythonWidget - except ImportError: - gui.warning( - "Cannot import taurus.qt.qtgui.console. " - + "The Console Panel will not be available" - ) - return - console = IPythonWidget() - gui.createPanel( - console, - "Console", - permanent=True, - icon=Qt.QIcon.fromTheme("utilities-terminal"), - ) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py deleted file mode 100644 index 6e40d9c76..000000000 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/sardana.py +++ /dev/null @@ -1,239 +0,0 @@ -############################################################################# -## -# This file is part of Taurus -## -# http://taurus-scada.org -## -# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain -## -# Taurus is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -## -# Taurus is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -## -# You should have received a copy of the GNU Lesser General Public License -# along with Taurus. If not, see . -## -########################################################################### - -"""""" -from operator import attrgetter - -from taurus import Device -from taurus.qt.qtgui.taurusgui.config_loader.abstract import ( - AbstractConfigLoader, -) -from taurus.qt.qtgui.taurusgui.config_loader.pyconf import PyConfigLoader -from taurus.qt.qtgui.taurusgui.config_loader.util import HookLoaderError -from taurus.qt.qtgui.taurusgui.config_loader.xmlconf import XmlConfigLoader - -__all__ = ["PySardanaConfigLoader", "XmlSardanaConfigLoader"] - - -class BaseSardanaConfigLoader(AbstractConfigLoader): - """ - Config loader which loads Sardana-related values. - This lives as a hack for manipulating AbstractLoader.CONFIG_VALUES. - It does not load anything by itself, just injects new values into - CONFIG_VALUES so other loaders will load them. - """ - - SARDANA_VALUES = [ - "MACROSERVER_NAME", - "MACRO_PANELS", - "DOOR_NAME", - "MACROEDITORS_PATH", - "INSTRUMENTS_FROM_POOL", - ] - - def __init__(self, confname): - super(BaseSardanaConfigLoader, self).__init__(confname) - # explicit copy of AbstractConfigLoader.CONFIG_VALUES is made on purpose - # this way we avoid problems about changing it for other derived classes - self.CONFIG_VALUES = ( - AbstractConfigLoader.CONFIG_VALUES[:] + self.SARDANA_VALUES - ) - - @property - def hooks(self): - return ( - self._loadMacroServerName, - self._loadMacroBroker, - self._loadDoorName, - self._loadMacroEditorsPath, - self._loadInstrumentsFromPool, - ) - - @staticmethod - def _loadMacroServerName(gui): - macro_server_name = gui.getConfigValue("MACROSERVER_NAME", "") - if macro_server_name: - gui.macroserverNameChanged.emit(macro_server_name) - return macro_server_name - - @staticmethod - def _loadMacroBroker(gui): - """configure macro infrastructure""" - ms = gui.getConfigValue("MACROSERVER_NAME", "") - mp = gui.getConfigValue("MACRO_PANELS", True) - # macro infrastructure will only be created if MACROSERVER_NAME is set - if ms and mp is True: - from sardana.taurus.qt.qtgui.macrolistener import MacroBroker - - gui.__macroBroker = MacroBroker(gui) - - @staticmethod - def _loadDoorName(gui): - door_name = gui.getConfigValue("DOOR_NAME", True) - if door_name: - gui.doorNameChanged.emit(door_name) - - @staticmethod - def _loadMacroEditorsPath(gui): - macro_editors_path = gui.getConfigValue( - "MACRO_EDITORS_PATH", True - ) - if macro_editors_path: - from sardana.taurus.qt.qtgui.extra_macroexecutor.macroparameterseditor.macroparameterseditor import ( - ParamEditorManager, - ) - - ParamEditorManager().parsePaths(macro_editors_path) - ParamEditorManager().browsePaths() - - def _loadInstrumentsFromPool(self, gui): - """ - Get panel descriptions from pool if required - """ - # todo: needs heavy refactor - ms = gui.getConfigValue("MACROSERVER_NAME", "") - if not ms: - return - - instruments_from_pool = gui.getConfigValue( - "INSTRUMENTS_FROM_POOL", False - ) - if instruments_from_pool: - try: - gui.splashScreen().showMessage( - "Gathering Instrument info from Pool" - ) - except AttributeError: - pass - - pool_instruments = self._getInstrumentsFromPool(ms) - if pool_instruments: - self._createInstrumentPanels(gui, pool_instruments) - - @staticmethod - def _getInstrumentsFromPool(gui, macroservername): - """ - Get Instruments information form Pool. Return models for - each instrument. - - :param TaurusGui gui: instance of TaurusGui - :param str macroservername: name of MacroServer - - :return: Dicionary with Pool instruments where values are lists - of models - :rtype: dict()>) - """ - # todo: needs heavy refactor - instrument_dict = {} - try: - ms = Device(macroservername) - instruments = ms.getElementsOfType("Instrument") - if instruments is None: - raise Exception() - except Exception as e: - msg = 'Could not fetch Instrument list from "%s": %s' % ( - macroservername, - str(e), - ) - raise HookLoaderError(msg) - - for i in instruments.values(): - instrument_dict[i.full_name] = [] - - pool_elements = [] - for kls in ("Moveable", "ExpChannel", "IORegister"): - pool_elements += sorted( - ms.getElementsWithInterface(kls).values(), - key=attrgetter("name"), - ) - - for elem in pool_elements: - instrument = elem.instrument - if instrument: - # ----------------------------------------------------------- - # Support sardana v<2.4 (which used tango names instead of - # taurus full names - e_name = elem.full_name - if not e_name.startswith("tango://"): - e_name = "tango://%s" % e_name - # ----------------------------------------------------------- - instrument_dict[instrument].append(e_name) - # filter out empty panels - ret = [i for i in instrument_dict if len(instrument_dict[i]) > 0] - return ret - - @staticmethod - def _createInstrumentPanels(gui, poolinstruments): - """ - Create GUI panels from Sardana Pool instruments. Each panel is a - TaurusForm grouping together all those elements that belong to - the same instrument according to the Pool info - - :param TaurusGui gui: isntance of TaurusGui - :param dict()) poolinstruments: dictionary where keys - are panel names and - values are lists of - models - :return: None - """ - - for name, model in poolinstruments.items(): - try: - try: - gui.splashScreen().showMessage( - "Creating instrument panel %s" % name - ) - except AttributeError: - pass - from taurus.qt.qtgui.panel.taurusform import TaurusForm - - w = TaurusForm() - - # ------------------------------------------------------------- - # Backwards-compat. Remove when removing CW map support - if gui._customWidgetMap: - w.setCustomWidgetMap(gui._customWidgetMap) - # ------------------------------------------------------------- - w.setModel(model) - - # the pool instruments may change when the pool config changes, - # so we do not store their config - gui.createPanel( - w, - name, - floating=False, - registerconfig=False, - instrumentkey=gui.IMPLICIT_ASSOCIATION, - permanent=True, - ) - except Exception as e: - msg = "Cannot create instrument panel %s: %s" % (name, str(e)) - raise HookLoaderError(msg) - - -class PySardanaConfigLoader(PyConfigLoader, BaseSardanaConfigLoader): - pass - - -class XmlSardanaConfigLoader(XmlConfigLoader, BaseSardanaConfigLoader): - pass diff --git a/setup.py b/setup.py index e6257f26c..0faa79ece 100644 --- a/setup.py +++ b/setup.py @@ -129,9 +129,6 @@ def get_release_info(): 'taurus.py = taurus.qt.qtgui.taurusgui.config_loader.pyconf:PyConfigLoader', 'taurus.json = taurus.qt.qtgui.taurusgui.config_loader.jsonconf:JsonConfigLoader', 'taurus.xml = taurus.qt.qtgui.taurusgui.config_loader.xmlconf:XmlConfigLoader', - 'taurus.bck_compat = taurus.qt.qtgui.taurusgui.config_loader.back_compat:BckCompatConfigLoader', - 'taurus.sardana.py = taurus.qt.qtgui.taurusgui.config_loader.sardana:PySardanaConfigLoader', - 'taurus.sardana.xml = taurus.qt.qtgui.taurusgui.config_loader.sardana:XmlSardanaConfigLoader', ] config_properties = [ From 8cbb2bcf30f79f23ee2bbe806c9664dec1186e35 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 8 Feb 2021 00:20:05 +0100 Subject: [PATCH 97/99] Get rid of hooks --- .../qtgui/taurusgui/config_loader/abstract.py | 9 --------- .../qtgui/taurusgui/config_loader/jsonconf.py | 4 ---- .../qt/qtgui/taurusgui/config_loader/pyconf.py | 4 ---- .../qt/qtgui/taurusgui/config_loader/util.py | 15 +-------------- .../qt/qtgui/taurusgui/config_loader/xmlconf.py | 4 ---- lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 17 ----------------- 6 files changed, 1 insertion(+), 52 deletions(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index d4764fb1c..4e5629f73 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -83,15 +83,6 @@ def load(self): """ return {} - @abc.abstractproperty - def hooks(self): - """ - List of hooks called at the end of 'TaurusGui.loadConfiguration' - method. Each of them shall be called with 'TaurusGui' instance as - only argument. - """ - return [] - def to_dict(self, conf): """ Generate pure Python dictionary from conf diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py index 5ab5373a3..5c1afb4a5 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py @@ -91,7 +91,3 @@ def load(self): ) return tmp - - @property - def hooks(self): - return [] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py index 631f0eb5e..c739f64bc 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/pyconf.py @@ -143,7 +143,3 @@ def load(self): tmp[section] = self._get_objects(klass) return tmp - - @property - def hooks(self): - return [] diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py index b647270c4..b47ea7bc7 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/util.py @@ -33,7 +33,7 @@ from taurus import warning -__all__ = ["getLoaders", "ConfigLoaderError", "HookLoaderError"] +__all__ = ["getLoaders", "ConfigLoaderError"] class ConfigLoaderError(Exception): @@ -46,19 +46,6 @@ def __init__(self, message): super(ConfigLoaderError, self).__init__(message) -class HookLoaderError(ConfigLoaderError): - """ - Exception raised by config loader hooks - """ - - def __init__(self, message): - message = ( - "Exception raised while executing config loader hookhook: " - + message - ) - super(HookLoaderError, self).__init__(message) - - def getLoaders(confname): """ Discover proper config loader based on passed string. diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py index c3e4f1e85..e0bd96d88 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/xmlconf.py @@ -125,7 +125,3 @@ def synoptics(self): if s: synoptic.append(s) return synoptic - - @property - def hooks(self): - return [] diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index f1385c9aa..9c81530f6 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -922,23 +922,6 @@ def loadConfiguration(self, confname): self._loadExternalApps() self._loadIniFile() - try: - for loader in loaders: - for hook in loader.hooks: - hook(self) - except Exception as e: - msg = "Error while executing config hooks: " + repr(e) - self.error(msg) - self.traceback(level=taurus.Info) # use traceback module? - result = Qt.QMessageBox.critical( - self, - "Initialization error", - "%s\n\n%s" % (msg, repr(e)), - Qt.QMessageBox.Abort | Qt.QMessageBox.Ignore, - ) - if result == Qt.QMessageBox.Abort: - sys.exit() - def _loadAppName(self, confname): appname = self.getConfigValue("GUI_NAME") Qt.qApp.setApplicationName(appname) From 10de1a13fb699270776795da252ac56c98f1c01e Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 8 Feb 2021 00:41:32 +0100 Subject: [PATCH 98/99] Add loading all extra config properties in TaurusGUI --- .../taurusgui/config_properties/__init__.py | 5 ++ .../qtgui/taurusgui/config_properties/util.py | 49 +++++++++++++++++++ lib/taurus/qt/qtgui/taurusgui/taurusgui.py | 11 +++++ setup.py | 1 + 4 files changed, 66 insertions(+) create mode 100644 lib/taurus/qt/qtgui/taurusgui/config_properties/util.py diff --git a/lib/taurus/qt/qtgui/taurusgui/config_properties/__init__.py b/lib/taurus/qt/qtgui/taurusgui/config_properties/__init__.py index 28cbba72e..b9f831f6d 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_properties/__init__.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_properties/__init__.py @@ -20,3 +20,8 @@ # along with Taurus. If not, see . ## ########################################################################### + +""" +""" + +from .util import getConfigPropertiesLoaders diff --git a/lib/taurus/qt/qtgui/taurusgui/config_properties/util.py b/lib/taurus/qt/qtgui/taurusgui/config_properties/util.py new file mode 100644 index 000000000..662f9d395 --- /dev/null +++ b/lib/taurus/qt/qtgui/taurusgui/config_properties/util.py @@ -0,0 +1,49 @@ +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see . +## +########################################################################### + + +import pkg_resources + +from taurus import warning + +__all__ = ["getConfigPropertiesLoaders"] + + +def getConfigPropertiesLoaders(): + """ + Get list of all registered callables + that can load additional config properties + """ + EP_GROUP_PROPS = "taurus.gui.properties" + + loaders = [] + for ep in pkg_resources.iter_entry_points(EP_GROUP_PROPS): + try: + loaders.append(ep.load()) + except Exception as e: + warning( + "Could not load config property plugin '%s. Reason: '%s", + ep.name, + e, + ) + return loaders diff --git a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py index 9c81530f6..cc51c4597 100644 --- a/lib/taurus/qt/qtgui/taurusgui/taurusgui.py +++ b/lib/taurus/qt/qtgui/taurusgui/taurusgui.py @@ -49,6 +49,7 @@ from taurus.qt.qtgui.taurusgui.utils import ExternalAppAction from taurus.core.util.log import deprecation_decorator from taurus.qt.qtgui.taurusgui.config_loader import getLoaders +from taurus.qt.qtgui.taurusgui.confif_properties import getConfigPropertiesLoaders __all__ = ["DockWidgetPanel", "TaurusGui"] @@ -922,6 +923,16 @@ def loadConfiguration(self, confname): self._loadExternalApps() self._loadIniFile() + extra_config_property_loaders = getConfigPropertiesLoaders() + if extra_config_property_loaders: + for ext in extra_config_property_loaders: + try: + ext(self) + except Exception: + import traceback + msg = 'Error loading extra configuration property: %s' % traceback.format_exc() # repr(e) + self.warning(msg) + def _loadAppName(self, confname): appname = self.getConfigValue("GUI_NAME") Qt.qApp.setApplicationName(appname) diff --git a/setup.py b/setup.py index 0faa79ece..7321660b5 100644 --- a/setup.py +++ b/setup.py @@ -148,6 +148,7 @@ def get_release_info(): 'taurus.qt.qtgui.panel.TaurusModelSelector.items': model_selectors, 'taurus.qt.formatters': formatters, 'taurus.gui.loaders': config_loaders, + 'taurus.gui.properties' : config_properties, } classifiers = [ From fbbd35263870f9047a3931e4c99eddd172693093 Mon Sep 17 00:00:00 2001 From: Stanislaw Cabala Date: Mon, 8 Feb 2021 00:44:40 +0100 Subject: [PATCH 99/99] Remove SYNOPTIC from stadard config properties --- lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py index 4e5629f73..ba0fa18a3 100644 --- a/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py +++ b/lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py @@ -55,7 +55,6 @@ class AbstractConfigLoader(abc.ABC): "MANUAL_URI", "INIFILE", "EXTRA_CATALOG_WIDGETS", - "SYNOPTIC", ] DESCRIPTIONS = [