Skip to content
This repository has been archived by the owner on Mar 17, 2021. It is now read-only.

Config loaders #1116

Draft
wants to merge 104 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
4e9d30d
Add main Taurus parser with common options and ability to load subcom…
Apr 15, 2019
0db8ad8
Rebuild testsuite laucnhing method to support it as a subcommand
Apr 15, 2019
6586b9b
Merge branch 'develop' of https://github.com/taurus-org/taurus into d…
Jun 12, 2020
4771f9a
Add skeleton for config loader
Jun 12, 2020
e0e5c92
Define interface of abstract class
Jun 12, 2020
938db8c
Move to use abstract class
Jun 12, 2020
88d733c
Implementation of JSON config loader
Jun 12, 2020
512a931
Delegate non-path strings to PyConfigLoader
Jun 12, 2020
9ab3ef4
Add implementation fo Python config loader
Jun 12, 2020
00a0c43
Add implementation of config loader from XML file
Jun 12, 2020
9e021a5
Specify proper section in XML
Jun 12, 2020
684ba73
Get in line with what XML file loads
Jun 12, 2020
9118498
Use helper function
Jun 12, 2020
445285e
Use helper function for Python config loader also
Jun 12, 2020
00e4139
Use config loader for most of configuration
Jun 12, 2020
81bf057
Allow setting deprecated Monitor widget
Jun 12, 2020
cce2f9a
Add filed with absolute path to config directory
Jun 12, 2020
1fb53f8
Load Sardana stuff from config files
Jun 12, 2020
b45c603
Cleanup xmlroot
Jun 12, 2020
ea2e634
Make loader more robust
Jun 12, 2020
5e83ae3
Delete function from unsucessful merge
Jun 13, 2020
7a27f2a
Use absolute paths for imports
Jun 13, 2020
4f213ff
Remove unused imports
Jun 13, 2020
d5e7d0f
Load monitor widget directly in config loader
Jun 13, 2020
072f025
Add some documentation
Jun 13, 2020
4ee3e72
Fix bugs when loading Python module
Jun 13, 2020
8b85750
PEP8
Jun 13, 2020
fb890ce
Use entrypoints to discover and load config loader plugins
Jun 15, 2020
5f7fc7f
Return default value when reading config from Python module
Jun 15, 2020
10394bd
Fix issues with entrypoints
Jun 15, 2020
6736212
Add launcher for manual testing of config loader
Jun 15, 2020
a6386b8
Add examples of configuration for Python and JSON file
Jun 15, 2020
402c829
Make quick launcher more structurized
Jun 16, 2020
d3af287
Add new moethod for indicitaing if loader supports condifuration
Jun 16, 2020
b5764a9
Implement supports method for all loaders
Jun 16, 2020
7e5ff0e
Make supports method static
Jun 16, 2020
ae83efc
Adapt getLoader emthod to support multiple loaders
Jun 16, 2020
9bf4b54
m, typo
Jun 17, 2020
5475327
Add prefix for config loaders entrypoints
Jun 17, 2020
1a3764d
Remove deprecated properties and Sardana-centred ones from mandatory …
Jun 17, 2020
9cd2178
Remove conf_dir from mandatory abstract API
Jun 17, 2020
5acc5c7
Use flexible dictionary with configuration instead of class fields
Jun 17, 2020
204a84d
Split logic responsible for loading data from formatting data
Jun 17, 2020
94ba5ab
Update loading values from configuration
Jun 17, 2020
d98275f
Add BckCompatConfigLoader
Jun 17, 2020
fc8d1e2
Add config loader for Sardana
Jun 17, 2020
435e250
Allow loading deprecated and Sardana-related config values
Jun 17, 2020
e48b285
Fix syntax
Jun 17, 2020
16a41b7
Add hooks list to abstract interface
Jun 17, 2020
42689ba
Add hooks for backward compatible changes
Jun 17, 2020
3b56644
Add Sardana custom laoder with hooks
Jun 17, 2020
5b59928
Update _loadCustomPanels method to laod panels from configuration or …
Jun 17, 2020
a97404e
Remove Sardana-related config loader methods
Jun 17, 2020
b883df6
Execute registered config loader hooks
Jun 17, 2020
b8910fb
PEP8
Jun 17, 2020
5be97c5
Add missing entry point for Sardana config loader
Jun 17, 2020
edda3b9
Fix typo
Jun 17, 2020
085e8af
Always try to laod Sardana config values
Jun 17, 2020
1f4247f
m, typos
Jun 18, 2020
deb7c9a
m, typo
Jun 18, 2020
55bab0b
Retiurn loaders list from loader function
Jun 18, 2020
1d08b0f
getLoader -> getLoaders
Jun 18, 2020
00a24d6
Move getLoaders function to its own module
Jun 18, 2020
edf38f6
USe variable with entry point name for easier testing
Jun 18, 2020
fd8b344
Create instrument panels completely in config loader hook
Jun 18, 2020
f8433f7
Protect against expections raised while executing config hooks
Jun 18, 2020
b0a09e8
Add new exception speicifc for hooks
Jun 18, 2020
21c5b95
Simplify handling of errors
Jun 18, 2020
c6a6a68
Import just Device
Jun 18, 2020
e0b6582
Move custom exceptions to util module
Jun 18, 2020
a4a5e1e
Remove unused import
Jun 18, 2020
fdff9cc
Provide concrete config loader classes for Python and XML configurati…
Jun 18, 2020
4a402e2
Add new Sardana config laoders to entry point
Jun 18, 2020
9bd06cd
Update docstring
Jun 18, 2020
2428a08
Refactor loading instruments from Pool
Jun 18, 2020
6bff4ed
PEP8
Jun 18, 2020
bc2ab07
Simplify printing configuration
Jun 18, 2020
5afc4e9
Add method to cast TaurusGuiComponent to dictionary
Jun 18, 2020
6b1622b
Cast description obejcts to dictionaries to simplify printing
Jun 18, 2020
a229e6c
Return dictionary, not result of 'update' call (None)
Jun 18, 2020
b10acbc
Fix printing description objects
Jun 18, 2020
372c8e5
Allow easy printing of ExternalApp objects
Jun 18, 2020
0123838
Merge branch 'develop' of https://github.com/taurus-org/taurus into d…
Jun 18, 2020
2431aeb
Merge branch 'develop' into config_loaders
Jun 18, 2020
87682d8
Merge branch 'config_loaders' of https://github.com/stanislaw47/tauru…
Jun 18, 2020
94f9030
Move default values to DEFAULT_CONFIG variable
Jun 18, 2020
5dee71a
Use unified way of refering to configuration fields
Jun 18, 2020
da9893d
Make conf private variable
Jun 18, 2020
cc9e428
Adapt loaders to new API
Jun 18, 2020
6e89719
Do not pass conf instance to hooks
Jun 18, 2020
4ccdf92
Fix extending CONFIG_VALUES list
Jun 20, 2020
c96d2eb
Add support for XML_CONFIG field
Jun 20, 2020
d41ccac
MAke GUI_NAME optional (default to confname)
Jun 20, 2020
c9b26e7
Addd list of all Description classes along with configuration sections
Jun 20, 2020
f3b9adf
Add helper method for generating pure Python dictionary from configur…
Jun 20, 2020
24b5651
Use existing DESCRIPTIONS list
Jun 20, 2020
19b22a0
Fix JSON loader
Jun 20, 2020
8dcca46
Add skeleton of tests for PYthon configuration
Jun 22, 2020
f352cba
Add new entrypoint for loading custom config properties
stanislaw47 Feb 7, 2021
eee6441
Remove redundant config loaders
stanislaw47 Feb 7, 2021
8cbb2bc
Get rid of hooks
stanislaw47 Feb 7, 2021
10de1a1
Add loading all extra config properties in TaurusGUI
stanislaw47 Feb 7, 2021
fbbd352
Remove SYNOPTIC from stadard config properties
stanislaw47 Feb 7, 2021
3b9e6d4
Merge branch 'develop' into config_loaders
stanislaw47 Feb 8, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions lib/taurus/qt/qtgui/taurusgui/config_loader/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#############################################################################
##
# 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 <http://www.gnu.org/licenses/>.
##
###########################################################################

"""
"""

from .util import getLoaders
18 changes: 18 additions & 0 deletions lib/taurus/qt/qtgui/taurusgui/config_loader/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import sys
from pprint import pprint

from .util import getLoaders


def main(conf):
cfg = {}
loaders = getLoaders(conf)
for loader in loaders:
cfg.update(loader.load())

cfg = loaders[0].to_dict(cfg)

pprint(cfg)


main(sys.argv[1])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes more sense as a taurus gui option/subcommand. Also, I think that the helper functions are better provided as method(s) of the configloader object (this way different loaders can take care of printing their own stuff)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not know yet how exactly that would work. But I simplified this a lot since now there's internal dictionary instead of class.

To make it simply, I needed to introduce to_dict method for each *Description class. In future, this could evolve to what was referenced as ConfigWriter.

94 changes: 94 additions & 0 deletions lib/taurus/qt/qtgui/taurusgui/config_loader/abstract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#############################################################################
##
# 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 <http://www.gnu.org/licenses/>.
##
###########################################################################

""""""
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,), {}))


__all__ = ["AbstractConfigLoader"]


class AbstractConfigLoader(abc.ABC):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this implementation even more than the one before!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to hear it :)

"""
Abstract class for config loaders.
It defines interface which has to be implemneted by subclass in
order for it to be ConfigLoader
"""

CONFIG_VALUES = [
"GUI_NAME",
"ORGANIZATION",
"CUSTOM_LOGO",
"ORGANIZATION_LOGO",
"SINGLE_INSTANCE",
"MANUAL_URI",
"INIFILE",
"EXTRA_CATALOG_WIDGETS",
]

DESCRIPTIONS = [
(AppletDescription, "AppletDescriptions"),
(ExternalApp, "ExternalApps"),
(PanelDescription, "PanelDescriptions"),
(ToolBarDescription, "ToolBarDescriptions"),
]

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):
"""
This method is meant to load actual data from file on disk.
Return dictionary with configuration.
"""
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
69 changes: 69 additions & 0 deletions lib/taurus/qt/qtgui/taurusgui/config_loader/examples/config.json
Original file line number Diff line number Diff line change
@@ -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]
]
}
70 changes: 70 additions & 0 deletions lib/taurus/qt/qtgui/taurusgui/config_loader/examples/config.py
Original file line number Diff line number Diff line change
@@ -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
93 changes: 93 additions & 0 deletions lib/taurus/qt/qtgui/taurusgui/config_loader/jsonconf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#############################################################################
##
# 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 <http://www.gnu.org/licenses/>.
##
###########################################################################

""""""

import json
import os

from taurus.qt.qtgui.taurusgui.config_loader.abstract import (
AbstractConfigLoader,
)
from taurus.qt.qtgui.taurusgui.config_loader.util import ConfigLoaderError

__all__ = ["JsonConfigLoader"]


class JsonConfigLoader(AbstractConfigLoader):
"""
Loads configuration for TaurusGui from JSON file
"""

def __init__(self, confname):
super(JsonConfigLoader, self).__init__(confname)
self._data = {}

def _get_objects(self, klass, section):
"""
Helper function to get list of Python objects from dictionary
"""
objs = []
for o in self._data.get(section, []):
if isinstance(o, dict):
objs.append(klass(**o))
return objs

@staticmethod
def supports(confname):
if os.path.isfile(confname):
ext = os.path.splitext(confname)[-1]
if ext == ".json":
return True
return False

def _get_data(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)
)

def load(self):
self._get_data()

tmp = {}

for v in self.CONFIG_VALUES:
if v in self._data:
tmp[v] = self._data[v]

for klass, section in self.DESCRIPTIONS:
tmp[section] = self._get_objects(klass, section)

tmp["CONF_DIR"] = os.path.abspath(
os.path.dirname(self._confname)
)

return tmp
Loading