From 3f9d696e24b5ffaa32d566e51999bb6dedcfc6f2 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 22 May 2018 11:18:11 +0200 Subject: [PATCH 001/652] Stop MG in case of starting failure Stop the acquisition if the Start method raises an exception. --- src/sardana/taurus/core/tango/sardana/pool.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 5eed4fc684..613636adf2 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1760,7 +1760,17 @@ def _enableChannels(self, channels, state): self.setConfiguration(cfg.raw_data) def _start(self, *args, **kwargs): - self.Start() + try: + self.Start() + except Exception as e: + while True: + try: + self.stop() + break + except Exception: + pass + # TODO: Do more friendly user the exception message. + raise e def go(self, *args, **kwargs): start_time = time.time() From ae904b066501690c0d7fec80795d540ad33d304a Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 30 May 2018 15:41:10 +0200 Subject: [PATCH 002/652] Initial draft after some ALBA brainstorming. --- doc/source/sep/SEP18.md | 62 +++++++++++++++++++++++++++++++++++++++++ doc/source/sep/index.md | 2 ++ 2 files changed, 64 insertions(+) create mode 100644 doc/source/sep/SEP18.md diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md new file mode 100644 index 0000000000..e0d95ee7dd --- /dev/null +++ b/doc/source/sep/SEP18.md @@ -0,0 +1,62 @@ + Title: Extend acquisition and synchronization concepts for SEP2 needs. + SEP: 18 + State: DRAFT + Reason: + New acquisition and synchronization concepts are necessary in order to + properly integrate 1D and 2D experimental channels in Sardana (SEP2). + Date: 2018-05-30 + Drivers: Zbigniew Reszela + URL: https://github.com/reszelaz/sardana/blob/sep18/doc/source/sep/SEP18.md + License: http://www.jclark.com/xml/copying.txt + Abstract: + SEP6 defined some acquisition and synchronization concepts for the needs + of the continuous scan. When working on the 1D and 2D experimental + channels integration we see that more concepts are necessary. This SEP + introduces them. + +Terminology +----------- + +* Measurement - a measurement process that may, but not necessarily, involve +multiple acquisitions e.g. measurement group count, continuous scan, step scan. +* Acquisition - a single acquisition e.g. over an integration time, which is a +part of a measurement + +Current Limitations +------------------- + +* The Software and Hardware synchronization types terminology is not self +descriptive. Internal and External terminology describes better these types. +* Some hardware or even the Lima library allows some synchronization modes +that are not foreseen in Sardana and are necessary. +* Some experimental channels could benefit from preparing them for multiple +acquisitions before the measurement e.g. software synchronized continuous +scan or step scan. + +Objectives +---------- + +Overcome the above limitations. + +Design +------ + +1. Document well that: + * Software(Trigger|Gate) are synonyms to Internal (Trigger|Gate). + Internal means that Sardana will synchronize the acquisitions. + * Hardware(Trigger|Gate) are synonyms to External(Trigger|Gate). + External means that an external to Sardana object (could be hardware) + will synchronize the acquisitions. +2. Extend AcqSynch with two new options: + * SoftwareStart (which means internal start) + * HardwareStart (which means external start) +3. Extend AcqSynchType with one new option (supported from expconf): + * Start +4. Allow different types of preparation of channels: + * Per measurement preparation with repetitions=n e.g. Prepare(One|All) + or a controller parameter + * Per acquisition preparation with repetitions=1 e.g. Load(One|All) +6. Modify acquisition actions (and synchronization action if necessary) so +they support the new concepts added in points 2 and 4. +5. Extend GSF (step mode) with measurement preparation (repetitions=n) if +possible i.e. scan macro knows beforehand the number of points. diff --git a/doc/source/sep/index.md b/doc/source/sep/index.md index a293b472c5..d888843c95 100644 --- a/doc/source/sep/index.md +++ b/doc/source/sep/index.md @@ -26,6 +26,7 @@ Proposals list [SEP13][] | REJECTED (moved to [TEP13][]) | Unified plugins support in Taurus & Sardana [SEP14][] | DRAFT | MSENV taurus schema [SEP15][] | ACCEPTED | Moving Sardana to Github + [SEP18][] | DRAFT | Extend acquisition and synchronization concepts for SEP2 needs @@ -46,6 +47,7 @@ Proposals list [SEP13]: http://www.sardana-controls.org/sep/?SEP13.md [SEP14]: http://www.sardana-controls.org/sep/?SEP14.md [SEP15]: http://www.sardana-controls.org/sep/?SEP15.md +[SEP18]: https://github.com/reszelaz/sardana/blob/sep18/doc/source/sep/SEP18.md [TEP3]: http://www.taurus-scada.org/tep/?TEP3.md From 19a88683bce5c964e4f08ab8bb230fccb9848120 Mon Sep 17 00:00:00 2001 From: schick Date: Fri, 8 Jun 2018 15:18:06 +0200 Subject: [PATCH 003/652] skeleton newfile macro --- src/sardana/macroserver/macros/standard.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index ead912fa3c..b182d119c5 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -845,3 +845,24 @@ def run(self, nr): self.__loop() progress = ((i + 1) / float(nr)) * 100 yield progress + + +class newfile(Macro): + """This macro sets a new ScanFile and ScanID values into the env""" + + # hints = { 'allowsHooks': ('body', 'break', 'continue') } + env = ('ScanFile', 'ScanID') + + param_def = [ + ['ScanID', Type.Integer, 1.0, 'Scan ID'] + ['ScanFile_list', + ParamRepeat(['ScanFile', Type.String, None, 'Name of scan file']), + None, 'List of scan file names'], + ] + + def run(self, ScanID, ScanFile_list): + oldScanFile = self.getEnv('ScanFile') + oldScanID = self.getEnv('ScanFile') + + self.output(oldScanFile) + self.output(oldScanID) \ No newline at end of file From 29b980e980c9a14baf3a6ce105ba5291085f463c Mon Sep 17 00:00:00 2001 From: schick Date: Fri, 8 Jun 2018 15:34:05 +0200 Subject: [PATCH 004/652] first version working version --- src/sardana/macroserver/macros/standard.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index b182d119c5..0e699f8f1f 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -848,21 +848,25 @@ def run(self, nr): class newfile(Macro): - """This macro sets a new ScanFile and ScanID values into the env""" + """This macro sets a new ScanFile and ScanID values into the env. + The ScanID should be set to the value N of the last executed ScanID + in order to continue with a ScanID N+1 for the next scan.""" - # hints = { 'allowsHooks': ('body', 'break', 'continue') } env = ('ScanFile', 'ScanID') param_def = [ - ['ScanID', Type.Integer, 1.0, 'Scan ID'] + ['ScanID', Type.Integer, 1, 'Scan ID'], ['ScanFile_list', ParamRepeat(['ScanFile', Type.String, None, 'Name of scan file']), None, 'List of scan file names'], ] - def run(self, ScanID, ScanFile_list): - oldScanFile = self.getEnv('ScanFile') - oldScanID = self.getEnv('ScanFile') + def run(self, ScanID, ScanFile_list): + self.setEnv('ScanFile', ScanFile_list) + self.setEnv('ScanID', ScanID) - self.output(oldScanFile) - self.output(oldScanID) \ No newline at end of file + self.output('ScanFile set to: ') + for ScanFile in ScanFile_list: + self.output(' %s', ScanFile) + self.output('ScanID set to: %d', ScanID) + \ No newline at end of file From 31ade43bda965b6346bf20b005b4d084f276a0c8 Mon Sep 17 00:00:00 2001 From: schick Date: Fri, 8 Jun 2018 16:06:56 +0200 Subject: [PATCH 005/652] add newfile to __all__ list --- src/sardana/macroserver/macros/standard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index 0e699f8f1f..eb6135ccff 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -25,7 +25,7 @@ __all__ = ["ct", "mstate", "mv", "mvr", "pwa", "pwm", "repeat", "set_lim", "set_lm", "set_pos", "settimer", "uct", "umv", "umvr", "wa", "wm", - "tw", "logmacro"] + "tw", "logmacro", "newfile"] __docformat__ = 'restructuredtext' From 0973d321c0e720f08b4b2eb1ebdc266b17b14d7f Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 11 Jun 2018 10:59:09 +0200 Subject: [PATCH 006/652] remove whitespaces --- src/sardana/macroserver/macros/standard.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index eb6135ccff..c0ecc183e9 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -860,13 +860,12 @@ class newfile(Macro): ParamRepeat(['ScanFile', Type.String, None, 'Name of scan file']), None, 'List of scan file names'], ] - - def run(self, ScanID, ScanFile_list): + + def run(self, ScanID, ScanFile_list): self.setEnv('ScanFile', ScanFile_list) self.setEnv('ScanID', ScanID) - + self.output('ScanFile set to: ') for ScanFile in ScanFile_list: self.output(' %s', ScanFile) - self.output('ScanID set to: %d', ScanID) - \ No newline at end of file + self.output('ScanID set to: %d', ScanID) \ No newline at end of file From 1f3fe40c0cc2d6d6fd2c89c8aec5b2be9dee87f1 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 11 Jun 2018 11:26:53 +0200 Subject: [PATCH 007/652] more corrections of whitepsaces --- src/sardana/macroserver/macros/standard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index c0ecc183e9..da180e4e7f 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -849,7 +849,7 @@ def run(self, nr): class newfile(Macro): """This macro sets a new ScanFile and ScanID values into the env. - The ScanID should be set to the value N of the last executed ScanID + The ScanID should be set to the value N of the last executed ScanID in order to continue with a ScanID N+1 for the next scan.""" env = ('ScanFile', 'ScanID') @@ -868,4 +868,4 @@ def run(self, ScanID, ScanFile_list): self.output('ScanFile set to: ') for ScanFile in ScanFile_list: self.output(' %s', ScanFile) - self.output('ScanID set to: %d', ScanID) \ No newline at end of file + self.output('ScanID set to: %d', ScanID) From b52315b395e28246e3da38de3ad91cb03f66a35b Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 13 Jun 2018 11:38:51 +0200 Subject: [PATCH 008/652] Relax restrictions in usage of repeat parameters in spock Spock syntax allows to use macros with only one repeat parameter which is defined at the end. Furthermore no nested repeat parameters are allowed. Remove this validation so it will be possible to extend the spock syntax for more cases. --- src/sardana/taurus/core/tango/sardana/macro.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py index 9b4a4ba3f5..f1f31bee22 100755 --- a/src/sardana/taurus/core/tango/sardana/macro.py +++ b/src/sardana/taurus/core/tango/sardana/macro.py @@ -1301,18 +1301,7 @@ def createMacroNode(macro_name, params_def, macro_params): if not new_interface: param_nodes = macro_node.params() - contain_param_repeat = False len_param_nodes = len(param_nodes) - for i, param_node in enumerate(param_nodes): - if isinstance(param_node, RepeatParamNode): - if contain_param_repeat: - msg = "Only one repeat parameter is allowed" - raise Exception(msg) - if i < len_param_nodes - 1: - msg = "Repeat parameter must be the last one" - raise Exception(msg) - # If ParamRepeat only one and as last parameter - # this ignores raw_parameters which exceeds the param_def for param_node, param_raw in zip(param_nodes, macro_params): if isinstance(param_node, SingleParamNode): param_node.setValue(param_raw) From b4790a576f456ecf4e6bee354323266847565c35 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 13 Jun 2018 11:47:25 +0200 Subject: [PATCH 009/652] Extend spock syntax repeat parameters usage Allow usage of macros with repeat parameters located at arbitrary places when only one repetition is passed by the user. When more repetitions are passed by the user the advanced spock syntax must be used (using square brackets to group repeat parameters and repetitions with more than one member). --- .../taurus/core/tango/sardana/macro.py | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py index f1f31bee22..60e63da859 100755 --- a/src/sardana/taurus/core/tango/sardana/macro.py +++ b/src/sardana/taurus/core/tango/sardana/macro.py @@ -1302,11 +1302,34 @@ def createMacroNode(macro_name, params_def, macro_params): if not new_interface: param_nodes = macro_node.params() len_param_nodes = len(param_nodes) + param_idx = 0 for param_node, param_raw in zip(param_nodes, macro_params): if isinstance(param_node, SingleParamNode): param_node.setValue(param_raw) - # the rest of the values are interpreted as repeat parameter - elif isinstance(param_node, RepeatParamNode): + # Repeat parameters that are not at the end. + elif (isinstance(param_node, RepeatParamNode) and + param_idx < (len_param_nodes - 1)): + repeat_node = param_node.child(0) + # Add a new repeat node. This is needed when the raw values + # fill more repeat nodes that the minimum number of + # repetitions e.g. min=0. + if repeat_node is None: + repeat_node = param_node.addRepeat() + if len(repeat_node.children()) > 1: + msg = ("repeat parameter with more than one member must " + "be defined at the end when intended to " + "be used with spock syntax") + raise Exception(msg) + member_node = repeat_node.child(0) + if isinstance(member_node, RepeatParamNode): + msg = ("nested repeat parameters are not allowed when " + "intended to be used with spock syntax") + raise Exception(msg) + member_node.setValue(param_raw) + # The resting values are interpreted as repeat parameter values. + # This ignores parameter values which exceeds the parameters + # definition. + else: params_info = param_node.paramsInfo() params_info_len = len(params_info) rep = 0 @@ -1329,6 +1352,7 @@ def createMacroNode(macro_name, params_def, macro_params): if mem == 0: rep += 1 break + param_idx += 1 else: macro_node.fromList(macro_params) return macro_node From 2232c10b94a1a7a3dbed521913703e9ea2774f98 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 13 Jun 2018 11:52:05 +0200 Subject: [PATCH 010/652] Correct comments and exception message (minor) --- src/sardana/taurus/core/tango/sardana/macro.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py index 60e63da859..5bb4e4ec78 100755 --- a/src/sardana/taurus/core/tango/sardana/macro.py +++ b/src/sardana/taurus/core/tango/sardana/macro.py @@ -1337,14 +1337,15 @@ def createMacroNode(macro_name, params_def, macro_params): rest_raw = macro_params[i:] for member_raw in rest_raw: repeat_node = param_node.child(rep) - # add a new repeat node (this is needed when the raw values - # fill more repeat nodes that the minimum number of - # repetitions e.g. min=0 + # Add a new repeat node. This is needed when the raw + # values fill more repeat nodes that the minimum number + # of repetitions e.g. min=0. if repeat_node is None: repeat_node = param_node.addRepeat() member_node = repeat_node.child(mem) if isinstance(member_node, RepeatParamNode): - msg = ("Nested repeat parameters are not allowed") + msg = ("nested repeat parameters are not allowed " + "when intended to be used with spock syntax") raise Exception(msg) member_node.setValue(member_raw) mem += 1 From c3e6538e6f33aa1c933c86794dad7890c30d5d3f Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 13 Jun 2018 15:09:37 +0200 Subject: [PATCH 011/652] Fix bug and use proper index of the last parameter Commit b52315b accidentally remove the i variable. Fix it. --- src/sardana/taurus/core/tango/sardana/macro.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py index 5bb4e4ec78..7ca7958675 100755 --- a/src/sardana/taurus/core/tango/sardana/macro.py +++ b/src/sardana/taurus/core/tango/sardana/macro.py @@ -1332,9 +1332,10 @@ def createMacroNode(macro_name, params_def, macro_params): else: params_info = param_node.paramsInfo() params_info_len = len(params_info) + last_param_idx = len_param_nodes - 1 rep = 0 mem = 0 - rest_raw = macro_params[i:] + rest_raw = macro_params[last_param_idx:] for member_raw in rest_raw: repeat_node = param_node.child(rep) # Add a new repeat node. This is needed when the raw From ba2a5f8ac7b5f88422dc58ec41ed873271f63b86 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 29 Jun 2018 13:31:00 +0200 Subject: [PATCH 012/652] Updating examples according to this extension --- src/sardana/macroserver/macros/examples/parameters.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sardana/macroserver/macros/examples/parameters.py b/src/sardana/macroserver/macros/examples/parameters.py index 486e5201a3..857fe091e8 100644 --- a/src/sardana/macroserver/macros/examples/parameters.py +++ b/src/sardana/macroserver/macros/examples/parameters.py @@ -186,6 +186,7 @@ class pt7d1(Macro): pt7d1 mot1 1 mot2 3 Using default value, ex.: pt7d1 [[mot1] [mot2 3]] # at any repetition + pt7d1 mot1 # if only one repetition """ @@ -262,6 +263,7 @@ class pt10(Macro): parameter may be defined as first one. Usage from Spock, ex.: pt10 [1 3] mot1 + pt10 1 mot1 # if only one repetition """ param_def = [ @@ -279,6 +281,7 @@ class pt11(Macro): parameters. Usages from Spock, ex.: pt11 ct1 [1 3] mot1 + pt11 ct1 1 mot1 # if only one repetition """ param_def = [ @@ -296,6 +299,7 @@ class pt12(Macro): parameters may defined. Usage from Spock, ex.: pt12 [1 3 4] [mot1 mot2] + pt12 1 mot1 # if only one repetition for each repeat parameter """ param_def = [ From 88ef601084874c2b4c39af3d3d133327f36bc48c Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Sat, 7 Jul 2018 02:58:15 +0200 Subject: [PATCH 013/652] change order of input and describe functionality --- src/sardana/macroserver/macros/standard.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index d7c76fe5a0..5c665fc859 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -864,13 +864,18 @@ class newfile(Macro): env = ('ScanFile', 'ScanID') param_def = [ - ['ScanID', Type.Integer, 1, 'Scan ID'], ['ScanFile_list', ParamRepeat(['ScanFile', Type.String, None, 'Name of scan file']), None, 'List of scan file names'], + ['ScanID', Type.Integer, 0, 'Scan ID'], ] - def run(self, ScanID, ScanFile_list): + def run(self, ScanFile_list, ScanID): + # check if the ScanFile_list contains any folder + # first iterate over every element in the ScanFile_list and extract the + # possible folder - then check if at least one folder is set and if + # multiples - they have to be equal + # if now inputs are givin the macro should be interactive self.setEnv('ScanFile', ScanFile_list) self.setEnv('ScanID', ScanID) From 97796c97ede14511d5cc84d753885ab0a227c8f8 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 9 Jul 2018 10:05:36 +0200 Subject: [PATCH 014/652] include ScanDir handling for newfile macro allow for scanDir and multiple file scanID is given for the upcoming scan - default is 1 --- src/sardana/macroserver/macros/standard.py | 83 +++++++++++++++++----- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index 5c665fc859..7abf03c9d6 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -30,6 +30,7 @@ __docformat__ = 'restructuredtext' import datetime +import os import numpy as np from taurus import Device @@ -861,25 +862,71 @@ class newfile(Macro): The ScanID should be set to the value N of the last executed ScanID in order to continue with a ScanID N+1 for the next scan.""" - env = ('ScanFile', 'ScanID') + env = ('ScanFilePath', 'ScanID') param_def = [ - ['ScanFile_list', - ParamRepeat(['ScanFile', Type.String, None, 'Name of scan file']), - None, 'List of scan file names'], - ['ScanID', Type.Integer, 0, 'Scan ID'], + ['ScanFilePath_list', + ParamRepeat(['ScanFilePath', Type.String, None, + 'full path to scan file']), + None, 'List of scan file names and paths'], + ['ScanID', Type.Integer, -1, 'Scan ID'], ] - def run(self, ScanFile_list, ScanID): - # check if the ScanFile_list contains any folder - # first iterate over every element in the ScanFile_list and extract the - # possible folder - then check if at least one folder is set and if - # multiples - they have to be equal - # if now inputs are givin the macro should be interactive - self.setEnv('ScanFile', ScanFile_list) - self.setEnv('ScanID', ScanID) - - self.output('ScanFile set to: ') - for ScanFile in ScanFile_list: - self.output(' %s', ScanFile) - self.output('ScanID set to: %d', ScanID) + def run(self, ScanFilePath_list, ScanID): + path_list = [] + fileName_list = [] + # traverse the repeat parameters for the path+fileNames + for i, ScanFilePath in enumerate(ScanFilePath_list): + path = os.path.dirname(ScanFilePath) + fileName = os.path.basename(ScanFilePath) + if not path and i == 0: + # first entry and no given path: use pwd + path = os.getcwd() + elif not path and i > 0: + # not first entry and no given path: use path of last iteration + path = path_list[i-1] + elif not os.path.isabs(path): + # relative path + path = os.path.normpath(os.path.join(os.getcwd(), path)) + else: + # absolute path + path = os.path.normpath(path) + + if i > 0 and path in ((p) for p in path_list): + # check if paths are equal + self.error("Multiple paths, %s, to the data files are not" + "allowed" % path) + return + elif not os.path.exists(path): + # check if folder exists + self.error("Path %s does not exists and has to be created in" + "advance." % path) + return + else: + self.debug("Path %s appended." % path) + path_list.append(path) + + if not fileName: + self.error("No filename is given") + return + elif i > 0 and fileName in ((f) for f in fileName_list): + self.error("Duplicate filename %s." % fileName) + return + else: + self.debug("Filename is %s." % fileName) + fileName_list.append(fileName) + + if ScanID < 1: + ScanID = 0 + else: + ScanID = ScanID-1 + + self.setEnv('ScanFile', fileName_list) + self.setEnv('ScanDir', path_list[0]) + self.setEnv('ScanID', ScanID) + + self.output('ScanDir is: %s', path_list[0]) + self.output('ScanFile set to: ') + for ScanFile in fileName_list: + self.output(' %s', ScanFile) + self.output('Next scan is #%d', ScanID+1) From 581d735259cd409a8c3d0bc0550cfcd54e417687 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 9 Jul 2018 23:19:09 +0200 Subject: [PATCH 015/652] remove pwd and relpath functionality only absoulte paths on the macroServer host are allowed. If no ScanDir is given, its existens will be checked --- src/sardana/macroserver/macros/standard.py | 64 +++++++++++++--------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index 7abf03c9d6..ac2b9fd366 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -858,62 +858,74 @@ def run(self, nr): class newfile(Macro): - """This macro sets a new ScanFile and ScanID values into the env. - The ScanID should be set to the value N of the last executed ScanID - in order to continue with a ScanID N+1 for the next scan.""" + """ Sets the ScanDir and ScanFile as well as ScanID in the environment. + If ScanFilePath is only a file name, the ScanDir must be set externally via + senv ScanDir PathToScanFile or using the %expconf. Otherwise, the path in + ScanFilePath must be absolute and existing on the MacroServer host. + The ScanID should be set to the value of the upcoming scan number. Default + value is 1. + """ - env = ('ScanFilePath', 'ScanID') + env = ('ScanDir', 'ScanFile', 'ScanID') param_def = [ - ['ScanFilePath_list', - ParamRepeat(['ScanFilePath', Type.String, None, - 'full path to scan file']), - None, 'List of scan file names and paths'], + ['ScanFileDir_list', + ParamRepeat(['ScanFileDir', Type.String, None, + '(ScanDir/)ScanFile']), + None, 'List of (ScanDir/)ScanFile'], ['ScanID', Type.Integer, -1, 'Scan ID'], ] - def run(self, ScanFilePath_list, ScanID): + def run(self, ScanFileDir_list, ScanID): path_list = [] fileName_list = [] - # traverse the repeat parameters for the path+fileNames - for i, ScanFilePath in enumerate(ScanFilePath_list): - path = os.path.dirname(ScanFilePath) - fileName = os.path.basename(ScanFilePath) + # traverse the repeat parameters for the ScanFilePath_list + for i, ScanFileDir in enumerate(ScanFileDir_list): + path = os.path.dirname(ScanFileDir) + fileName = os.path.basename(ScanFileDir) if not path and i == 0: - # first entry and no given path: use pwd - path = os.getcwd() + # first entry and no given ScanDir: check if ScanDir exists + ScanDir = self.getEnv('ScanDir') + if not ScanDir: + self.warning('Data is not stored until ScanDir is set! ' + 'Provide ScanDir with newfile macro: ' + 'newfile [/] or' + 'senv ScanDir or with %expconf') + else: + path = ScanDir elif not path and i > 0: # not first entry and no given path: use path of last iteration path = path_list[i-1] elif not os.path.isabs(path): # relative path - path = os.path.normpath(os.path.join(os.getcwd(), path)) + self.error('Only absolute path are allowed!') + return else: # absolute path path = os.path.normpath(path) - if i > 0 and path in ((p) for p in path_list): + if i > 0 and (path not in path_list): # check if paths are equal - self.error("Multiple paths, %s, to the data files are not" - "allowed" % path) + self.error('Multiple paths to the data files are not allowed') return elif not os.path.exists(path): # check if folder exists - self.error("Path %s does not exists and has to be created in" - "advance." % path) + self.error('Path %s does not exists on the host of the ' + 'MacroServerand has to be created in ' + 'advance.' % path) return else: - self.debug("Path %s appended." % path) + self.debug('Path %s appended.' % path) path_list.append(path) if not fileName: - self.error("No filename is given") + self.error('No filename is given.') return - elif i > 0 and fileName in ((f) for f in fileName_list): - self.error("Duplicate filename %s." % fileName) + elif fileName in fileName_list: + self.error('Duplicate filename %s is not allowed.' % fileName) return else: - self.debug("Filename is %s." % fileName) + self.debug('Filename is %s.' % fileName) fileName_list.append(fileName) if ScanID < 1: From 26dc568fa7fd07f8d952e29110f5b81621b7f8cf Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 18 Jul 2018 15:06:34 +0200 Subject: [PATCH 016/652] Not send default parameter value Do not send the default parameter value on the execution of the macro. The use of the default value is implemented on the server site. --- src/sardana/taurus/core/tango/sardana/macro.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py index 9b4a4ba3f5..25c4a34af2 100755 --- a/src/sardana/taurus/core/tango/sardana/macro.py +++ b/src/sardana/taurus/core/tango/sardana/macro.py @@ -487,10 +487,10 @@ def __init__(self, parent=None, param=None): if param is None: return self.setType(str(param.get('type'))) - self.setDefValue(str(param.get('default_value', ''))) + self.setDefValue(str(param.get('default_value', None))) if self.type() == "User": self.setDefValue(str(USER_NAME)) - self.setValue(self.defValue()) + self._value = None def __len__(self): return 0 @@ -523,7 +523,9 @@ def setType(self, type): def toXml(self): value = self.value() paramElement = etree.Element("param", name=self.name()) - if not value is None: + # set value attribute only if it is different than the default value + # the server will assign the default value anyway. + if value is not None and value != self.defValue(): paramElement.set("value", value) return paramElement @@ -542,9 +544,12 @@ def allMotors(self): def toRun(self): val = self.value() - if val is None or val == "None" or val == "": - alert = "Parameter " + self.name() + " is missing.
" - return ([val], alert) + if val is None or val == "None": + if self.defValue() is None: + alert = "Parameter " + self.name() + " is missing.
" + return ([val], alert) + else: + val = self.defValue() return ([val], "") def toList(self): From 7cf519f482e40d1749d220a982893d1c4178a9dd Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 18 Jul 2018 17:52:46 +0200 Subject: [PATCH 017/652] Implement OptionalParamClass Implement class and validations to allow optional parameters on the macros. --- src/sardana/macroserver/macro.py | 5 +-- src/sardana/macroserver/msparameter.py | 45 ++++++++++++++++++++------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/sardana/macroserver/macro.py b/src/sardana/macroserver/macro.py index 1fd5d99e33..719b58fc63 100644 --- a/src/sardana/macroserver/macro.py +++ b/src/sardana/macroserver/macro.py @@ -32,7 +32,7 @@ __all__ = ["OverloadPrint", "PauseEvent", "Hookable", "ExecMacroHook", "MacroFinder", "Macro", "macro", "iMacro", "imacro", "MacroFunc", "Type", "ParamRepeat", "Table", "List", "ViewOption", - "LibraryError"] + "LibraryError", "OptionalParam"] __docformat__ = 'restructuredtext' @@ -55,7 +55,8 @@ from sardana.sardanadefs import State from sardana.util.wrap import wraps -from sardana.macroserver.msparameter import Type, ParamType, ParamRepeat +from sardana.macroserver.msparameter import Type, ParamType, ParamRepeat, \ + OptionalParam from sardana.macroserver.msexception import StopException, AbortException, \ MacroWrongParameterType, UnknownEnv, UnknownMacro, LibraryError from sardana.macroserver.msoptions import ViewOption diff --git a/src/sardana/macroserver/msparameter.py b/src/sardana/macroserver/msparameter.py index f0422c8959..de482ae035 100644 --- a/src/sardana/macroserver/msparameter.py +++ b/src/sardana/macroserver/msparameter.py @@ -36,7 +36,7 @@ from copy import deepcopy from lxml import etree - +import json from taurus.core.util.containers import CaselessDict from sardana import ElementType, INTERFACES_EXPANDED @@ -45,6 +45,28 @@ UnknownMacro, UnknownMacroLibrary +class OptionalParamClass(dict): + def __init__(self, obj): + super(OptionalParamClass, self).__init__(obj) + attributes = dir(self) + + for attr in attributes: + if attr in ['__setattr__', '__repr__', 'raise_error', '__class__', + '__dict__', '__weakref__']: + continue + self.__setattr__(attr, self.raise_error) + self.__setattr__ = self.raise_error + + def __repr__(self): + return 'OptionalParam' + + def raise_error(*args, **kwargs): + raise RuntimeError('can not be accessed') + + +OptionalParam = OptionalParamClass({'___optional_parameter__': True}) + + class WrongParam(MacroServerException): def __init__(self, *args): @@ -397,22 +419,25 @@ def decodeNormal(self, raw_param, param_def): else: value = raw_param # None or [] indicates default value - if value is None or (isinstance(value, list) and len(value) == 0): + if value is None or (isinstance(value, list) and + len(value) == 0): value = param_def['default_value'] if value is None: - raise MissingParam, "'%s' not specified" % name + raise MissingParam("'%s' not specified" % name) + elif isinstance(value, OptionalParamClass): + param = OptionalParam else: # cast to sting to fulfill with ParamType API - value = str(value) - param = param_type.getObj(value) - except ValueError, e: - raise WrongParamType, e.message - except UnknownParamObj, e: - raise WrongParam, e.message + param = param_type.getObj(str(value)) + + except ValueError as e: + raise WrongParamType(e.message) + except UnknownParamObj as e: + raise WrongParam(e.message) if param is None: msg = 'Could not create %s parameter "%s" for "%s"' % \ (param_type.getName(), name, raw_param) - raise WrongParam, msg + raise WrongParam(msg) return param def decodeRepeat(self, raw_param_repeat, param_repeat_def): From 93ee0dc91926c0a479bcf7ac043f48adac41abff Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 19 Jul 2018 16:31:49 +0200 Subject: [PATCH 018/652] Adapt macroexecutor to support optional parameters --- .../taurus/core/tango/sardana/macro.py | 18 ++++++++---- .../extra_macroexecutor/macroexecutor.py | 28 ++++++++++++++----- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py index 25c4a34af2..45356bdabe 100755 --- a/src/sardana/taurus/core/tango/sardana/macro.py +++ b/src/sardana/taurus/core/tango/sardana/macro.py @@ -1,5 +1,5 @@ #!/usr/bin/env python - +from __future__ import absolute_import ############################################################################## ## # This file is part of Sardana @@ -41,6 +41,7 @@ from taurus.core.util.user import USER_NAME from taurus.core.util.codecs import CodecFactory +from sardana.macroserver.msparameter import OptionalParam class MacroRunException(Exception): @@ -487,9 +488,9 @@ def __init__(self, parent=None, param=None): if param is None: return self.setType(str(param.get('type'))) - self.setDefValue(str(param.get('default_value', None))) + self.setDefValue(param.get('default_value', None)) if self.type() == "User": - self.setDefValue(str(USER_NAME)) + self.setDefValue(USER_NAME) self._value = None def __len__(self): @@ -507,7 +508,9 @@ def setValue(self, value): self._value = value def defValue(self): - return self._defValue + if self._defValue is None: + return None + return str(self._defValue) def setDefValue(self, defValue): if defValue == "None": @@ -525,8 +528,9 @@ def toXml(self): paramElement = etree.Element("param", name=self.name()) # set value attribute only if it is different than the default value # the server will assign the default value anyway. - if value is not None and value != self.defValue(): - paramElement.set("value", value) + if value is not None or str(value).lower() != 'none': + if value != self.defValue(): + paramElement.set("value", value) return paramElement def fromXml(self, xmlElement): @@ -548,6 +552,8 @@ def toRun(self): if self.defValue() is None: alert = "Parameter " + self.name() + " is missing.
" return ([val], alert) + elif self._defValue == OptionalParam: + val = '' else: val = self.defValue() return ([val], "") diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index f3115c55bb..8d6fbbf872 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -47,6 +47,8 @@ from .favouriteseditor import FavouritesMacrosEditor, HistoryMacrosViewer from .common import MacroComboBox, MacroExecutionWindow, standardPlotablesFilter +from sardana.macroserver.msparameter import OptionalParam + class MacroProgressBar(Qt.QProgressBar): @@ -256,11 +258,16 @@ def validateAllExpresion(self, secValidation=False): self.setStyleSheet("") self.setToolTip('
'.join(problems)) return - self.currentIndex = Qt.QModelIndex() ix = self.getIndex() self.currentIndex = ix counter = 1 + + # Get the parameters information to check if there are optional + # paramters + macro_obj = self.getModelObj() + macro_params_info = macro_obj.getElementInfo(mlist[0]).parameters + while not ix == Qt.QModelIndex(): try: propValue = mlist[counter] @@ -274,13 +281,20 @@ def validateAllExpresion(self, secValidation=False): message = "" + txt + " " + e[0] problems.append(message) except IndexError: - txt = str(Qt.from_qvariant( - ix.sibling(ix.row(), 0).data(), str)) - problems.append("" + txt + " is missing!") + param_info = macro_params_info[counter-1] + # Skip validation in case of optional parameters + if param_info['default_value'] == OptionalParam: + self.model().setData(self.currentIndex, + Qt.QVariant(None)) + else: + txt = str(Qt.from_qvariant( + ix.sibling(ix.row(), 0).data(), str)) + problems.append("" + txt + " is missing!") - data = str(Qt.from_qvariant(ix.data(), str)) - if data != 'None': - self.model().setData(self.currentIndex, Qt.QVariant('None')) + data = str(Qt.from_qvariant(ix.data(), str)) + if data != 'None': + self.model().setData(self.currentIndex, + Qt.QVariant('None')) counter += 1 ix = self.getIndex() self.currentIndex = ix From 116e087a9eb7af0b46fb29b73d0f0bdcf64b1bd5 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 20 Jul 2018 12:26:13 +0200 Subject: [PATCH 019/652] Add OptionalParam documentation --- .../devel/howto_macros/macros_general.rst | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index e24f8a29ae..8822c50575 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -298,7 +298,9 @@ being a composed of four elements: - parameter name - parameter type - - parameter default value (None means no default value) + - parameter default value: + * None means no default value + * :ref:`OptionalParam ` - parameter description Here is a list of the most common allowed parameter types: @@ -321,6 +323,39 @@ The complete list of types distributed with sardana is made up by these five simple types: ``Integer``, ``Float``, ``Boolean``, ``String``, ``Any``, plus all available sardana interfaces (:obj:`~sardana.sardanadefs.Interface`) +.. _sardana-macro-optional-parameters: + +Optional parameters +~~~~~~~~~~~~~~~~~ + +A special default value is the *OptionalParam*. It allows to the macro +identify if the user introduces a value or not to take a decision. + +So, here is an example how to define and use a optional parameter:: + + from sardana.macroserver.macro import Macro, Type, OptionalParam + + class count(Macro): + + param_def = [ + ['itime', Type.Float, 1, 'integration time'], + ['mntgrp', Type.MeasurementGroup, OptionalParam, 'MntGrp to use'] + ] + + def run(self, itime, mntgrp): + bkp_active_mntgrp = None + try: + if mntgrp is not OptionalParam: + bkp_active_mntgrp = self.getEnv('ActiveMntGrp') + self.setEnv('ActiveMntGrp', mntgrp.name) + self.info('Use "{0}" measurement ' + 'group'.format(self.getEnv('ActiveMntGrp'))) + self.ct(itime) + finally: + if bkp_active_mntgrp is not None: + self.setEnv('ActiveMntGrp', bkp_active_mntgrp) + + .. _sardana-macro-repeat-parameters: Repeat parameters From e87a69e91a686c7d6420ba43aefb60714caf7f4b Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 23 Jul 2018 13:47:30 +0200 Subject: [PATCH 020/652] Fix flake8 error --- src/sardana/macroserver/msparameter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sardana/macroserver/msparameter.py b/src/sardana/macroserver/msparameter.py index de482ae035..9cf820989f 100644 --- a/src/sardana/macroserver/msparameter.py +++ b/src/sardana/macroserver/msparameter.py @@ -36,7 +36,6 @@ from copy import deepcopy from lxml import etree -import json from taurus.core.util.containers import CaselessDict from sardana import ElementType, INTERFACES_EXPANDED From e2c82cf9c2dbafd42585427a80b4586726bcdb08 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 23 Jul 2018 13:52:10 +0200 Subject: [PATCH 021/652] Fix Sphinx warning --- doc/source/devel/howto_macros/macros_general.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 8822c50575..b2155540c7 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -326,7 +326,7 @@ all available sardana interfaces (:obj:`~sardana.sardanadefs.Interface`) .. _sardana-macro-optional-parameters: Optional parameters -~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~ A special default value is the *OptionalParam*. It allows to the macro identify if the user introduces a value or not to take a decision. From 1e091ea9513a7d981276169e2aa43a4885be226e Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 27 Jul 2018 12:05:35 +0200 Subject: [PATCH 022/652] Register Qt signal for Taurus 4 compatibility --- .../taurus/qt/qtcore/tango/sardana/macroserver.py | 10 +++++++++- src/sardana/taurus/qt/qtcore/tango/sardana/pool.py | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 5907fa046b..95c03baedf 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -105,6 +105,15 @@ def logReceived(self, log_name, output): class QMacroServer(BaseMacroServer, Qt.QObject): + # TODO: For Taurus 4 compatibility + try: + typesUpdated = Qt.pyqtSignal() + elementsUpdated = Qt.pyqtSignal() + elementsChanged = Qt.pyqtSignal() + macrosUpdated = Qt.pyqtSignal() + environmentChange = Qt.pyqtSignal(list) + except AttributeError: + pass def __init__(self, name, qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) @@ -145,7 +154,6 @@ def on_elements_changed(self, s, t, v): def on_environment_changed(self, s, t, v): ret = added, removed, changed = \ BaseMacroServer.on_environment_changed(self, s, t, v) - if added or removed or changed: self.emit(Qt.SIGNAL("environmentChanged"), ret) return ret diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py index 9b0ca17fc4..2ad5335966 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py @@ -46,6 +46,11 @@ def __init__(self, name, qt_parent=None, **kw): class QMeasurementGroup(Qt.QObject, TangoDevice): + # TODO: For Taurus 4 compatibility + try: + configurationChanged = Qt.pyqtSignal() + except AttributeError: + pass def __init__(self, name, qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) From 5f8d37113553681afc0edb696e8e8d93a4d736bc Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 27 Jul 2018 15:42:45 +0200 Subject: [PATCH 023/652] Store configuration attribute Store configuration attribute to receive the change events. --- src/sardana/taurus/qt/qtcore/tango/sardana/pool.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py index 2ad5335966..5a47d4e56a 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py @@ -57,8 +57,8 @@ def __init__(self, name, qt_parent=None, **kw): self.call__init__(TangoDevice, name, **kw) self._config = None - configuration = self.getAttribute("Configuration") - configuration.addListener(self._configurationChanged) + self.__configuration = self.getAttribute("Configuration") + self.__configuration.addListener(self._configurationChanged) def __getattr__(self, name): try: From fc0d3519b85ff05d84e2fc4d7bf07997647fabd1 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 27 Jul 2018 18:51:01 +0200 Subject: [PATCH 024/652] Add experimentConfigurationChange signal Implement the experimentConfigurationChanged Qt.Signal which will be emitted when: * There are changes on the MacroServer enviroment. * Adding or Removing measurement groups. * Change the Measurment Groups configurations --- .../qt/qtcore/tango/sardana/macroserver.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 95c03baedf..beed9b30ca 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -52,12 +52,15 @@ class QDoor(BaseDoor, Qt.QObject): infoUpdated = Qt.pyqtSignal(object) outputUpdated = Qt.pyqtSignal(object) debugUpdated = Qt.pyqtSignal(object) + experimentConfigurationChanged = Qt.pyqtSignal() except AttributeError: pass def __init__(self, name, qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) self.call__init__(BaseDoor, name, **kw) + self._mntgrp_connected = [] + self._use_experimet_configuration = False def resultReceived(self, log_name, result): res = BaseDoor.resultReceived(self, log_name, result) @@ -103,6 +106,40 @@ def logReceived(self, log_name, output): pass return res + def _prepare_connections(self): + if not self._use_experimet_configuration: + self.connect(self.macro_server, Qt.SIGNAL("environmentChanged"), + self._experimentalConfiguration) + self.connect(self.macro_server, Qt.SIGNAL("elementsChanged"), + self._elementsChanged) + + def _elementsChanged(self): + len_mnt_grps_connected = len(self._mntgrp_connected) + elements = self.macro_server.getElementsOfType("MeasurementGroup") + for name, mg in elements.items(): + if name in self._mntgrp_connected: + continue + else: + obj = mg.getObj() + self.connect(obj, Qt.SIGNAL("configurationChanged"), + self._experimentalConfiguration) + self._mntgrp_connected.append(name) + + if len(self._mntgrp_connected) != len_mnt_grps_connected: + self.emit(Qt.SIGNAL("experimentConfigurationChanged")) + + def _experimentalConfiguration(self, *args): + self.emit(Qt.SIGNAL("experimentConfigurationChanged")) + + def getExperimentConfigurationObj(self): + self._prepare_connections() + return BaseDoor.getExperimentConfigurationObj(self) + + def getExperimentConfiguration(self): + self._prepare_connections() + return BaseDoor.getExperimentConfiguration(self) + + class QMacroServer(BaseMacroServer, Qt.QObject): # TODO: For Taurus 4 compatibility From dd1452e8c90fd6e5caa89f474439c8c220a1eb83 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 27 Jul 2018 18:53:36 +0200 Subject: [PATCH 025/652] Find different on ExperimentConfiguration objects. --- .../qt/qtgui/extra_sardana/expdescription.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index bd7195bdca..aba2c4af3b 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -66,6 +66,55 @@ def filterAcceptsRow(self, sourceRow, sourceParent): return True +def find_diff(first, second): + """ + Return a dict of keys that differ with another config object. If a value + is not found in one fo the configs, it will be represented by KEYNOTFOUND. + @param first: Fist configuration to diff. + @param second: Second configuration to diff. + @return diff: Dict of Key => (first.val, second.val) + """ + + KEYNOTFOUNDIN1 = 'KeyNotFoundInRemote' + KEYNOTFOUNDIN2 = 'KeyNotFoundInLocal' + SKIPKEYS = ['_controller_name'] + SKIPLIST = ['scanfile'] + DICT_TYPES = [taurus.core.util.containers.CaselessDict, dict] + diff = {} + sd1 = set(first) + sd2 = set(second) + # Keys missing in the second dict + + for key in sd1.difference(sd2): + if key in SKIPKEYS: + continue + diff[key] = (first[key], KEYNOTFOUNDIN2) + # Keys missing in the first dict + for key in sd2.difference(sd1): + if key in SKIPKEYS: + continue + diff[key] = (KEYNOTFOUNDIN1, second[key]) + # Check for differences + for key in sd1.intersection(sd2): + value1 = first[key] + value2 = second[key] + if type(value1) in DICT_TYPES: + idiff = find_diff(value1, value2) + if len(idiff) > 0: + diff[key] = idiff + elif type(value1) == list and key.lower() not in SKIPLIST: + ldiff = [] + for v1, v2 in zip(value1, value2): + idiff = find_diff(v1, v2) + ldiff.append(idiff) + if len(ldiff) > 0: + diff[key] = ldiff + else: + if value1 != value2: + diff[key] = (first[key], second[key]) + return diff + + @UILoadable(with_ui='ui') class ExpDescriptionEditor(Qt.QWidget, TaurusBaseWidget): ''' From 849e2f1422815af0c7c3d98aae07eab1a8419ef9 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 27 Jul 2018 18:56:28 +0200 Subject: [PATCH 026/652] Create internal Qt.Signal Add createExpConfChangedDialog Signal to create the message box and use it for futures change events. --- .../taurus/qt/qtgui/extra_sardana/expdescription.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index aba2c4af3b..248e3fb6ec 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -147,6 +147,12 @@ def __init__(self, parent=None, door=None, plotsButton=True): self._dirty = False self._dirtyMntGrps = set() + # Pending event variables + self._expConfChangedDialog = None + self.createExpConfChangedDialog = Qt.pyqtSignal() + self.connect(self, Qt.SIGNAL('createExpConfChangedDialog'), + self._createExpConfChangedDialog) + self.connect(self.ui.activeMntGrpCB, Qt.SIGNAL( 'activated (QString)'), self.changeActiveMntGrp) self.connect(self.ui.createMntGrpBT, Qt.SIGNAL( @@ -229,6 +235,8 @@ def setModel(self, model): msname = door.macro_server.getFullName() self.ui.taurusModelTree.setModel(tghost) self.ui.sardanaElementTree.setModel(msname) + self.connect(door, Qt.SIGNAL("experimentConfigurationChanged"), + self._experimentalConfigurationChanged) def _reloadConf(self, force=False): if not force and self.isDataChanged(): From e7d18b40b465388bfa048d037ca60405dedb2b9f Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 27 Jul 2018 18:57:32 +0200 Subject: [PATCH 027/652] Implement message dialog. --- .../qt/qtgui/extra_sardana/expdescription.py | 97 ++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 248e3fb6ec..add95f393e 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -27,7 +27,9 @@ __all__ = ["ExpDescriptionEditor"] -from taurus.external.qt import Qt + +import json +from taurus.external.qt import Qt, QtCore import copy import taurus import taurus.core @@ -198,6 +200,99 @@ def __init__(self, parent=None, door=None, plotsButton=True): # Taurus Configuration properties and delegates self.registerConfigDelegate(self.ui.channelEditor) + def _getResumeText(self): + msg_resume = '

Summary of changes:

    ' + mnt_grps = '' + envs = '' + for key in self._diff: + if key == 'MntGrpConfigs': + for names in self._diff['MntGrpConfigs']: + if mnt_grps != '': + mnt_grps += ', ' + mnt_grps += '{0}'.format(names) + else: + if envs != '': + envs += ', ' + envs += '{0}'.format(key) + values = '' + if mnt_grps != '': + values += '
  • Measurement Groups: {0}
  • '.format(mnt_grps) + if envs != '': + values += '
  • Enviroment variables: {0}
  • '.format(envs) + + msg_resume += values + msg_resume += '

' + return msg_resume + + def _getDetialsText(self): + msg_detials = 'Changes {key: [external, local], ...}\n' + msg_detials += json.dumps(self._diff, sort_keys=True) + return msg_detials + + def _createExpConfChangedDialog(self): + msg_details = self._getDetialsText() + msg_info = self._getResumeText() + self._expConfChangedDialog = Qt.QMessageBox() + self._expConfChangedDialog.setIcon(Qt.QMessageBox.Warning) + self._expConfChangedDialog.setWindowTitle('External Changes') + # text = ''' + #

+ # The experiment configuration has been modified externally.
+ # You can either:
Load the new configuration from the + # door + # (discarding local changes) or Keep your local configuration + # (would eventually overwrite the external changes when applying). + #

''' + text = ''' +

The experiment configuration has been modified externally. + You can either: +

    +
  • Load the new configuration from the door + (discarding local changes)
  • +
  • Keep your local configuration (would eventually + overwrite the external changes when applying)
  • +

+ ''' + self._expConfChangedDialog.setText(text) + self._expConfChangedDialog.setTextFormat(QtCore.Qt.RichText) + self._expConfChangedDialog.setInformativeText(msg_info) + self._expConfChangedDialog.setDetailedText(msg_details) + self._expConfChangedDialog.setStandardButtons(Qt.QMessageBox.Ok | + Qt.QMessageBox.Cancel) + btn_ok = self._expConfChangedDialog.button(Qt.QMessageBox.Ok) + btn_ok.setText('Load') + btn_cancel = self._expConfChangedDialog.button(Qt.QMessageBox.Cancel) + btn_cancel.setText('Keep') + result = self._expConfChangedDialog.exec_() + self._expConfChangedDialog = None + if result == Qt.QMessageBox.Ok: + self._reloadConf(force=True) + + @QtCore.pyqtSlot() + def _experimentalConfigurationChanged(self): + try: + self._diff = self._getDiff() + except Exception: + return + + if len(self._diff) > 0: + if self._expConfChangedDialog is None: + self.emit(Qt.SIGNAL('createExpConfChangedDialog')) + else: + msg_details = self._getDetialsText() + msg_info = self._getResumeText() + self._expConfChangedDialog.setInformativeText(msg_info) + self._expConfChangedDialog.setDetailedText(msg_details) + + def _getDiff(self): + door = self.getModelObj() + if door is None: + return [] + + new_conf = door.getExperimentConfiguration() + old_conf = self._localConfig + return find_diff(new_conf, old_conf) + def getModelClass(self): '''reimplemented from :class:`TaurusBaseWidget`''' return taurus.core.taurusdevice.TaurusDevice From e9f012937938950f6efcd20b88555ebe31ff11c1 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 30 Jul 2018 10:17:51 +0200 Subject: [PATCH 028/652] Fix flake8 errors --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index add95f393e..4ff2ea806b 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -247,9 +247,9 @@ def _createExpConfChangedDialog(self):

The experiment configuration has been modified externally. You can either:

    -
  • Load the new configuration from the door +
  • Load the new configuration from the door (discarding local changes)
  • -
  • Keep your local configuration (would eventually +
  • Keep your local configuration (would eventually overwrite the external changes when applying)

''' From a640f723064d874695053209331d48a65705e6d2 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 30 Jul 2018 11:55:17 +0200 Subject: [PATCH 029/652] Change reset button label Change label to Reload which is more in line with its function. --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 4ff2ea806b..610e0617dd 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -133,6 +133,8 @@ def __init__(self, parent=None, door=None, plotsButton=True): self.loadUi() self.ui.buttonBox.setStandardButtons( Qt.QDialogButtonBox.Reset | Qt.QDialogButtonBox.Apply) + self.ui.buttonBox.button(Qt.QDialogButtonBox.Reset).setText('Reload') + newperspectivesDict = copy.deepcopy( self.ui.sardanaElementTree.KnownPerspectives) #newperspectivesDict[self.ui.sardanaElementTree.DftPerspective]['model'] = [SardanaAcquirableProxyModel, SardanaElementPlainModel] From 0582890aed65e67e026fe5b9024d76087b8a64fd Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 30 Jul 2018 15:21:22 +0200 Subject: [PATCH 030/652] Add Start AcqSyncType --- src/sardana/pool/pooldefs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/pool/pooldefs.py b/src/sardana/pool/pooldefs.py index 740118d72a..e5ac46e667 100644 --- a/src/sardana/pool/pooldefs.py +++ b/src/sardana/pool/pooldefs.py @@ -114,7 +114,7 @@ class SynchParam(SynchEnum): # Trigger = 0 # Gate = 1 -AcqSynchType = Enumeration("AcqSynchType", ["Trigger", "Gate"]) +AcqSynchType = Enumeration("AcqSynchType", ["Trigger", "Gate", "Start"]) # TODO: convert to to python enums, but having in ming problems with From 11b9cacdb4fcce6eafb63eca03cb3a99ad2bd0c4 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 30 Jul 2018 15:33:00 +0200 Subject: [PATCH 031/652] Add two new AcqSync Add SoftwareStart and HardwareStart as new acquisition synchronizations. --- src/sardana/pool/pooldefs.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sardana/pool/pooldefs.py b/src/sardana/pool/pooldefs.py index e5ac46e667..7ca8be11c6 100644 --- a/src/sardana/pool/pooldefs.py +++ b/src/sardana/pool/pooldefs.py @@ -125,6 +125,8 @@ class AcqSynch(Enumeration): HardwareTrigger = 1 SoftwareGate = 2 HardwareGate = 3 + SoftwareStart = 4 + HardwareStart = 5 @classmethod def from_synch_type(self, software, synch_type): @@ -141,6 +143,11 @@ def from_synch_type(self, software, synch_type): return AcqSynch.SoftwareGate else: return AcqSynch.HardwareGate + elif synch_type is AcqSynchType.Start: + if software: + return AcqSynch.SoftwareStart + else: + return AcqSynch.HardwareStart else: raise ValueError("Unable to determine AcqSynch from %s" % synch_type) From c84c47d4f311c6098329d2587931fd01bc44c7fc Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 30 Jul 2018 15:55:31 +0200 Subject: [PATCH 032/652] Fix flake8 errors --- src/sardana/pool/pooldefs.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/pooldefs.py b/src/sardana/pool/pooldefs.py index 7ca8be11c6..8c995527ed 100644 --- a/src/sardana/pool/pooldefs.py +++ b/src/sardana/pool/pooldefs.py @@ -68,7 +68,8 @@ class SynchDomain(SynchEnum): - Time - describes the synchronization in time domain - Position - describes the synchronization in position domain - - Monitor - not used at the moment but foreseen for synchronization on monitor + - Monitor - not used at the moment but foreseen for synchronization on + monitor .. note:: The SynchDomain class has been included in Sardana @@ -81,7 +82,8 @@ class SynchDomain(SynchEnum): Monitor = 2 # - Default - the controller selects the most appropriate domain: # for active events the precedence should be first Position and then Time -# for passive events the precedence should be first Time and then Position +# for passive events the precedence should be first Time and then +# Position # Default = 3 @@ -114,6 +116,7 @@ class SynchParam(SynchEnum): # Trigger = 0 # Gate = 1 + AcqSynchType = Enumeration("AcqSynchType", ["Trigger", "Gate", "Start"]) From b4a2bbb1a537db1af96e37eab4f39836897b5986 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 1 Aug 2018 12:36:32 +0200 Subject: [PATCH 033/652] Add auto-update as optional parameter --- src/sardana/spock/magic.py | 3 ++- .../qt/qtgui/extra_sardana/expdescription.py | 24 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/sardana/spock/magic.py b/src/sardana/spock/magic.py index db0e0bf9b3..73a66b081a 100644 --- a/src/sardana/spock/magic.py +++ b/src/sardana/spock/magic.py @@ -62,9 +62,10 @@ def expconf(self, parameter_s=''): # https://sourceforge.net/p/sardana/tickets/10/ import subprocess import sys - fname = sys.modules[ExpDescriptionEditor.__module__].__file__ args = ['python', fname, doorname] + if parameter_s == '--auto-update': + args.insert(2, parameter_s) subprocess.Popen(args) # =========================================================================== diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 610e0617dd..ad4e176eb9 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -127,7 +127,8 @@ class ExpDescriptionEditor(Qt.QWidget, TaurusBaseWidget): using the `ExperimentConfiguration` environmental variable for that Door. ''' - def __init__(self, parent=None, door=None, plotsButton=True): + def __init__(self, parent=None, door=None, plotsButton=True, + autoUpdate=False): Qt.QWidget.__init__(self, parent) TaurusBaseWidget.__init__(self, 'ExpDescriptionEditor') self.loadUi() @@ -150,6 +151,7 @@ def __init__(self, parent=None, door=None, plotsButton=True): self._originalConfiguration = None self._dirty = False self._dirtyMntGrps = set() + self._autoUpdate = autoUpdate # Pending event variables self._expConfChangedDialog = None @@ -598,10 +600,10 @@ def onPlotsButtonToggled(self, checked): self.__plotManager = None -def demo(model=None): +def demo(model=None, autoUpdate=False): """Experiment configuration""" #w = main_ChannelEditor() - w = ExpDescriptionEditor() + w = ExpDescriptionEditor(autoUpdate=autoUpdate) if model is None: from sardana.taurus.qt.qtgui.extra_macroexecutor import \ TaurusMacroConfigurationDialog @@ -621,14 +623,23 @@ def main(): app = Application.instance() owns_app = app is None - if owns_app: + import taurus.core.util.argparse + parser = taurus.core.util.argparse.get_taurus_parser() + parser.usage = "%prog [options] " + parser.add_option('--auto-update', dest='auto_update', + action='store_true', + help='Set auto update of experimental configuration') app = Application(app_name="Exp. Description demo", app_version="1.0", - org_domain="Sardana", org_name="Tango community") + org_domain="Sardana", org_name="Tango community", + cmd_line_parser=parser) args = app.get_command_line_args() + opt = app.get_command_line_options() + if len(args) == 1: - w = demo(model=args[0]) + auto_update = opt.auto_update is not None + w = demo(model=args[0], autoUpdate=auto_update) else: w = demo() w.show() @@ -638,5 +649,6 @@ def main(): else: return w + if __name__ == "__main__": main() From f93e173a5200f0ea9553a49d5a9683ecd154ed11 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 1 Aug 2018 13:28:09 +0200 Subject: [PATCH 034/652] Implement auto-update mechanism --- .../qt/qtgui/extra_sardana/expdescription.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index ad4e176eb9..4fef4ca554 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -280,13 +280,16 @@ def _experimentalConfigurationChanged(self): return if len(self._diff) > 0: - if self._expConfChangedDialog is None: - self.emit(Qt.SIGNAL('createExpConfChangedDialog')) + if self._autoUpdate: + self._reloadConf(force=True) else: - msg_details = self._getDetialsText() - msg_info = self._getResumeText() - self._expConfChangedDialog.setInformativeText(msg_info) - self._expConfChangedDialog.setDetailedText(msg_details) + if self._expConfChangedDialog is None: + self.emit(Qt.SIGNAL('createExpConfChangedDialog')) + else: + msg_details = self._getDetialsText() + msg_info = self._getResumeText() + self._expConfChangedDialog.setInformativeText(msg_info) + self._expConfChangedDialog.setDetailedText(msg_details) def _getDiff(self): door = self.getModelObj() From b04c91bd9ab1dd5b569f1c26c210c9a4d172e561 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Wed, 1 Aug 2018 13:58:46 +0200 Subject: [PATCH 035/652] typo --- src/sardana/macroserver/macros/standard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index ac2b9fd366..27773378f0 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -911,7 +911,7 @@ def run(self, ScanFileDir_list, ScanID): elif not os.path.exists(path): # check if folder exists self.error('Path %s does not exists on the host of the ' - 'MacroServerand has to be created in ' + 'MacroServer and has to be created in ' 'advance.' % path) return else: From 17411bf5cf33dd70cfc77da00ccd91288e70e3de Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 2 Aug 2018 17:22:54 +0200 Subject: [PATCH 036/652] Add warning message on auto-update mode --- .../qt/qtgui/extra_sardana/expdescription.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 4fef4ca554..d68c66d417 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -29,7 +29,7 @@ import json -from taurus.external.qt import Qt, QtCore +from taurus.external.qt import Qt, QtCore, QtGui import copy import taurus import taurus.core @@ -151,7 +151,12 @@ def __init__(self, parent=None, door=None, plotsButton=True, self._originalConfiguration = None self._dirty = False self._dirtyMntGrps = set() + + # Add warning message to the Widget self._autoUpdate = autoUpdate + if self._autoUpdate: + w = self._getWarningWidget() + self.ui.verticalLayout_3.insertWidget(0, w) # Pending event variables self._expConfChangedDialog = None @@ -204,6 +209,21 @@ def __init__(self, parent=None, door=None, plotsButton=True, # Taurus Configuration properties and delegates self.registerConfigDelegate(self.ui.channelEditor) + def _getWarningWidget(self): + w = Qt.QWidget() + layout = QtGui.QHBoxLayout() + w.setLayout(layout) + icon = QtGui.QIcon.fromTheme('dialog-warning') + pixmap =QtGui.QPixmap(icon.pixmap(QtCore.QSize(32, 32))) + label_icon = QtGui.QLabel() + label_icon.setPixmap(pixmap) + label = QtGui.QLabel('This experiment configuration dialog ' + 'updates automatically on external changes!') + layout.addWidget(label_icon) + layout.addWidget(label) + layout.addStretch(1) + return w + def _getResumeText(self): msg_resume = '

Summary of changes:

    ' mnt_grps = '' From 0f1d9ef42a0cc3e0f309c81ac2fc20675c4041a2 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 2 Aug 2018 17:47:38 +0200 Subject: [PATCH 037/652] Fix flake8 errors --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index d68c66d417..a57db3c626 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -214,7 +214,7 @@ def _getWarningWidget(self): layout = QtGui.QHBoxLayout() w.setLayout(layout) icon = QtGui.QIcon.fromTheme('dialog-warning') - pixmap =QtGui.QPixmap(icon.pixmap(QtCore.QSize(32, 32))) + pixmap = QtGui.QPixmap(icon.pixmap(QtCore.QSize(32, 32))) label_icon = QtGui.QLabel() label_icon.setPixmap(pixmap) label = QtGui.QLabel('This experiment configuration dialog ' From 3405457b2778f69d6262dab86605aaa906c7d2c6 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 2 Aug 2018 18:17:31 +0200 Subject: [PATCH 038/652] Return a None instead of OptionalParam --- doc/source/devel/howto_macros/macros_general.rst | 2 +- src/sardana/macroserver/msparameter.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index b2155540c7..25897c470a 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -345,7 +345,7 @@ So, here is an example how to define and use a optional parameter:: def run(self, itime, mntgrp): bkp_active_mntgrp = None try: - if mntgrp is not OptionalParam: + if mntgrp is not None: bkp_active_mntgrp = self.getEnv('ActiveMntGrp') self.setEnv('ActiveMntGrp', mntgrp.name) self.info('Use "{0}" measurement ' diff --git a/src/sardana/macroserver/msparameter.py b/src/sardana/macroserver/msparameter.py index 9cf820989f..a85bdaec1d 100644 --- a/src/sardana/macroserver/msparameter.py +++ b/src/sardana/macroserver/msparameter.py @@ -407,6 +407,7 @@ def decodeNormal(self, raw_param, param_def): """ param_type = param_def["type"] name = param_def["name"] + optional_param = False if isinstance(param_type, list): param = self.decodeRepeat(raw_param, param_def) else: @@ -424,7 +425,8 @@ def decodeNormal(self, raw_param, param_def): if value is None: raise MissingParam("'%s' not specified" % name) elif isinstance(value, OptionalParamClass): - param = OptionalParam + param = None + optional_param = True else: # cast to sting to fulfill with ParamType API param = param_type.getObj(str(value)) @@ -433,7 +435,7 @@ def decodeNormal(self, raw_param, param_def): raise WrongParamType(e.message) except UnknownParamObj as e: raise WrongParam(e.message) - if param is None: + if param is None and not optional_param: msg = 'Could not create %s parameter "%s" for "%s"' % \ (param_type.getName(), name, raw_param) raise WrongParam(msg) From 1b8b8c009da00bb87197307fcc73c116001421a3 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Mon, 6 Aug 2018 15:50:49 +0200 Subject: [PATCH 039/652] change logstash to logstash-async --- src/sardana/tango/core/util.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sardana/tango/core/util.py b/src/sardana/tango/core/util.py index 91b7af4ba9..20ff712945 100644 --- a/src/sardana/tango/core/util.py +++ b/src/sardana/tango/core/util.py @@ -914,7 +914,7 @@ def prepare_logstash(args): log_messages = [] try: - import logstash + from logstash_async.handler import AsynchronousLogstashHandler except ImportError: msg = ("Unable to import logstash. Skipping logstash " + "configuration...", ) @@ -953,7 +953,8 @@ def get_logstash_conf(dev_name): if host is not None: root = Logger.getRootLog() - handler = logstash.TCPLogstashHandler(host, port, version=1) + handler = AsynchronousLogstashHandler(host, port, + database_path="/tmp/sardana-logstash-cache.db") root.addHandler(handler) msg = ("Log is being sent to logstash listening on %s:%d", host, port) From e6c574d85737e1aeb532b02709e471f3194168e3 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Mon, 6 Aug 2018 16:47:55 +0200 Subject: [PATCH 040/652] don't use full path as program_name --- src/sardana/tango/core/util.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sardana/tango/core/util.py b/src/sardana/tango/core/util.py index 20ff712945..cb0c1f0ceb 100644 --- a/src/sardana/tango/core/util.py +++ b/src/sardana/tango/core/util.py @@ -955,6 +955,9 @@ def get_logstash_conf(dev_name): root = Logger.getRootLog() handler = AsynchronousLogstashHandler(host, port, database_path="/tmp/sardana-logstash-cache.db") + # don't use full path for program_name + handler._create_formatter_if_necessary() + _, handler.formatter._program_name = os.path.split(handler.formatter._program_name) root.addHandler(handler) msg = ("Log is being sent to logstash listening on %s:%d", host, port) From 938ff107d291bd80022bf57dd309d3f2209e3c59 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Mon, 6 Aug 2018 17:11:00 +0200 Subject: [PATCH 041/652] add configuration endpoints for logstash cache --- src/sardana/tango/core/util.py | 23 ++++++++++++++------ src/sardana/tango/macroserver/MacroServer.py | 11 +++++++++- src/sardana/tango/pool/Pool.py | 11 +++++++++- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/sardana/tango/core/util.py b/src/sardana/tango/core/util.py index cb0c1f0ceb..ffb817fce9 100644 --- a/src/sardana/tango/core/util.py +++ b/src/sardana/tango/core/util.py @@ -921,7 +921,7 @@ def prepare_logstash(args): log_messages.append(msg,) return log_messages - def get_logstash_conf(dev_name): + def get_logstash_conf(dev_name, class_name=None): try: props = db.get_device_property(dev_name, "LogstashHost") host = props["LogstashHost"][0] @@ -932,7 +932,17 @@ def get_logstash_conf(dev_name): port = int(props["LogstashPort"][0]) except IndexError: port = 12345 - return host, port + try: + props = db.get_device_property(dev_name, "LogstashCacheDbPath") + cache_db_path = int(props["LogstashCacheDbPath"][0]) + except IndexError: + if class_name == "Pool": + cache_db_path = "/tmp/sardana-pool-logstash-cache.db" + elif class_name == "MacroServer": + cache_db_path = "/tmp/sardana-ms-logstash-cache.db" + else: + cache_db_path = "/tmp/sardana-logstash-cache.db" + return host, port, cache_db_path db = Database() @@ -942,19 +952,18 @@ def get_logstash_conf(dev_name): if bin_name in ["Pool", "MacroServer"]: class_name = bin_name dev_name = get_dev_from_class_server(db, class_name, server_name)[0] - host, port = get_logstash_conf(dev_name) + host, port, cache = get_logstash_conf(dev_name, class_name) else: dev_name = get_dev_from_class_server(db, "Pool", server_name)[0] - host, port = get_logstash_conf(dev_name) + host, port, cache = get_logstash_conf(dev_name) if host is None: dev_name = get_dev_from_class_server(db, "MacroServer", server_name)[0] - host, port = get_logstash_conf(dev_name) + host, port, cache = get_logstash_conf(dev_name) if host is not None: root = Logger.getRootLog() - handler = AsynchronousLogstashHandler(host, port, - database_path="/tmp/sardana-logstash-cache.db") + handler = AsynchronousLogstashHandler(host, port, database_path=cache) # don't use full path for program_name handler._create_formatter_if_necessary() _, handler.formatter._program_name = os.path.split(handler.formatter._program_name) diff --git a/src/sardana/tango/macroserver/MacroServer.py b/src/sardana/tango/macroserver/MacroServer.py index 13e8c1be51..7a0e73ed3f 100644 --- a/src/sardana/tango/macroserver/MacroServer.py +++ b/src/sardana/tango/macroserver/MacroServer.py @@ -397,7 +397,16 @@ class MacroServerClass(SardanaDeviceClass): "basis. Backwards incompatible changes (up to and including " "its removal) may occur if deemed necessary by the " "core developers.", - None] + None], + 'LogstashCacheDbPath': + [DevString, + "Path to the Logstash cache database [default: " + "/tmp/sardana-ms-logstash-cache.db]. " + "This property has been included in Sardana on a provisional " + "basis. Backwards incompatible changes (up to and including " + "its removal) may occur if deemed necessary by the " + "core developers.", + "/tmp/sardana-ms-logstash-cache.db"] } # Command definitions diff --git a/src/sardana/tango/pool/Pool.py b/src/sardana/tango/pool/Pool.py index 4930368afa..eda5ec3a33 100644 --- a/src/sardana/tango/pool/Pool.py +++ b/src/sardana/tango/pool/Pool.py @@ -1380,7 +1380,16 @@ class PoolClass(PyTango.DeviceClass): "basis. Backwards incompatible changes (up to and including " "its removal) may occur if deemed necessary by the " "core developers.", - None] + None], + 'LogstashCacheDbPath': + [PyTango.DevString, + "Path to the Logstash cache database [default: " + "/tmp/sardana-pool-logstash-cache.db]. " + "This property has been included in Sardana on a provisional " + "basis. Backwards incompatible changes (up to and including " + "its removal) may occur if deemed necessary by the " + "core developers.", + "/tmp/sardana-pool-logstash-cache.db"] } # Command definitions From 361b5d64eb1c7d07daff476ad22fcb2f62ced7f8 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Tue, 7 Aug 2018 12:45:35 +0200 Subject: [PATCH 042/652] fix logstash cache path property --- src/sardana/tango/core/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/tango/core/util.py b/src/sardana/tango/core/util.py index ffb817fce9..e2631eca6e 100644 --- a/src/sardana/tango/core/util.py +++ b/src/sardana/tango/core/util.py @@ -934,7 +934,7 @@ def get_logstash_conf(dev_name, class_name=None): port = 12345 try: props = db.get_device_property(dev_name, "LogstashCacheDbPath") - cache_db_path = int(props["LogstashCacheDbPath"][0]) + cache_db_path = props["LogstashCacheDbPath"][0] except IndexError: if class_name == "Pool": cache_db_path = "/tmp/sardana-pool-logstash-cache.db" From 97da009fba7b4bc60e2c1727aae6cf4dffa620c1 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Fri, 10 Aug 2018 16:52:27 +0200 Subject: [PATCH 043/652] Bump version 2.5.0 to 2.5.1-alpha --- .bumpversion.cfg | 2 +- src/sardana/release.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 49c6dfb671..99e68d31ca 100755 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ commit = True message = Bump version {current_version} to {new_version} tag = False tag_name = {new_version} -current_version = 2.5.0 +current_version = 2.5.1-alpha parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} diff --git a/src/sardana/release.py b/src/sardana/release.py index df919e5d06..118a97d4de 100644 --- a/src/sardana/release.py +++ b/src/sardana/release.py @@ -47,7 +47,7 @@ # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '2.5.0' +version = '2.5.1-alpha' # generate version_info and revision (**deprecated** since v 2.1.2--alpha). if '-' in version: From c31e4a125744fe0a21013683a51ffcff28e21b80 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Fri, 10 Aug 2018 18:17:25 +0200 Subject: [PATCH 044/652] Update how_to_release.md --- doc/how_to_release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/how_to_release.md b/doc/how_to_release.md index 62703082dc..cccdbf9064 100644 --- a/doc/how_to_release.md +++ b/doc/how_to_release.md @@ -63,7 +63,7 @@ tested. * Ilustration: sardana or official logo (use png) * Summary: short summary of the news (do not include the whole changelog here..) * Categories: Release - 2. After submitting click on Modify this content text of the area <> and provide detailes of the release e.g. changelog. + 2. After submitting click on Modify this content text of the area \<\\> and provide detailes of the release e.g. changelog. 12. Notify mailing lists (sardana-users@lists.sourceforge.net, sardana-devel@lists.sourceforge.net, info@tango-controls.org) ## Manual test checklist From 91fc6b37766913487f9b54fc4ad9261d92fa9690 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 21 Aug 2018 09:34:23 +0200 Subject: [PATCH 045/652] Avoid multi connections to the same Qt signals --- src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index beed9b30ca..4d280e6746 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -61,6 +61,7 @@ def __init__(self, name, qt_parent=None, **kw): self.call__init__(BaseDoor, name, **kw) self._mntgrp_connected = [] self._use_experimet_configuration = False + self._connections_prepared = False def resultReceived(self, log_name, result): res = BaseDoor.resultReceived(self, log_name, result) @@ -107,11 +108,13 @@ def logReceived(self, log_name, output): return res def _prepare_connections(self): - if not self._use_experimet_configuration: + if not self._use_experimet_configuration and \ + not self._connections_prepared: self.connect(self.macro_server, Qt.SIGNAL("environmentChanged"), self._experimentalConfiguration) self.connect(self.macro_server, Qt.SIGNAL("elementsChanged"), self._elementsChanged) + self._connections_prepared = True def _elementsChanged(self): len_mnt_grps_connected = len(self._mntgrp_connected) From 7cbdf0f022b9f6230e82061f7522daaa5a7d0496 Mon Sep 17 00:00:00 2001 From: teresa Date: Thu, 30 Aug 2018 11:28:56 +0200 Subject: [PATCH 046/652] Adapting for 4c diffrac --- src/sardana/macroserver/macros/hkl.py | 87 +++++++++++++++------------ 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py index 3073a540b4..5d391fc8e7 100644 --- a/src/sardana/macroserver/macros/hkl.py +++ b/src/sardana/macroserver/macros/hkl.py @@ -1,25 +1,3 @@ -############################################################################## -## -# This file is part of Sardana -## -# http://www.sardana-controls.org/ -## -# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain -## -# Sardana 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. -## -# Sardana 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 Sardana. If not, see . -## -############################################################################# """ Macro library containning diffractometer related macros for the macros @@ -27,14 +5,6 @@ """ -__all__ = ["addreflection", "affine", "br", "ca", "caa", "ci", "computeub", - "freeze", "getmode", "hklscan", "hscan", "kscan", "latticecal", - "loadcrystal", "lscan", "newcrystal", "or0", "or1", "orswap", - "pa", "savecrystal", "setaz", "setlat", "setmode", "setor0", - "setor1", "setorn", "th2th", "ubr", "wh"] - - - # TODO: use taurus instead of PyTango API e.g. read_attribute, # write_attribute. This module is full of PyTango centric calls. @@ -43,6 +13,11 @@ # using getDevice. However this getter seems to accept only the elements names # and not the full names. +__all__ = ["addreflexion", "affine", "br", "ca", "caa", "ci", "computeub", + "freeze", "getmode", "hklscan", "hscan", "kscan", "latticecal", + "loadcrystal", "lscan", "newcrystal", "or0", "or1", "orswap", + "pa", "savecrystal", "setaz", "setlat", "setmode", "setor0", + "setor1", "setorn", "th2th", "ubr", "wh"] import time import math @@ -110,11 +85,17 @@ def prepare(self): self.angle_names.append("delta") if self.nb_motors == 4: - self.labelmotor = {'Omega': "omega", - 'Chi': "chi", 'Phi': "phi", 'Tth': "tth"} + self.labelmotor = {'Omega': self.angle_names[0], 'Chi': self.angle_names[1], + 'Phi': self.angle_names[2], 'Tth': self.angle_names[3]} elif self.nb_motors == 6: - self.labelmotor = {'Mu': "mu", 'Theta': "omega", 'Chi': "chi", - 'Phi': "phi", 'Gamma': "gamma", 'Delta': "delta"} + self.labelmotor = {'Mu': self.angle_names[0], 'Theta': self.angle_names[1], + 'Chi': self.angle_names[2], 'Phi': self.angle_names[3], + 'Gamma': self.angle_names[4], 'Delta': self.angle_names[5]} + elif self.nb_motors == 7: + self.labelmotor = {'Omega_t': self.angle_names[0], 'Mu': self.angle_names[1], + 'Omega': self.angle_names[2], 'Chi': self.angle_names[3], + 'Phi': self.angle_names[4], 'Gamma': self.angle_names[5], + 'Delta': self.angle_names[6]} prop = self.diffrac.get_property(['DiffractometerType']) for v in prop['DiffractometerType']: @@ -363,6 +344,18 @@ def run(self, H, K, L, Trajectory): str_pos[self.labelmotor["Omega"]], str_pos[self.labelmotor["Chi"]], str_pos[self.labelmotor["Phi"]])) + elif self.nb_motors == 7: + self.output("%10s %11s %12s %11s %10s %11s %11s" % + ("Omega_t", "Mu", "Omega", "Chi", + "Phi", "Gamma", "Delta")) + self.output("%10s %11s %12s %11s %10s %11s %11s" % + (str_pos[self.labelmotor["Omega_t"]], + str_pos[self.labelmotor["Mu"]], + str_pos[self.labelmotor["Omega"]], + str_pos[self.labelmotor["Chi"]], + str_pos[self.labelmotor["Phui"]], + str_pos[self.labelmotor["Gamma"]], + str_pos[self.labelmotor["Delta"]])) @@ -601,7 +594,7 @@ def run(self): self.output("%s %7.5f" % ("Wavelength = ", self.diffrac.WaveLength)) self.output("") - + if self.nb_motors == 6: str_pos1 = "%7.5f" % self.getDevice( self.angle_device_names[self.labelmotor["Delta"]]).Position @@ -616,7 +609,7 @@ def run(self): str_pos6 = "%7.5f" % self.getDevice( self.angle_device_names[self.labelmotor["Gamma"]]).Position self.output("%10s %11s %12s %11s %10s %11s" % - ("Delta", "Theta", "Chi", "Phi", "Mu", "Gamma")) + (self.labelmotor["Delta"], self.labelmotor["Theta"], self.labelmotor["Chi"], self.labelmotor["Phi"], self.labelmotor["Mu"], self.labelmotor["Gamma"])) self.output("%10s %11s %12s %11s %10s %11s" % (str_pos1, str_pos2, str_pos3, str_pos4, str_pos5, str_pos6)) @@ -630,9 +623,29 @@ def run(self): str_pos4 = "%7.5f" % self.getDevice( self.angle_device_names[self.labelmotor["Phi"]]).Position self.output("%10s %11s %12s %11s" % - ("Tth", "Omega", "Chi", "Phi")) + (self.labelmotor["Tth"], self.labelmotor["Omega"], self.labelmotor["Chi"], self.labelmotor["Phi"])) self.output("%10s %11s %12s %11s" % (str_pos1, str_pos2, str_pos3, str_pos4)) + elif self.nb_motors == 7: + str_pos1 = "%7.5f" % self.getDevice( + self.angle_device_names[self.labelmotor["Omega_t"]]).Position + str_pos2 = "%7.5f" % self.getDevice( + self.angle_device_names[self.labelmotor["Mu"]]).Position + str_pos3 = "%7.5f" % self.getDevice( + self.angle_device_names[self.labelmotor["Omega"]]).Position + str_pos4 = "%7.5f" % self.getDevice( + self.angle_device_names[self.labelmotor["Chi"]]).Position + str_pos5 = "%7.5f" % self.getDevice( + self.angle_device_names[self.labelmotor["Phi"]]).Position + str_pos6 = "%7.5f" % self.getDevice( + self.angle_device_names[self.labelmotor["Gamma"]]).Position + str_pos7 = "%7.5f" % self.getDevice( + self.angle_device_names[self.labelmotor["Delta"]]).Position + self.output("%10s %11s %12s %11s %10s %11s %11s" % + (self.labelmotor["Omega_t"], self.labelmotor["Mu"], self.labelmotor["Omega"], self.labelmotor["Chi"], self.labelmotor["Phi"], self.labelmotor["Gamma"], self.labelmotor["Delta"])) + self.output("%10s %11s %12s %11s %10s %11s %11s" % + (str_pos1, str_pos2, str_pos3, str_pos4, str_pos5, + str_pos6, str_pos7)) self.setEnv('Q', [self.h_device.position, self.k_device.position, self.l_device.position, self.diffrac.WaveLength]) From 3d50f807e233d7366ddda857f6107dedc3880d38 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 31 Aug 2018 09:05:37 +0200 Subject: [PATCH 047/652] Adding diffractometer types --- .../HklPseudoMotorController.py | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py b/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py index 738671660d..785f325b38 100644 --- a/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py +++ b/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py @@ -452,7 +452,7 @@ def CalcAllPhysical(self, pseudo_pos, curr_physical_pos): values = None if engine_name == "hkl": values = [pseudo_pos[0], pseudo_pos[1], pseudo_pos[2]] - elif self.nb_ph_axes == 4: # noqa "E4CV", "E4CH", "SOLEIL MARS": hkl(3), psi(1), q(1); "K4CV": hkl(3), psi(1), q(1), eulerians(3); "SOLEIL SIXS MED1+2": hkl(3), q2(2), qper_qpar(2) + elif self.nb_ph_axes == 4: # noqa "E4CV", "E4CH", "SOLEIL MARS": hkl(3), psi(1), q(1); "K4CV": hkl(3), psi(1), q(1), eulerians(3); "SOLEIL SIXS MED1+2": hkl(3), q2(2), qper_qpar(2); "PETRA3 P23 4C": hkl(3), q2(2), qper_qpar(2), tth2(2), petra3_p23_4c_incidence(1), _petra3_p23_4c_emergence(1) if engine_name == "psi": values = [pseudo_pos[3]] elif engine_name == "q": @@ -463,7 +463,13 @@ def CalcAllPhysical(self, pseudo_pos, curr_physical_pos): values = [pseudo_pos[3], pseudo_pos[4]] elif engine_name == "qper_qpar": values = [pseudo_pos[5], pseudo_pos[6]] - elif self.nb_ph_axes == 6: # noqa "E6C", "SOLEIL SIXS MED2+2": hkl(3), psi(1), q2(2), qper_qpar(2); "K6C": hkl(3), psi(1), q2(2), qper_qpar(2), eulerians(3); "PETRA3 P09 EH2": hkl(3) + elif engine_name == "tth2": + values = [pseudo_pos[7], pseudo_pos[8]] + elif engine_name == "petra3_p23_4c_incidence": + values = [pseudo_pos[9]] + elif engine_name == "petra3_p23_4c_emergence": + values = [pseudo_pos[10]] + elif self.nb_ph_axes == 6: # noqa "E6C", "SOLEIL SIXS MED2+2": hkl(3), psi(1), q2(2), qper_qpar(2); "K6C": hkl(3), psi(1), q2(2), qper_qpar(2), eulerians(3); "PETRA3 P09 EH2": hkl(3), "PETRA3 P23 6C": hkl(3), psi(1), q2(2), qper_qpar(2), tth2(2), petra3_p23_6c_incidence(1), _petra3_p23_6c_emergence(1) if engine_name == "psi": values = [pseudo_pos[3]] elif engine_name == "q2": @@ -472,6 +478,12 @@ def CalcAllPhysical(self, pseudo_pos, curr_physical_pos): values = [pseudo_pos[6], pseudo_pos[7]] elif engine_name == "eulerians": values = [pseudo_pos[8], pseudo_pos[9], pseudo_pos[10]] + elif engine_name == "tth2": + values = [pseudo_pos[8], pseudo_pos[9]] + elif engine_name == "petra3_p23_6c_incidence": + values = [pseudo_pos[10]] + elif engine_name == "petra3_p23_6c_emergence": + values = [pseudo_pos[11]] # getWavelength updates wavelength in the library in case automatic # energy update is set. Needed before computing trajectories. @@ -1396,6 +1408,21 @@ def setComputeHKL(self, value): # 6C Diffractometers #################### +class Diffrac6Cp23(DiffracBasis): # DiffractometerType: "PETRA3 P23 6C" + + """ The PseudoMotor controller for the diffractometer""" + + pseudo_motor_roles = "h", "k", "l", "psi", "q", "alpha", "tth2", "alpha_tth2", "incidence", "emergence" + motor_roles = "omega_t", "mu", "omega", "chi", "phi", "gamma", "delta" + + def __init__(self, inst, props, *args, **kwargs): + """ Do the default init plus the specific diffractometer + staff. + @param properties of the controller + """ + + DiffracBasis.__init__(self, inst, props, *args, **kwargs) + class Diffrac6C(DiffracBasis): # DiffractometerType: "PETRA3 P09 EH2" """ The PseudoMotor controller for the diffractometer""" @@ -1429,6 +1456,20 @@ def __init__(self, inst, props, *args, **kwargs): # 4C Diffractometers #################### +class Diffrac4Cp23(DiffracBasis): # DiffractometerType: "PETRA3 P23 4C" + + """ The PseudoMotor controller for the diffractometer""" + + pseudo_motor_roles = "h", "k", "l", "q", "alpha", "qper", "qpar", "tth2", "alpha_tth2", "incidence", "emergence" + motor_roles = "omega_t", "mu", "gamma", "delta" + + def __init__(self, inst, props, *args, **kwargs): + """ Do the default init plus the specific diffractometer + staff. + @param properties of the controller + """ + + DiffracBasis.__init__(self, inst, props, *args, **kwargs) class DiffracE4C(DiffracBasis): From 6cccd93a624fdcb696abdb7c6876cfecfac49446 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 31 Aug 2018 11:40:45 +0200 Subject: [PATCH 048/652] pep8 --- .../pool/poolcontrollers/HklPseudoMotorController.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py b/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py index 785f325b38..9de372e631 100644 --- a/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py +++ b/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py @@ -1412,7 +1412,8 @@ class Diffrac6Cp23(DiffracBasis): # DiffractometerType: "PETRA3 P23 6C" """ The PseudoMotor controller for the diffractometer""" - pseudo_motor_roles = "h", "k", "l", "psi", "q", "alpha", "tth2", "alpha_tth2", "incidence", "emergence" + pseudo_motor_roles = "h", "k", "l", "psi", "q", "alpha", "tth2", + "alpha_tth2", "incidence", "emergence" motor_roles = "omega_t", "mu", "omega", "chi", "phi", "gamma", "delta" def __init__(self, inst, props, *args, **kwargs): @@ -1456,11 +1457,13 @@ def __init__(self, inst, props, *args, **kwargs): # 4C Diffractometers #################### + class Diffrac4Cp23(DiffracBasis): # DiffractometerType: "PETRA3 P23 4C" """ The PseudoMotor controller for the diffractometer""" - pseudo_motor_roles = "h", "k", "l", "q", "alpha", "qper", "qpar", "tth2", "alpha_tth2", "incidence", "emergence" + pseudo_motor_roles = "h", "k", "l", "q", "alpha", "qper", "qpar", + "tth2", "alpha_tth2", "incidence", "emergence" motor_roles = "omega_t", "mu", "gamma", "delta" def __init__(self, inst, props, *args, **kwargs): From 58c421d777ae3b441f1fadea9b38cef7c44f0f1a Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 31 Aug 2018 13:16:48 +0200 Subject: [PATCH 049/652] pep8 errors --- src/sardana/macroserver/macros/hkl.py | 31 ++++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py index 5d391fc8e7..ed79a494ee 100644 --- a/src/sardana/macroserver/macros/hkl.py +++ b/src/sardana/macroserver/macros/hkl.py @@ -85,16 +85,24 @@ def prepare(self): self.angle_names.append("delta") if self.nb_motors == 4: - self.labelmotor = {'Omega': self.angle_names[0], 'Chi': self.angle_names[1], - 'Phi': self.angle_names[2], 'Tth': self.angle_names[3]} + self.labelmotor = {'Omega': self.angle_names[0], + 'Chi': self.angle_names[1], + 'Phi': self.angle_names[2], + 'Tth': self.angle_names[3]} elif self.nb_motors == 6: - self.labelmotor = {'Mu': self.angle_names[0], 'Theta': self.angle_names[1], - 'Chi': self.angle_names[2], 'Phi': self.angle_names[3], - 'Gamma': self.angle_names[4], 'Delta': self.angle_names[5]} + self.labelmotor = {'Mu': self.angle_names[0], + 'Theta': self.angle_names[1], + 'Chi': self.angle_names[2], + 'Phi': self.angle_names[3], + 'Gamma': self.angle_names[4], + 'Delta': self.angle_names[5]} elif self.nb_motors == 7: - self.labelmotor = {'Omega_t': self.angle_names[0], 'Mu': self.angle_names[1], - 'Omega': self.angle_names[2], 'Chi': self.angle_names[3], - 'Phi': self.angle_names[4], 'Gamma': self.angle_names[5], + self.labelmotor = {'Omega_t': self.angle_names[0], + 'Mu': self.angle_names[1], + 'Omega': self.angle_names[2], + 'Chi': self.angle_names[3], + 'Phi': self.angle_names[4], + 'Gamma': self.angle_names[5], 'Delta': self.angle_names[6]} prop = self.diffrac.get_property(['DiffractometerType']) @@ -609,7 +617,9 @@ def run(self): str_pos6 = "%7.5f" % self.getDevice( self.angle_device_names[self.labelmotor["Gamma"]]).Position self.output("%10s %11s %12s %11s %10s %11s" % - (self.labelmotor["Delta"], self.labelmotor["Theta"], self.labelmotor["Chi"], self.labelmotor["Phi"], self.labelmotor["Mu"], self.labelmotor["Gamma"])) + (self.labelmotor["Delta"], self.labelmotor["Theta"], + self.labelmotor["Chi"], self.labelmotor["Phi"], + self.labelmotor["Mu"], self.labelmotor["Gamma"])) self.output("%10s %11s %12s %11s %10s %11s" % (str_pos1, str_pos2, str_pos3, str_pos4, str_pos5, str_pos6)) @@ -623,7 +633,8 @@ def run(self): str_pos4 = "%7.5f" % self.getDevice( self.angle_device_names[self.labelmotor["Phi"]]).Position self.output("%10s %11s %12s %11s" % - (self.labelmotor["Tth"], self.labelmotor["Omega"], self.labelmotor["Chi"], self.labelmotor["Phi"])) + (self.labelmotor["Tth"], self.labelmotor["Omega"], + self.labelmotor["Chi"], self.labelmotor["Phi"])) self.output("%10s %11s %12s %11s" % (str_pos1, str_pos2, str_pos3, str_pos4)) elif self.nb_motors == 7: From 7c5825eb79e04a963ec12890d4e37aa3969d5a3b Mon Sep 17 00:00:00 2001 From: reszelaz Date: Mon, 10 Sep 2018 11:59:22 +0200 Subject: [PATCH 050/652] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bbed99897..dd8ece617d 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This file follows the formats and conventions from [keepachangelog.com] ## [Unreleased] +### Added +- Support to "PETRA3 P23 6C" and "PETRA3 P23 4C" diffractometers by means +of new controller classes (#923) + ## [2.5.0] 2018-08-10 ### Added From 277aeee8b2d7c7d472ebf5b017a8b0c7a786b6f0 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 10 Sep 2018 12:22:06 +0200 Subject: [PATCH 051/652] Fix flake8 --- src/sardana/macroserver/macros/hkl.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py index ed79a494ee..9069e8ca84 100644 --- a/src/sardana/macroserver/macros/hkl.py +++ b/src/sardana/macroserver/macros/hkl.py @@ -602,7 +602,7 @@ def run(self): self.output("%s %7.5f" % ("Wavelength = ", self.diffrac.WaveLength)) self.output("") - + if self.nb_motors == 6: str_pos1 = "%7.5f" % self.getDevice( self.angle_device_names[self.labelmotor["Delta"]]).Position @@ -653,7 +653,10 @@ def run(self): str_pos7 = "%7.5f" % self.getDevice( self.angle_device_names[self.labelmotor["Delta"]]).Position self.output("%10s %11s %12s %11s %10s %11s %11s" % - (self.labelmotor["Omega_t"], self.labelmotor["Mu"], self.labelmotor["Omega"], self.labelmotor["Chi"], self.labelmotor["Phi"], self.labelmotor["Gamma"], self.labelmotor["Delta"])) + (self.labelmotor["Omega_t"], self.labelmotor["Mu"], + self.labelmotor["Omega"], self.labelmotor["Chi"], + self.labelmotor["Phi"], self.labelmotor["Gamma"], + self.labelmotor["Delta"])) self.output("%10s %11s %12s %11s %10s %11s %11s" % (str_pos1, str_pos2, str_pos3, str_pos4, str_pos5, str_pos6, str_pos7)) From 628e3137ba94c26846e146b8f64ec392a8dbcf16 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 10 Sep 2018 12:23:12 +0200 Subject: [PATCH 052/652] Reintroduce licence header --- src/sardana/macroserver/macros/hkl.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py index 9069e8ca84..81e66f2d32 100644 --- a/src/sardana/macroserver/macros/hkl.py +++ b/src/sardana/macroserver/macros/hkl.py @@ -1,3 +1,25 @@ +############################################################################## +## +# This file is part of Sardana +## +# http://www.sardana-controls.org/ +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Sardana 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. +## +# Sardana 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 Sardana. If not, see . +## +############################################################################## """ Macro library containning diffractometer related macros for the macros From bf8d5b16728e83e0a2a63b54e7df9e40a452a778 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 10 Sep 2018 12:55:02 +0200 Subject: [PATCH 053/652] Fix typo in addreflection --- src/sardana/macroserver/macros/hkl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py index 81e66f2d32..b7ea6b43f2 100644 --- a/src/sardana/macroserver/macros/hkl.py +++ b/src/sardana/macroserver/macros/hkl.py @@ -35,7 +35,7 @@ # using getDevice. However this getter seems to accept only the elements names # and not the full names. -__all__ = ["addreflexion", "affine", "br", "ca", "caa", "ci", "computeub", +__all__ = ["addreflection", "affine", "br", "ca", "caa", "ci", "computeub", "freeze", "getmode", "hklscan", "hscan", "kscan", "latticecal", "loadcrystal", "lscan", "newcrystal", "or0", "or1", "orswap", "pa", "savecrystal", "setaz", "setlat", "setmode", "setor0", From b346beb33244212f63383886ff40d9da2336a032 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Mon, 10 Sep 2018 14:20:38 +0200 Subject: [PATCH 054/652] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd8ece617d..ffd5bf9850 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ This file follows the formats and conventions from [keepachangelog.com] ### Added - Support to "PETRA3 P23 6C" and "PETRA3 P23 4C" diffractometers by means -of new controller classes (#923) +of new controller classes and necessary adaptation to macros (#923, #921) ## [2.5.0] 2018-08-10 From e46163260a3be6501366002b7388004f38ced014 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 10 Sep 2018 18:15:34 +0200 Subject: [PATCH 055/652] Move pre-scan and post-scan hooks out of scan_loop pre-scan and post-scan hooks are executed within the scan_loop. Before the scan loop, for example, are started the scan recorders making them to start the scan entry. It makes more sense to not start them until the pre-scan hooks are executed - they may want discard the scan or simply may not want to mix the scan header output with the pre-scan hooks output. This solution allows to avoid the code duplication in all the scan specific implementation. --- src/sardana/macroserver/scan/gscan.py | 42 ++++++--------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index 83862aea0a..600c803db6 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -944,6 +944,10 @@ def scan(self): pass def step_scan(self): + macro = self.macro + if hasattr(macro, 'getHooks'): + for hook in macro.getHooks('pre-scan'): + hook() self.start() try: for i in self.scan_loop(): @@ -960,7 +964,11 @@ def step_scan(self): self._env["endstatus"] = endstatus self.end() self.do_restore() - if endstatus != ScanEndStatus.Normal: + if endstatus == ScanEndStatus.Normal: + if hasattr(macro, 'getHooks'): + for hook in macro.getHooks('post-scan'): + hook() + else: raise def scan_loop(self): @@ -1004,10 +1012,6 @@ def scan_loop(self): else: yield 0.0 - if hasattr(macro, 'getHooks'): - for hook in macro.getHooks('pre-scan'): - hook() - self._sum_motion_time = 0 self._sum_acq_time = 0 @@ -1019,10 +1023,6 @@ def scan_loop(self): if scream: yield ((i + 1) / nr_points) * 100.0 - if hasattr(macro, 'getHooks'): - for hook in macro.getHooks('post-scan'): - hook() - if not scream: yield 100.0 @@ -1755,10 +1755,6 @@ def scan_loop(self): point_nb, step = -1, None # data = self.data - if hasattr(macro, 'getHooks'): - for hook in macro.getHooks('pre-scan'): - hook() - # start move & acquisition as close as possible # from this point on synchronization becomes critical manager.add_job(self.go_through_waypoints) @@ -1872,10 +1868,6 @@ def scan_loop(self): self.motion_end_event.wait() - if hasattr(macro, 'getHooks'): - for hook in macro.getHooks('post-scan'): - hook() - env = self._env env['acqtime'] = sum_integ_time env['delaytime'] = sum_delay @@ -2452,16 +2444,8 @@ def scan_loop(self): # point_nb, step = -1, None # data = self.data - if hasattr(macro, 'getHooks'): - for hook in macro.getHooks('pre-scan'): - hook() - self.go_through_waypoints() - if hasattr(macro, 'getHooks'): - for hook in macro.getHooks('post-scan'): - hook() - env = self._env env['acqtime'] = sum_integ_time env['delaytime'] = sum_delay @@ -2668,10 +2652,6 @@ def scan_loop(self): msg = "Relative timestamp (dt) column contains theoretical values" self.macro.warning(msg) - if hasattr(macro, 'getHooks'): - for hook in macro.getHooks('pre-scan'): - hook() - if hasattr(macro, 'getHooks'): for hook in macro.getHooks('pre-acq'): hook() @@ -2689,10 +2669,6 @@ def scan_loop(self): for hook in macro.getHooks('post-acq'): hook() - if hasattr(macro, 'getHooks'): - for hook in macro.getHooks('post-scan'): - hook() - def _fill_missing_records(self): # fill record list with dummy records for the final padding nr_points = self.macro.nr_points From 87265a4c1ed584222bda81d86668c155352728be Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 12 Sep 2018 11:07:33 +0200 Subject: [PATCH 056/652] Update CHANGELOG.md --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffd5bf9850..0f1f11ea89 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,11 @@ This file follows the formats and conventions from [keepachangelog.com] ### Added - Support to "PETRA3 P23 6C" and "PETRA3 P23 4C" diffractometers by means -of new controller classes and necessary adaptation to macros (#923, #921) + of new controller classes and necessary adaptation to macros (#923, #921) + +### Changed +- Move pre-scan and post-scan hooks out of `scan_loop` method (#920, #922, + #933) ## [2.5.0] 2018-08-10 From 1b5b54f7145be35722eebc5dae1c9498d65e6000 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 12 Jul 2018 16:47:40 +0200 Subject: [PATCH 057/652] Give more visibility to Accessing macro data --- doc/source/devel/howto_macros/macros_general.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 963bb83bd1..3fb1676fb1 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -669,7 +669,7 @@ parameters with different *flavors*: Accessing macro data -~~~~~~~~~~~~~~~~~~~~ +-------------------- Sometimes it is desirable to access data generated by the macro we just called. For these cases, the Macro :term:`API` provides a pair of low level methods From 154677005470088f36a78633790ec9047514f225 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 12 Jul 2018 17:29:18 +0200 Subject: [PATCH 058/652] Add Adding hooks support --- .../devel/howto_macros/macros_general.rst | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 3fb1676fb1..568bfd9b5b 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -825,6 +825,34 @@ of user's interruption you must override the withing the :meth:`~sardana.macroserver.macro.Macro.on_stop` or :meth:`~sardana.macroserver.macro.Macro.on_abort`. +Adding hooks support +-------------------- + +Your macros may accept to :ref:`attach an arbitrary ` +code, a simple Python callable or even another macro, that will be executed +at given places. In Sardana this code are called *hooks*, and the places are +called *hook places*. + +In order to allow attaching hooks to your macro you must :ref:`write you +macro as a class ` while at the same time +inheriting from the :class:`~sardana.macroserver.macro.Hookable` class. + +The hook places can be defined in the ``hints`` class member dictionary with +the ``allowedHooks`` key and a tuple of strings with the hook places +identifiers:: + + class loop(Macro, Hookable): + """A macro that accepts and executes hooks.""" + + hints = {"allowsHooks": ("hook-place", "another-hook-place")} + + def run(self): + for hook in self.getHooks("hook-place"): + hook() + self.info("In between hook places") + for hook in self.getHooks("another-hook-place"): + hook() + Using external python libraries ------------------------------- From 8ec300a57b9a6d0add5e072f917a60e9da30cb0a Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 12 Jul 2018 17:41:21 +0200 Subject: [PATCH 059/652] Fix some typos --- doc/source/devel/howto_macros/macros_general.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 568bfd9b5b..ed51a9f1fe 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -838,10 +838,10 @@ macro as a class ` while at the same time inheriting from the :class:`~sardana.macroserver.macro.Hookable` class. The hook places can be defined in the ``hints`` class member dictionary with -the ``allowedHooks`` key and a tuple of strings with the hook places +the ``allowsHooks`` key and a tuple of strings with the hook places identifiers:: - class loop(Macro, Hookable): + class hookable_macro(Macro, Hookable): """A macro that accepts and executes hooks.""" hints = {"allowsHooks": ("hook-place", "another-hook-place")} From 8762e6d0293e8f3c961cf85078e5f23ed78c1449 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Sep 2018 12:40:15 +0200 Subject: [PATCH 060/652] Document how to attach hooks programmatically --- .../devel/howto_macros/macros_general.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index ed51a9f1fe..4f268fb17d 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -853,6 +853,25 @@ identifiers:: for hook in self.getHooks("another-hook-place"): hook() +Hooks can be programmatically attached to a macro before its execution either +using the :attr:`~sardana.macroserver.macro.Hookable.hooks` property or +using the :meth:`~sardana.macroserver.macro.Hookable.appendHook` method:: + + def hook_function(): + pass + + class wrapping_macro(Macro): + """A wrapping macro that attaches hooks to a hookable macro + and executes it.""" + + def run(self): + hookable_macro, _ = self.createMacro("hookable_macro") + hook_macro = ExecMacroHook(self, "mv", [["mot01", 1]]) + hookable_macro.hooks = [(hook_macro, ["hook-place"])] + hookable_macro.appendHook((hook_function, ["another-hook-place"])) + self.runMacro(hookable_macro) + + Using external python libraries ------------------------------- From 1fa32b507f2674d48dcf377335f7c25f370f3a30 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Sep 2018 13:00:53 +0200 Subject: [PATCH 061/652] Correct hook references --- doc/source/devel/howto_macros/macros_general.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 4f268fb17d..d4a9383335 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -778,7 +778,7 @@ prepare HelloWorld to run only after year 1989: def run(self): print "Hello, World!" -.. _sardana-macro-using-external-libraries: +.. _sardana-macro-handling-macro-stop-and-abort: Handling macro stop and abort ----------------------------- @@ -825,6 +825,8 @@ of user's interruption you must override the withing the :meth:`~sardana.macroserver.macro.Macro.on_stop` or :meth:`~sardana.macroserver.macro.Macro.on_abort`. +.. _sardana-macro-adding-hooks-support: + Adding hooks support -------------------- @@ -872,6 +874,8 @@ using the :meth:`~sardana.macroserver.macro.Hookable.appendHook` method:: self.runMacro(hookable_macro) +.. _sardana-macro-using-external-libraries: + Using external python libraries ------------------------------- From b78e16a1d9c5e5c4177a5ac62967f77a1436e740 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Sep 2018 13:01:16 +0200 Subject: [PATCH 062/652] Add link to programmatic hooks --- doc/source/users/macro_hooks.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/source/users/macro_hooks.rst b/doc/source/users/macro_hooks.rst index 6a5616905f..717840a3a5 100644 --- a/doc/source/users/macro_hooks.rst +++ b/doc/source/users/macro_hooks.rst @@ -11,16 +11,18 @@ Macro Hooks =========== A hook is an extra code that can be run at certain points of a macro execution. -These points are predefined for each hookable macro and passed via a "hints" mechanism. -The hint tells the macro how and when to run the attached hook. -Hooks allow the customization of already existing macros and can be added using -three different ways: +These points, called *hook places* are predefined for each *hookable* macro. +The hook place tells the macro how and when to run the attached hook. +Hooks allow the customization of already existing macros and can be added +using three different ways: -- General Hooks +- :ref:`General Hooks ` - :ref:`Sequencer Hooks ` -- :ref:`Programmatic Hooks ` +- :ref:`Programmatic Hooks ` All available macros can be used as a hook. + +.. _sardana-macros-hooks-general: General Hooks ------------- From 0c03e3a767ce0de2e28bae47690ffb7dca0f6da0 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Sep 2018 13:04:31 +0200 Subject: [PATCH 063/652] Minor corrections to general hooks --- doc/source/users/macro_hooks.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/source/users/macro_hooks.rst b/doc/source/users/macro_hooks.rst index 717840a3a5..b3f1969204 100644 --- a/doc/source/users/macro_hooks.rst +++ b/doc/source/users/macro_hooks.rst @@ -29,14 +29,16 @@ General Hooks The general hooks were implemented in Sardana after the programmatic hooks. The motivation for this implementation was to allow the customization -of the scan macros without having to redefine them. -The general hooks apply to all hookable macros and allow the definition -of new hints. -They can be controlled using dedicated macros: :class:`~sardana.macroserver.macros.env.lsgh`, -:class:`~sardana.macroserver.macros.env.defgh` and :class:`~sardana.macroserver.macros.env.udefgh`. -For each hook position, hint, several hooks can be run, they will be run in the -order they were added. The same hook can be run several times in the same position -if it's added several times. +of the scan macros without having to redefine them. The general hooks apply +to all hookable macros. + +They can be controlled using dedicated macros: +:class:`~sardana.macroserver.macros.env.lsgh`, +:class:`~sardana.macroserver.macros.env.defgh` and +:class:`~sardana.macroserver.macros.env.udefgh`. +For each hook place, several hooks can be attached, they will be run in the +order they were added. The same hook can be run several times in the same +place if it was added several times. Examples: From a5d54d47cf5d706f293ae4f3c878aace442f8db8 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Sep 2018 16:21:53 +0200 Subject: [PATCH 064/652] Do not fill missing records if timescan is stopped Add a check point in order to avoid filling missing records when timescan is aborted by the user. --- src/sardana/macroserver/scan/gscan.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index 600c803db6..a61da2bee4 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -2662,6 +2662,7 @@ def scan_loop(self): self.debug("Waiting for value buffer events to be processed") self.wait_value_buffer() self.join_thread_pool() + self.macro.checkPoint() self._fill_missing_records() yield 100 From 48833fd4638c05761f3e09afd11d1b1d75038845 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Sep 2018 17:14:53 +0200 Subject: [PATCH 065/652] Add aNscanct class --- src/sardana/macroserver/macros/scan.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sardana/macroserver/macros/scan.py b/src/sardana/macroserver/macros/scan.py index 726e80de1d..da74e47e43 100644 --- a/src/sardana/macroserver/macros/scan.py +++ b/src/sardana/macroserver/macros/scan.py @@ -1415,6 +1415,19 @@ def do_restore(self): self._motion.move(self.originalPositions) +class aNscanct(aNscan): + """N-dimensional continuous scan. This is **not** meant to be called by + the user, but as a generic base to construct ascanct, a2scanct, a3scanct, + ...""" + + hints = {"scan": "aNscanct", + "allowsHooks": ("pre-scan", "pre-configuration", + "post-configuration", "pre-move", + "post-move", "pre-acq", "pre-start", + "post-acq", "pre-cleanup", "post-cleanup", + "post-scan")} + + class ascanct(aNscan, Macro): """Do an absolute continuous scan of the specified motor. ascanct scans one motor, as specified by motor. The motor starts before the From e875f09d2e00000e8ee06bd0df6421768a4168fd Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Sep 2018 17:16:02 +0200 Subject: [PATCH 066/652] Use aNscanct instead of aNscan class in continuous scan macros --- src/sardana/macroserver/macros/scan.py | 38 ++------------------------ 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/src/sardana/macroserver/macros/scan.py b/src/sardana/macroserver/macros/scan.py index da74e47e43..846d89acc7 100644 --- a/src/sardana/macroserver/macros/scan.py +++ b/src/sardana/macroserver/macros/scan.py @@ -1428,21 +1428,13 @@ class aNscanct(aNscan): "post-scan")} -class ascanct(aNscan, Macro): +class ascanct(aNscanct, Macro): """Do an absolute continuous scan of the specified motor. ascanct scans one motor, as specified by motor. The motor starts before the position given by start_pos in order to reach the constant velocity at the start_pos and finishes at the position after the final_pos in order to maintain the constant velocity until the final_pos.""" - hints = {'scan': 'ascanct', 'allowsHooks': ('pre-configuration', - 'post-configuration', - 'pre-start', - 'pre-acq', - 'post-acq', - 'pre-cleanup', - 'post-cleanup')} - param_def = [['motor', Type.Moveable, None, 'Moveable name'], ['start_pos', Type.Float, None, 'Scan start position'], ['final_pos', Type.Float, None, 'Scan final position'], @@ -1457,7 +1449,7 @@ def prepare(self, motor, start_pos, final_pos, nr_interv, latency_time=latency_time, **opts) -class a2scanct(aNscan, Macro): +class a2scanct(aNscanct, Macro): """Two-motor continuous scan. a2scanct scans two motors, as specified by motor1 and motor2. Each motor starts before the position given by its start_pos in order to reach the @@ -1465,14 +1457,6 @@ class a2scanct(aNscan, Macro): its final_pos in order to maintain the constant velocity until its final_pos.""" - hints = {'scan': 'a2scanct', 'allowsHooks': ('pre-configuration', - 'post-configuration', - 'pre-start', - 'pre-acq', - 'post-acq', - 'pre-cleanup', - 'post-cleanup')} - param_def = [ ['motor1', Type.Moveable, None, 'Moveable 1 to move'], ['start_pos1', Type.Float, None, 'Scan start position 1'], @@ -1491,7 +1475,7 @@ def prepare(self, m1, s1, f1, m2, s2, f2, nr_interv, latency_time=latency_time, **opts) -class a3scanct(aNscan, Macro): +class a3scanct(aNscanct, Macro): """Three-motor continuous scan. a2scanct scans three motors, as specified by motor1, motor2 and motor3. Each motor starts before the position given by its start_pos in order to @@ -1499,14 +1483,6 @@ class a3scanct(aNscan, Macro): after its final_pos in order to maintain the constant velocity until its final_pos.""" - hints = {'scan': 'a2scanct', 'allowsHooks': ('pre-configuration', - 'post-configuration', - 'pre-start', - 'pre-acq', - 'post-acq', - 'pre-cleanup', - 'post-cleanup')} - param_def = [ ['motor1', Type.Moveable, None, 'Moveable 1 to move'], ['start_pos1', Type.Float, None, 'Scan start position 1'], @@ -1536,14 +1512,6 @@ class a4scanct(aNscan, Macro): position after its final_pos in order to maintain the constant velocity until its final_pos.""" - hints = {'scan': 'a2scanct', 'allowsHooks': ('pre-configuration', - 'post-configuration', - 'pre-start', - 'pre-acq', - 'post-acq', - 'pre-cleanup', - 'post-cleanup')} - param_def = [ ['motor1', Type.Moveable, None, 'Moveable 1 to move'], ['start_pos1', Type.Float, None, 'Scan start position 1'], From 614f54a5906ec3b2b95070b2c2c83840d533abe2 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Sep 2018 17:16:21 +0200 Subject: [PATCH 067/652] Add dNscanct class --- src/sardana/macroserver/macros/scan.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sardana/macroserver/macros/scan.py b/src/sardana/macroserver/macros/scan.py index 846d89acc7..c5ffa24c8c 100644 --- a/src/sardana/macroserver/macros/scan.py +++ b/src/sardana/macroserver/macros/scan.py @@ -1536,6 +1536,19 @@ def prepare(self, m1, s1, f1, m2, s2, f2, m3, s3, f3, m4, s4, f4, latency_time=latency_time, **opts) +class dNscanct(dNscan): + """N-dimensional continuous scan. This is **not** meant to be called by + the user, but as a generic base to construct ascanct, a2scanct, a3scanct, + ...""" + + hints = {"scan": "dNscanct", + "allowsHooks": ("pre-scan", "pre-configuration", + "post-configuration", "pre-move", + "post-move", "pre-acq", "pre-start", + "post-acq", "pre-cleanup", "post-cleanup", + "post-scan")} + + class dscanct(dNscan, Macro): """Do an a relative continuous motor scan, dscanct scans a motor, as specified by motor1. From 23e9ec8cef3f7af0784b90001e21074dae092097 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Sep 2018 17:17:36 +0200 Subject: [PATCH 068/652] Use dNscanct instead of dNscan in relative continuous scans --- src/sardana/macroserver/macros/scan.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/macroserver/macros/scan.py b/src/sardana/macroserver/macros/scan.py index c5ffa24c8c..3d6b29d093 100644 --- a/src/sardana/macroserver/macros/scan.py +++ b/src/sardana/macroserver/macros/scan.py @@ -1549,7 +1549,7 @@ class dNscanct(dNscan): "post-scan")} -class dscanct(dNscan, Macro): +class dscanct(dNscanct, Macro): """Do an a relative continuous motor scan, dscanct scans a motor, as specified by motor1. The Motor starts before the position given by its start_pos in order to @@ -1571,7 +1571,7 @@ def prepare(self, motor, start_pos, final_pos, nr_interv, latency_time=latency_time, **opts) -class d2scanct(dNscan, Macro): +class d2scanct(dNscanct, Macro): """continuous two-motor scan relative to the starting positions, d2scanct scans three motors, as specified by motor1 and motor2. Each motor starts before the position given by its start_pos in order to @@ -1595,7 +1595,7 @@ def prepare(self, m1, s1, f1, m2, s2, f2, integ_time, slow_down, **opts): mode=ContinuousHwTimeMode, **opts) -class d3scanct(dNscan, Macro): +class d3scanct(dNscanct, Macro): """continuous three-motor scan relative to the starting positions, d3scanct scans three motors, as specified by motor1, motor2 and motor3. Each motor starts before the position given by its start_pos in order to @@ -1623,7 +1623,7 @@ def prepare(self, m1, s1, f1, m2, s2, f2, m3, s3, f3, integ_time, integ_time, mode=ContinuousHwTimeMode, **opts) -class d4scanct(dNscan, Macro): +class d4scanct(dNscanct, Macro): """continuous four-motor scan relative to the starting positions, d4scanct scans three motors, as specified by motor1, motor2, motor3 and motor4. From bdbfb7bd1b4b324d7ca7984f14fbb20d1833b0dd Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Sep 2018 17:17:51 +0200 Subject: [PATCH 069/652] Correct meshct hook places --- src/sardana/macroserver/macros/scan.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sardana/macroserver/macros/scan.py b/src/sardana/macroserver/macros/scan.py index 3d6b29d093..10d04c8b9c 100644 --- a/src/sardana/macroserver/macros/scan.py +++ b/src/sardana/macroserver/macros/scan.py @@ -1666,10 +1666,12 @@ class meshct(Macro, Hookable): first motor scan is nested within the second motor scan. """ - hints = {'scan': 'meshct', 'allowsHooks': ('pre-scan', 'pre-move', - 'post-move', 'pre-acq', - 'post-acq', 'post-step', - 'post-scan')} + hints = {"scan": "meshct", + "allowsHooks": ("pre-scan", "pre-configuration", + "post-configuration", "pre-move", + "post-move", "pre-acq", "pre-start", + "post-acq", "pre-cleanup", "post-cleanup", + "post-scan")} env = ('ActiveMntGrp',) param_def = [ From fccfe2ab9e3acbb3d06af2c5132fd3d9502741ce Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 13 Sep 2018 09:25:53 +0200 Subject: [PATCH 070/652] Small corrections in the docs --- .../devel/howto_macros/macros_general.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 25897c470a..c7131c7167 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -299,8 +299,10 @@ being a composed of four elements: - parameter name - parameter type - parameter default value: - * None means no default value - * :ref:`OptionalParam ` + - ``None`` means no default value + - ``OptionalParam`` means that + :ref:`the parameter value is optional ` + - parameter description Here is a list of the most common allowed parameter types: @@ -328,10 +330,10 @@ all available sardana interfaces (:obj:`~sardana.sardanadefs.Interface`) Optional parameters ~~~~~~~~~~~~~~~~~~~ -A special default value is the *OptionalParam*. It allows to the macro -identify if the user introduces a value or not to take a decision. +A special parameter default value is the ``OptionalParam``. It allows to +execute a macro even the given parameter value is not specified by the user. -So, here is an example how to define and use a optional parameter:: +So, here is an example how to define and use the optional parameter:: from sardana.macroserver.macro import Macro, Type, OptionalParam @@ -347,9 +349,9 @@ So, here is an example how to define and use a optional parameter:: try: if mntgrp is not None: bkp_active_mntgrp = self.getEnv('ActiveMntGrp') - self.setEnv('ActiveMntGrp', mntgrp.name) - self.info('Use "{0}" measurement ' - 'group'.format(self.getEnv('ActiveMntGrp'))) + mntgrp_name = mntgrp.name + self.setEnv('ActiveMntGrp', mntgrp_name) + self.info('Use "{0}" measurement group'.format(mntgrp_name)) self.ct(itime) finally: if bkp_active_mntgrp is not None: From a1542ebfb69da17d0e77c5cdf671271e4f960c24 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 13 Sep 2018 09:46:15 +0200 Subject: [PATCH 071/652] Change comparison of optional param --- src/sardana/macroserver/msparameter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/macroserver/msparameter.py b/src/sardana/macroserver/msparameter.py index a85bdaec1d..3d89eab028 100644 --- a/src/sardana/macroserver/msparameter.py +++ b/src/sardana/macroserver/msparameter.py @@ -424,7 +424,7 @@ def decodeNormal(self, raw_param, param_def): value = param_def['default_value'] if value is None: raise MissingParam("'%s' not specified" % name) - elif isinstance(value, OptionalParamClass): + elif value is OptionalParam: param = None optional_param = True else: From 046c3fdae018ead726ae9c7cc8d970dd7a6a8ba9 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 13 Sep 2018 09:57:56 +0200 Subject: [PATCH 072/652] Rename OptionalParam to Optional --- doc/source/devel/howto_macros/macros_general.rst | 8 ++++---- src/sardana/macroserver/macro.py | 4 ++-- src/sardana/macroserver/msparameter.py | 6 +++--- src/sardana/taurus/core/tango/sardana/macro.py | 4 ++-- .../taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index c7131c7167..ab49a861cc 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -300,7 +300,7 @@ being a composed of four elements: - parameter type - parameter default value: - ``None`` means no default value - - ``OptionalParam`` means that + - ``Optional`` means that :ref:`the parameter value is optional ` - parameter description @@ -330,18 +330,18 @@ all available sardana interfaces (:obj:`~sardana.sardanadefs.Interface`) Optional parameters ~~~~~~~~~~~~~~~~~~~ -A special parameter default value is the ``OptionalParam``. It allows to +A special parameter default value is the ``Optional``. It allows to execute a macro even the given parameter value is not specified by the user. So, here is an example how to define and use the optional parameter:: - from sardana.macroserver.macro import Macro, Type, OptionalParam + from sardana.macroserver.macro import Macro, Type, Optional class count(Macro): param_def = [ ['itime', Type.Float, 1, 'integration time'], - ['mntgrp', Type.MeasurementGroup, OptionalParam, 'MntGrp to use'] + ['mntgrp', Type.MeasurementGroup, Optional, 'MntGrp to use'] ] def run(self, itime, mntgrp): diff --git a/src/sardana/macroserver/macro.py b/src/sardana/macroserver/macro.py index 719b58fc63..2e0e88b025 100644 --- a/src/sardana/macroserver/macro.py +++ b/src/sardana/macroserver/macro.py @@ -32,7 +32,7 @@ __all__ = ["OverloadPrint", "PauseEvent", "Hookable", "ExecMacroHook", "MacroFinder", "Macro", "macro", "iMacro", "imacro", "MacroFunc", "Type", "ParamRepeat", "Table", "List", "ViewOption", - "LibraryError", "OptionalParam"] + "LibraryError", "Optional"] __docformat__ = 'restructuredtext' @@ -56,7 +56,7 @@ from sardana.util.wrap import wraps from sardana.macroserver.msparameter import Type, ParamType, ParamRepeat, \ - OptionalParam + Optional from sardana.macroserver.msexception import StopException, AbortException, \ MacroWrongParameterType, UnknownEnv, UnknownMacro, LibraryError from sardana.macroserver.msoptions import ViewOption diff --git a/src/sardana/macroserver/msparameter.py b/src/sardana/macroserver/msparameter.py index 3d89eab028..0d75e69e1c 100644 --- a/src/sardana/macroserver/msparameter.py +++ b/src/sardana/macroserver/msparameter.py @@ -57,13 +57,13 @@ def __init__(self, obj): self.__setattr__ = self.raise_error def __repr__(self): - return 'OptionalParam' + return 'Optional' def raise_error(*args, **kwargs): raise RuntimeError('can not be accessed') -OptionalParam = OptionalParamClass({'___optional_parameter__': True}) +Optional = OptionalParamClass({'___optional_parameter__': True}) class WrongParam(MacroServerException): @@ -424,7 +424,7 @@ def decodeNormal(self, raw_param, param_def): value = param_def['default_value'] if value is None: raise MissingParam("'%s' not specified" % name) - elif value is OptionalParam: + elif value is Optional: param = None optional_param = True else: diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py index 45356bdabe..48339b48a2 100755 --- a/src/sardana/taurus/core/tango/sardana/macro.py +++ b/src/sardana/taurus/core/tango/sardana/macro.py @@ -41,7 +41,7 @@ from taurus.core.util.user import USER_NAME from taurus.core.util.codecs import CodecFactory -from sardana.macroserver.msparameter import OptionalParam +from sardana.macroserver.msparameter import Optional class MacroRunException(Exception): @@ -552,7 +552,7 @@ def toRun(self): if self.defValue() is None: alert = "Parameter " + self.name() + " is missing.
    " return ([val], alert) - elif self._defValue == OptionalParam: + elif self._defValue == Optional: val = '' else: val = self.defValue() diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index 8d6fbbf872..b2ec9140df 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -47,7 +47,7 @@ from .favouriteseditor import FavouritesMacrosEditor, HistoryMacrosViewer from .common import MacroComboBox, MacroExecutionWindow, standardPlotablesFilter -from sardana.macroserver.msparameter import OptionalParam +from sardana.macroserver.msparameter import Optional class MacroProgressBar(Qt.QProgressBar): @@ -283,7 +283,7 @@ def validateAllExpresion(self, secValidation=False): except IndexError: param_info = macro_params_info[counter-1] # Skip validation in case of optional parameters - if param_info['default_value'] == OptionalParam: + if param_info['default_value'] == Optional: self.model().setData(self.currentIndex, Qt.QVariant(None)) else: From 6cd80f5c76042d1750b134d9c32a599226eb0b14 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 13 Sep 2018 11:31:09 +0200 Subject: [PATCH 073/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f1f11ea89..4bb6abcc9e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This file follows the formats and conventions from [keepachangelog.com] ## [Unreleased] ### Added +- Possibility to define macros with optional parameters. These must be the last + ones in the definition (#285, #876) - Support to "PETRA3 P23 6C" and "PETRA3 P23 4C" diffractometers by means of new controller classes and necessary adaptation to macros (#923, #921) From 613b9ae98cc079187a17ecf79fbc0fbb8f93b365 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 13 Sep 2018 12:40:50 +0200 Subject: [PATCH 074/652] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bb6abcc9e..559799f271 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ This file follows the formats and conventions from [keepachangelog.com] - Support to "PETRA3 P23 6C" and "PETRA3 P23 4C" diffractometers by means of new controller classes and necessary adaptation to macros (#923, #921) +### Fixed +- Avoid final padding in timescan when it was stopped by user (#869, #935) + ### Changed - Move pre-scan and post-scan hooks out of `scan_loop` method (#920, #922, #933) From 9bec42ed9401ed2003dbe1b5a38c9480ed34909a Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 13 Sep 2018 14:21:23 +0200 Subject: [PATCH 075/652] Update how_to_release.md --- doc/how_to_release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/how_to_release.md b/doc/how_to_release.md index cccdbf9064..688b82f718 100644 --- a/doc/how_to_release.md +++ b/doc/how_to_release.md @@ -1,4 +1,4 @@ -# How to release (draft) +# How to This is a guide for sardana release managers: it details the steps for making an official release, including a checklist of stuff that should be manually From 00a7fe6841f225e3ce56e1cd849ef0412bb67eb0 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 17 Sep 2018 10:20:58 +0200 Subject: [PATCH 076/652] Use experimentConfiguration as method names --- src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py | 6 +++--- .../taurus/qt/qtgui/extra_sardana/expdescription.py | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 4d280e6746..455c9ecfeb 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -111,7 +111,7 @@ def _prepare_connections(self): if not self._use_experimet_configuration and \ not self._connections_prepared: self.connect(self.macro_server, Qt.SIGNAL("environmentChanged"), - self._experimentalConfiguration) + self._experimentConfiguration) self.connect(self.macro_server, Qt.SIGNAL("elementsChanged"), self._elementsChanged) self._connections_prepared = True @@ -125,13 +125,13 @@ def _elementsChanged(self): else: obj = mg.getObj() self.connect(obj, Qt.SIGNAL("configurationChanged"), - self._experimentalConfiguration) + self._experimentConfiguration) self._mntgrp_connected.append(name) if len(self._mntgrp_connected) != len_mnt_grps_connected: self.emit(Qt.SIGNAL("experimentConfigurationChanged")) - def _experimentalConfiguration(self, *args): + def _experimentConfiguration(self, *args): self.emit(Qt.SIGNAL("experimentConfigurationChanged")) def getExperimentConfigurationObj(self): diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 502a326142..e606b57c63 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -323,7 +323,8 @@ def _createExpConfChangedDialog(self): self._reloadConf(force=True) @QtCore.pyqtSlot() - def _experimentalConfigurationChanged(self): + def _experimentConfigurationChanged(self): + self._diff = '' try: self._diff = self._getDiff() except Exception: @@ -388,7 +389,7 @@ def setModel(self, model): self.ui.taurusModelTree.setModel(tghost) self.ui.sardanaElementTree.setModel(msname) self.connect(door, Qt.SIGNAL("experimentConfigurationChanged"), - self._experimentalConfigurationChanged) + self._experimentConfigurationChanged) def _reloadConf(self, force=False): if not force and self.isDataChanged(): @@ -681,7 +682,7 @@ def main(): parser.usage = "%prog [options] " parser.add_option('--auto-update', dest='auto_update', action='store_true', - help='Set auto update of experimental configuration') + help='Set auto update of experiment configuration') app = Application(app_name="Exp. Description demo", app_version="1.0", org_domain="Sardana", org_name="Tango community", cmd_line_parser=parser) From 6dd9699bf12ee939f7d8fc710e2abc9cfd295176 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 17 Sep 2018 11:14:21 +0200 Subject: [PATCH 077/652] Add more keys to skips Add plot_axes and PreScanSnapshot as keys with list as values. --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index e606b57c63..efb0867734 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -110,7 +110,7 @@ def find_diff(first, second): KEYNOTFOUNDIN1 = 'KeyNotFoundInRemote' KEYNOTFOUNDIN2 = 'KeyNotFoundInLocal' SKIPKEYS = ['_controller_name'] - SKIPLIST = ['scanfile'] + SKIPLIST = ['scanfile', 'plot_axes', 'prescansnapshot'] DICT_TYPES = [taurus.core.util.containers.CaselessDict, dict] diff = {} sd1 = set(first) From 28c2644156f38e0c3c2b835d984758ce58a4d585 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 17 Sep 2018 11:15:31 +0200 Subject: [PATCH 078/652] Add protections Add protection on the find_diff method to avoid wrong behaviours. --- .../taurus/qt/qtgui/extra_sardana/expdescription.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index efb0867734..adecc8f3ae 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -115,8 +115,8 @@ def find_diff(first, second): diff = {} sd1 = set(first) sd2 = set(second) - # Keys missing in the second dict + # Keys missing in the second dict for key in sd1.difference(sd2): if key in SKIPKEYS: continue @@ -126,18 +126,25 @@ def find_diff(first, second): if key in SKIPKEYS: continue diff[key] = (KEYNOTFOUNDIN1, second[key]) + # Check for differences for key in sd1.intersection(sd2): value1 = first[key] value2 = second[key] if type(value1) in DICT_TYPES: - idiff = find_diff(value1, value2) + try: + idiff = find_diff(value1, value2) + except Exception: + idiff = 'Error on processing' if len(idiff) > 0: diff[key] = idiff elif type(value1) == list and key.lower() not in SKIPLIST: ldiff = [] for v1, v2 in zip(value1, value2): - idiff = find_diff(v1, v2) + try: + idiff = find_diff(v1, v2) + except Exception: + idiff = 'Error on processing' ldiff.append(idiff) if len(ldiff) > 0: diff[key] = ldiff From 8c431791a9b2e48d4e2f476c0b0f48ec0d15874d Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 17 Sep 2018 11:18:05 +0200 Subject: [PATCH 079/652] Show error in case of exception Show the exception error in case of find_diff method fails. --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index adecc8f3ae..63e2578b2d 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -334,8 +334,8 @@ def _experimentConfigurationChanged(self): self._diff = '' try: self._diff = self._getDiff() - except Exception: - return + except Exception as e: + raise RuntimeError('Error on processing! {0}'.format(e)) if len(self._diff) > 0: if self._autoUpdate: From 2647b335ee9e6872f6e56592337a3bf4644b760f Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 18 Sep 2018 11:08:56 +0200 Subject: [PATCH 080/652] Add LICENSE file --- LICENSE | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..85dc2b3f4e --- /dev/null +++ b/LICENSE @@ -0,0 +1,34 @@ +Sardana is Free Software by the CELLS / ALBA Synchrotron, Bellaterra, Spain + +SECTION 1: GENERAL LICENSE FOR SARDANA SOURCE CODE +================================================= + +The files in Sardana, except for the cases described in SECTION 2 +are distributed under 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. +See + +SECTION 2: EXCEPTIONS +===================== + +Some files (e.g., those authored by 3rd parties or the documentation +sources) are distributed under Free Software / documentation licenses +that may differ from the the general one defined in SECTION 1. + +The following is a list of these exceptions: + +2.1: Explicit copyright info in header/metadata: +------------------------------------------------ + +If a file contains an explicit license or other copyright information in +its header or metadata which differs from the one defined in SECTION 1, +such license/copyright info mentioned in the header/metadata prevails. + +2.2: Documentation: +------------------- + +The .py scripts in the doc directory are treated as per SECTION 1, +and the rest of its files are distributed under a Creative Commons +Attribution 3.0 License +See From 467ea063216d3108a9902dffc4809acd7115cd1e Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 18 Sep 2018 11:19:29 +0200 Subject: [PATCH 081/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 559799f271..f2997e0765 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ This file follows the formats and conventions from [keepachangelog.com] ### Fixed - Avoid final padding in timescan when it was stopped by user (#869, #935) +- Hook places advertised by continuous scans so the `allowHooks` hint and the + code are coherent (#936) ### Changed - Move pre-scan and post-scan hooks out of `scan_loop` method (#920, #922, From 1ea2e43ca18e09d18f723319a52bf84072cef981 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 18 Sep 2018 14:40:06 +0200 Subject: [PATCH 082/652] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2997e0765..4533dee2c8 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This file follows the formats and conventions from [keepachangelog.com] ones in the definition (#285, #876) - Support to "PETRA3 P23 6C" and "PETRA3 P23 4C" diffractometers by means of new controller classes and necessary adaptation to macros (#923, #921) +- Top LICENSE file that applies to the whole project (#938) ### Fixed - Avoid final padding in timescan when it was stopped by user (#869, #935) From 686abc6f91ff746b7a3664f25f968e8ca272acdc Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 18 Sep 2018 15:00:32 +0200 Subject: [PATCH 083/652] Rename some internal variables of QMacroServer * _experimentConfiguration -> _experimentConfigurationChanged * environmentChange -> environmentChanged --- src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 455c9ecfeb..aaf22d9a9a 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -111,7 +111,7 @@ def _prepare_connections(self): if not self._use_experimet_configuration and \ not self._connections_prepared: self.connect(self.macro_server, Qt.SIGNAL("environmentChanged"), - self._experimentConfiguration) + self._experimentConfigurationChanged) self.connect(self.macro_server, Qt.SIGNAL("elementsChanged"), self._elementsChanged) self._connections_prepared = True @@ -125,13 +125,13 @@ def _elementsChanged(self): else: obj = mg.getObj() self.connect(obj, Qt.SIGNAL("configurationChanged"), - self._experimentConfiguration) + self._experimentConfigurationChanged) self._mntgrp_connected.append(name) if len(self._mntgrp_connected) != len_mnt_grps_connected: self.emit(Qt.SIGNAL("experimentConfigurationChanged")) - def _experimentConfiguration(self, *args): + def _experimentConfigurationChanged(self, *args): self.emit(Qt.SIGNAL("experimentConfigurationChanged")) def getExperimentConfigurationObj(self): @@ -151,7 +151,7 @@ class QMacroServer(BaseMacroServer, Qt.QObject): elementsUpdated = Qt.pyqtSignal() elementsChanged = Qt.pyqtSignal() macrosUpdated = Qt.pyqtSignal() - environmentChange = Qt.pyqtSignal(list) + environmentChanged = Qt.pyqtSignal(list) except AttributeError: pass From 5cfb41194c8afadbc91f3b88ff654d7c8ac7bb40 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 18 Sep 2018 15:35:37 +0200 Subject: [PATCH 084/652] Change sphinx style in find_diff docstring --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 63e2578b2d..8912b37fd2 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -102,9 +102,9 @@ def find_diff(first, second): """ Return a dict of keys that differ with another config object. If a value is not found in one fo the configs, it will be represented by KEYNOTFOUND. - @param first: Fist configuration to diff. - @param second: Second configuration to diff. - @return diff: Dict of Key => (first.val, second.val) + :param first: Fist configuration to diff. + :param second: Second configuration to diff. + :return: Dict of Key => (first.val, second.val) """ KEYNOTFOUNDIN1 = 'KeyNotFoundInRemote' From fe2b398fc3c08fe9dd234404d529c87e5ee63f2d Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 18 Sep 2018 16:52:57 +0200 Subject: [PATCH 085/652] Force first connection to measurement group configurations --- src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index aaf22d9a9a..65269b47eb 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -114,6 +114,7 @@ def _prepare_connections(self): self._experimentConfigurationChanged) self.connect(self.macro_server, Qt.SIGNAL("elementsChanged"), self._elementsChanged) + self._elementsChanged() self._connections_prepared = True def _elementsChanged(self): From b2fb2a91218faac2eba5d901b3dd62200793430c Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 18 Sep 2018 16:53:25 +0200 Subject: [PATCH 086/652] Refactor _elementsChanged --- .../qt/qtcore/tango/sardana/macroserver.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 65269b47eb..cfcd701036 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -59,7 +59,7 @@ class QDoor(BaseDoor, Qt.QObject): def __init__(self, name, qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) self.call__init__(BaseDoor, name, **kw) - self._mntgrp_connected = [] + self._mntgrps_connected = [] self._use_experimet_configuration = False self._connections_prepared = False @@ -118,18 +118,20 @@ def _prepare_connections(self): self._connections_prepared = True def _elementsChanged(self): - len_mnt_grps_connected = len(self._mntgrp_connected) - elements = self.macro_server.getElementsOfType("MeasurementGroup") - for name, mg in elements.items(): - if name in self._mntgrp_connected: - continue - else: + mntgrps = self.macro_server.getElementsOfType("MeasurementGroup") + # one or more measurement group was deleted + mntgrp_changed = len(self._mntgrps_connected) > len(mntgrps) + new_mntgrp_connected = [] + for name, mg in mntgrps.items(): + if name not in self._mntgrps_connected: + mntgrp_changed = True # this measurement group is new obj = mg.getObj() self.connect(obj, Qt.SIGNAL("configurationChanged"), self._experimentConfigurationChanged) - self._mntgrp_connected.append(name) + new_mntgrp_connected.append(name) + self._mntgrp_connected = new_mntgrp_connected - if len(self._mntgrp_connected) != len_mnt_grps_connected: + if mntgrp_changed: self.emit(Qt.SIGNAL("experimentConfigurationChanged")) def _experimentConfigurationChanged(self, *args): From e08fd9978267194be8b0fe9e1c4ac94cb864e664 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Tue, 18 Sep 2018 17:12:12 +0200 Subject: [PATCH 087/652] ct/uct macro with mntGrp as a Optional Param --- src/sardana/macroserver/macros/standard.py | 45 +++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index 64f793d99d..12d9326f32 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -41,6 +41,8 @@ ViewOption, iMacro, Hookable from sardana.macroserver.msexception import StopException from sardana.macroserver.scan.scandata import Record +from sardana.macroserver.msparameter import Optional + ########################################################################## # # Motion related macros @@ -648,17 +650,25 @@ class ct(Macro, Hookable): env = ('ActiveMntGrp',) hints = {'allowsHooks': ('pre-acq', 'post-acq')} param_def = [ - ['integ_time', Type.Float, 1.0, 'Integration time'] + ['integ_time', Type.Float, 1.0, 'Integration time'], + ['mnt_grp', Type.MeasurementGroup, Optional, 'MntGrp to use'] + ] - def prepare(self, integ_time, **opts): - mnt_grp_name = self.getEnv('ActiveMntGrp') - self.mnt_grp = self.getObj( - mnt_grp_name, type_class=Type.MeasurementGroup) + def prepare(self, integ_time, mnt_grp, **opts): + if mnt_grp is None: + self.mnt_grp_name = self.getEnv('ActiveMntGrp') + self.mnt_grp = self.getObj(self.mnt_grp_name, + type_class=Type.MeasurementGroup) + else: + self.mnt_grp_name = mnt_grp.name + self.mnt_grp = mnt_grp - def run(self, integ_time): + + def run(self, integ_time, mnt_grp): if self.mnt_grp is None: - self.error('ActiveMntGrp is not defined or has invalid value') + self.error('The MntGrp {} is not defined or has invalid ' + 'value'.format(self.mnt_grp_name)) return # integration time has to be accessible from with in the hooks # so declare it also instance attribute @@ -699,16 +709,22 @@ class uct(Macro): env = ('ActiveMntGrp',) param_def = [ - ['integ_time', Type.Float, 1.0, 'Integration time'] + ['integ_time', Type.Float, 1.0, 'Integration time'], + ['mnt_grp', Type.MeasurementGroup, Optional, 'MntGrp to use'] + ] - def prepare(self, integ_time, **opts): + def prepare(self, integ_time, mnt_grp, **opts): self.print_value = False - mnt_grp_name = self.getEnv('ActiveMntGrp') - self.mnt_grp = self.getObj( - mnt_grp_name, type_class=Type.MeasurementGroup) + if mnt_grp is None: + self.mnt_grp_name = self.getEnv('ActiveMntGrp') + self.mnt_grp = self.getObj(self.mnt_grp_name, + type_class=Type.MeasurementGroup) + else: + self.mnt_grp_name = mnt_grp.name + self.mnt_grp = mnt_grp if self.mnt_grp is None: return @@ -726,9 +742,10 @@ def prepare(self, integ_time, **opts): valueObj = channel.getValueObj_() valueObj.subscribeEvent(self.counterChanged, channel) - def run(self, integ_time): + def run(self, integ_time, mnt_grp): if self.mnt_grp is None: - self.error('ActiveMntGrp is not defined or has invalid value') + self.error('The MntGrp {} is not defined or has invalid ' + 'value'.format(self.mnt_grp_name)) return self.print_value = True From bd69df674a1b752f153284d2e6b166002e735319 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Tue, 18 Sep 2018 17:14:36 +0200 Subject: [PATCH 088/652] fix pep8 --- src/sardana/macroserver/macros/standard.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index 12d9326f32..6dd138cfca 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -659,12 +659,11 @@ def prepare(self, integ_time, mnt_grp, **opts): if mnt_grp is None: self.mnt_grp_name = self.getEnv('ActiveMntGrp') self.mnt_grp = self.getObj(self.mnt_grp_name, - type_class=Type.MeasurementGroup) + type_class=Type.MeasurementGroup) else: self.mnt_grp_name = mnt_grp.name self.mnt_grp = mnt_grp - def run(self, integ_time, mnt_grp): if self.mnt_grp is None: self.error('The MntGrp {} is not defined or has invalid ' @@ -721,7 +720,7 @@ def prepare(self, integ_time, mnt_grp, **opts): if mnt_grp is None: self.mnt_grp_name = self.getEnv('ActiveMntGrp') self.mnt_grp = self.getObj(self.mnt_grp_name, - type_class=Type.MeasurementGroup) + type_class=Type.MeasurementGroup) else: self.mnt_grp_name = mnt_grp.name self.mnt_grp = mnt_grp @@ -839,6 +838,7 @@ def run(self, offon, mode): else: self.setEnv('LogMacro', False) + class repeat(Hookable, Macro): """This macro executes as many repetitions of a set of macros as specified by nr parameter. The macros to be repeated can be From a7901930205573689f8250a0e82a8b9da3a25fc2 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 19 Sep 2018 10:37:45 +0200 Subject: [PATCH 089/652] Add shape key to skip --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 8912b37fd2..59f38fc540 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -110,7 +110,7 @@ def find_diff(first, second): KEYNOTFOUNDIN1 = 'KeyNotFoundInRemote' KEYNOTFOUNDIN2 = 'KeyNotFoundInLocal' SKIPKEYS = ['_controller_name'] - SKIPLIST = ['scanfile', 'plot_axes', 'prescansnapshot'] + SKIPLIST = ['scanfile', 'plot_axes', 'prescansnapshot', 'shape'] DICT_TYPES = [taurus.core.util.containers.CaselessDict, dict] diff = {} sd1 = set(first) From 8f98403081bb54cad6d7ecd5d7c57af9e18299fb Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 19 Sep 2018 11:23:42 +0200 Subject: [PATCH 090/652] Add more keys to skip Add more keys than the server can change regardless of the values set by the GUI. Skip these key in the comparison process. --- .../taurus/qt/qtgui/extra_sardana/expdescription.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 59f38fc540..9911a52b94 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -109,8 +109,14 @@ def find_diff(first, second): KEYNOTFOUNDIN1 = 'KeyNotFoundInRemote' KEYNOTFOUNDIN2 = 'KeyNotFoundInLocal' - SKIPKEYS = ['_controller_name'] + + # The GUI can not change these keys. They are changed by the server. + SKIPKEYS = ['_controller_name', 'description', 'timer', 'monitor', 'ndim', + 'source'] + + # These keys can have a list as value. SKIPLIST = ['scanfile', 'plot_axes', 'prescansnapshot', 'shape'] + DICT_TYPES = [taurus.core.util.containers.CaselessDict, dict] diff = {} sd1 = set(first) @@ -129,6 +135,8 @@ def find_diff(first, second): # Check for differences for key in sd1.intersection(sd2): + if key in SKIPKEYS: + continue value1 = first[key] value2 = second[key] if type(value1) in DICT_TYPES: From 3f223383adc701558bb6eae8c169a5cb13492a0b Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 19 Sep 2018 12:07:37 +0200 Subject: [PATCH 091/652] Distinguish error reason and execute stop only once --- src/sardana/taurus/core/tango/sardana/pool.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 539785086f..c0978afed0 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1786,16 +1786,16 @@ def _enableChannels(self, channels, state): def _start(self, *args, **kwargs): try: self.Start() - except Exception as e: - while True: - try: - self.stop() - break - except Exception: - pass - # TODO: Do more friendly user the exception message. + except DevFailed as e: + # TODO: Workaround for CORBA timeout on measurement group start + # remove it whenever sardana-org/sardana#93 gets implemented + if e[-1].reason == "API_DeviceTimedOut": + self.error("start timed out, trying to stop") + self.stop() + self.debug("stopped") raise e + def go(self, *args, **kwargs): start_time = time.time() cfg = self.getConfiguration() From 43eabb45148e4ea0512a146f7b7cb7577bf0b237 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Wed, 19 Sep 2018 12:26:58 +0200 Subject: [PATCH 092/652] Provide requested changes --- src/sardana/macroserver/macros/standard.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index 6dd138cfca..d9463e8570 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -41,7 +41,7 @@ ViewOption, iMacro, Hookable from sardana.macroserver.msexception import StopException from sardana.macroserver.scan.scandata import Record -from sardana.macroserver.msparameter import Optional +from sardana.macroserver.macro import Optional ########################################################################## # @@ -651,7 +651,8 @@ class ct(Macro, Hookable): hints = {'allowsHooks': ('pre-acq', 'post-acq')} param_def = [ ['integ_time', Type.Float, 1.0, 'Integration time'], - ['mnt_grp', Type.MeasurementGroup, Optional, 'MntGrp to use'] + ['mnt_grp', Type.MeasurementGroup, Optional, 'Measurement Group to ' + 'use'] ] @@ -709,7 +710,8 @@ class uct(Macro): param_def = [ ['integ_time', Type.Float, 1.0, 'Integration time'], - ['mnt_grp', Type.MeasurementGroup, Optional, 'MntGrp to use'] + ['mnt_grp', Type.MeasurementGroup, Optional, 'Measurement Group to ' + 'use'] ] From ca4d9a47d17310f49e6a1367dddd75ef3c4d4d33 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 19 Sep 2018 12:32:32 +0200 Subject: [PATCH 093/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4533dee2c8..10679e85ee 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ This file follows the formats and conventions from [keepachangelog.com] ### Added - Possibility to define macros with optional parameters. These must be the last ones in the definition (#285, #876) +- Workaround for API_DeviceTimedOut errors on MeasurementGroup Start. Call Stop + in case this error occured (#764). - Support to "PETRA3 P23 6C" and "PETRA3 P23 4C" diffractometers by means of new controller classes and necessary adaptation to macros (#923, #921) - Top LICENSE file that applies to the whole project (#938) From c9a668c06f575921534fa0e19e93e2a4201f7fbb Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 19 Sep 2018 12:56:47 +0200 Subject: [PATCH 094/652] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10679e85ee..06c0de41a0 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This file follows the formats and conventions from [keepachangelog.com] ones in the definition (#285, #876) - Workaround for API_DeviceTimedOut errors on MeasurementGroup Start. Call Stop in case this error occured (#764). +- Optional measurement group parameter to `ct` and `uct` macros (#940, #473) - Support to "PETRA3 P23 6C" and "PETRA3 P23 4C" diffractometers by means of new controller classes and necessary adaptation to macros (#923, #921) - Top LICENSE file that applies to the whole project (#938) From 3c3a5b9f33f3f79aa00cb3b0e01a8ce204d25208 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 19 Sep 2018 18:03:11 +0200 Subject: [PATCH 095/652] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06c0de41a0..1bff647a00 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ This file follows the formats and conventions from [keepachangelog.com] - Top LICENSE file that applies to the whole project (#938) ### Fixed +- Make `expconf` react on events of environment, measurement groups and their + configurations. An event offers an option to reload the whole experiment + configuration or keep the local changes. `expconf` started with + `--auto-update` option will automatically reload the whole experiment + configuration (#806, #882) - Avoid final padding in timescan when it was stopped by user (#869, #935) - Hook places advertised by continuous scans so the `allowHooks` hint and the code are coherent (#936) From 3d0da0ee67e8aa6c86f55390762232cfed3872be Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 20 Sep 2018 12:34:38 +0200 Subject: [PATCH 096/652] Add protection on parameter info reading Avoid exception raising during the macro typing on the macroexecutor widget. --- .../taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index b2ec9140df..93f1b057a3 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -265,10 +265,15 @@ def validateAllExpresion(self, secValidation=False): # Get the parameters information to check if there are optional # paramters - macro_obj = self.getModelObj() - macro_params_info = macro_obj.getElementInfo(mlist[0]).parameters + ms_obj = self.getModelObj() + macro_obj = ms_obj.getElementInfo(mlist[0]) + macro_params_info = None + if macro_obj is not None: + macro_params_info = macro_obj.parameters while not ix == Qt.QModelIndex(): + if macro_params_info is None: + break try: propValue = mlist[counter] try: From c64faf0c3fd9affa7ccd23f68677c12297c8c78e Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Fri, 21 Sep 2018 08:05:56 +0200 Subject: [PATCH 097/652] MacroButton Stop macro instead direct Aborting --- .../qt/qtgui/extra_macroexecutor/macrobutton.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py index 4654aff27a..c3942c08bb 100755 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py @@ -271,7 +271,7 @@ def _onButtonClicked(self): if self.ui.button.isChecked(): self.runMacro() else: - self.abort() + self.stop() @ProtectTaurusMessageBox(msg='Error while executing the macro.') def runMacro(self): @@ -292,8 +292,13 @@ def runMacro(self): self.ui.button.setChecked(False) raise e + # For backward compatibility def abort(self): - '''abort the macro.''' + self.warning("abort method is deprecated. Use stop instead") + self.stop() + + def stop(self): + '''stop the macro.''' if self.door is None: return self.door.PauseMacro() @@ -301,15 +306,15 @@ def abort(self): # we provide a warning message that does not make the process too slow # It may also be useful and 'ABORT' at TaurusApplication level # (macros+motions+acquisitions) - title = 'Aborting macro' + title = 'Stopping macro' message = 'The following macro is still running:\n\n' message += '%s %s\n\n' % (self.macro_name, ' '.join(self.macro_args)) - message += 'Are you sure you want to abort?\n' + message += 'Are you sure you want to Stop?\n' buttons = Qt.QMessageBox.Ok | Qt.QMessageBox.Cancel ans = Qt.QMessageBox.warning( self, title, message, buttons, Qt.QMessageBox.Ok) if ans == Qt.QMessageBox.Ok: - self.door.abort(synch=True) + self.door.stop(synch=True) else: self.ui.button.setChecked(True) self.door.ResumeMacro() From df6423c8bf1c8d2004c3c785b728c36149459c64 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Fri, 21 Sep 2018 08:21:39 +0200 Subject: [PATCH 098/652] Fix sar_info macro reports a wrong description If a macro module does not have '__doc__' defined 'sar_info' macro reports as description "MACRO in error" that is not the case. Fix #944 --- src/sardana/sardanameta.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sardana/sardanameta.py b/src/sardana/sardanameta.py index 1324bb83d1..1ccda440ed 100644 --- a/src/sardana/sardanameta.py +++ b/src/sardana/sardanameta.py @@ -120,8 +120,9 @@ def __init__(self, **kwargs): name, _ = os.path.splitext(self.file_name) self.meta_classes = {} self.meta_functions = {} - if module is not None and module.__doc__: - self.description = module.__doc__ + if module is not None: + if module.__doc__ is not None: + self.description = module.__doc__ self._code = getsourcelines(module)[0] else: self.description = name + " in error!" From 34f8c58520d596cc394c82ec61437e7e163efc49 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Fri, 21 Sep 2018 08:29:44 +0200 Subject: [PATCH 099/652] relmaclib macro does not respect the MacroPath precedence If there are two modules with the same name relmaclib macro reloads the wrong module and raises an AttributeError. Fix it avoiding to reverse the given list of path in the 'MacroManagermsmacro.reloadMacroLib' method. Fix #927 --- src/sardana/macroserver/msmacromanager.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/sardana/macroserver/msmacromanager.py b/src/sardana/macroserver/msmacromanager.py index 29d88d70a8..2b93c37474 100644 --- a/src/sardana/macroserver/msmacromanager.py +++ b/src/sardana/macroserver/msmacromanager.py @@ -484,13 +484,6 @@ def reloadMacroLib(self, module_name, path=None): means the current MacroPath will be used] :return: the MacroLibrary object for the reloaded macro library""" path = path or self.getMacroPath() - # reverse the path order: - # more priority elements last. This way if there are repeated elements - # they first ones (lower priority) will be overwritten by the last ones - if path: - path = copy.copy(path) - path.reverse() - mod_manager = ModuleManager() m, exc_info = None, None valid, exc_info = mod_manager.isValidModule(module_name, path) From a1104ece5abf1a5abd741861b07c2160398c73c7 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Fri, 21 Sep 2018 11:04:14 +0200 Subject: [PATCH 100/652] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bff647a00..fe5cbb284b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This file follows the formats and conventions from [keepachangelog.com] configuration or keep the local changes. `expconf` started with `--auto-update` option will automatically reload the whole experiment configuration (#806, #882) +- Reload macro library overriding another library (#927, #946) - Avoid final padding in timescan when it was stopped by user (#869, #935) - Hook places advertised by continuous scans so the `allowHooks` hint and the code are coherent (#936) From 5c859983c97a53e82ba55d33e256d0d952d70e96 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 21 Sep 2018 13:53:53 +0200 Subject: [PATCH 101/652] Add pt1d example macro --- .../macroserver/macros/examples/parameters.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sardana/macroserver/macros/examples/parameters.py b/src/sardana/macroserver/macros/examples/parameters.py index 857fe091e8..04e8539a68 100644 --- a/src/sardana/macroserver/macros/examples/parameters.py +++ b/src/sardana/macroserver/macros/examples/parameters.py @@ -56,6 +56,19 @@ def run(self, f): pass +class pt1d(Macro): + """Macro with one float parameter with default value.. + Usage from Spock, ex.: + pt1d 1 + pt1d + """ + + param_def = [['value', Type.Float, None, 'some bloody float']] + + def run(self, f): + pass + + class pt2(Macro): """Macro with one Motor parameter: Each parameter is described in the param_def sequence as being a sequence of four elements: name, type, From 9b2cd8589a3259bdbefed4919ae3fe01ed2c3ae1 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 21 Sep 2018 14:03:40 +0200 Subject: [PATCH 102/652] Add tests for ParamParser with parameters definition --- src/sardana/spock/test/test_parser.py | 252 ++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) diff --git a/src/sardana/spock/test/test_parser.py b/src/sardana/spock/test/test_parser.py index 6f2d6449df..808d4b41cc 100644 --- a/src/sardana/spock/test/test_parser.py +++ b/src/sardana/spock/test/test_parser.py @@ -61,3 +61,255 @@ def parse(self, params_str, params): msg = "Parsing failed (result: %r; expected: %r)" %\ (result, params) self.assertListEqual(result, params, msg) + + +pt0_params_def = [] + +pt1d_params_def = [ + { + "default_value": 99, + "description": "some bloody float", + "max": None, + "min": 1, + "name": "value", + "type": "Float" + } +] + +pt3_params_def = [ + { + "default_value": None, + "description": "List of values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": None, + "description": "value", + "max": None, + "min": 1, + "name": "position", + "type": "Float" + } + ] + } +] + +pt3d_params_def = [ + { + "default_value": None, + "description": "List of values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": 21, + "description": "value", + "max": None, + "min": 1, + "name": "position", + "type": "Float" + } + ] + } +] + +pt5_params_def = [ + { + "default_value": None, + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + }, + { + "default_value": None, + "description": "List of values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": None, + "description": "value", + "max": None, + "min": 1, + "name": "position", + "type": "Float" + } + ] + } +] + +pt7_params_def = [ + { + "default_value": None, + "description": "List of motor/position pairs", + "max": None, + "min": 1, + "name": "m_p_pair", + "type": [ + { + "default_value": None, + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + }, + { + "default_value": None, + "description": "Position to move to", + "max": None, + "min": 1, + "name": "position", + "type": "Float" + } + ] + } +] + +pt10_params_def = [ + { + "default_value": None, + "description": "List of values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": None, + "description": "value", + "max": None, + "min": 1, + "name": "pos", + "type": "Float" + } + ] + }, + { + "default_value": None, + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + }, +] + +pt13_params_def = [ + { + "default_value": None, + "description": "Motor groups", + "max": None, + "min": 1, + "name": "motor_group_list", + "type": [ + { + "default_value": None, + "description": "List of motors", + "max": None, + "min": 1, + "name": "motor list", + "type": [ + { + "default_value": None, + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + } + ] + } + ] + } +] + +pt14_params_def = [ + { + "default_value": None, + "description": "Motor groups", + "max": None, + "min": 1, + "name": "motor_group_list", + "type": [ + { + "default_value": None, + "description": "List of motors", + "max": None, + "min": 1, + "name": "motor list", + "type": [ + { + "default_value": None, + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + } + ] + }, + { + "default_value": None, + "description": "Number", + "max": None, + "min": 1, + "name": "float", + "type": "Float" + } + ] + } +] + + +@insertTest(helper_name="parse", params_def=pt0_params_def, + params_str="", params=[]) +@insertTest(helper_name="parse", params_def=pt1d_params_def, + params_str="1", params=["1"]) +@insertTest(helper_name="parse", params_def=pt1d_params_def, + params_str="", params=[]) +@insertTest(helper_name="parse", params_def=pt3_params_def, + params_str="1 34 15", params=[["1", "34", "15"]]) +@insertTest(helper_name="parse", params_def=pt3_params_def, + params_str="[1 34 15]", params=[["1", "34", "15"]]) +@insertTest(helper_name="parse", params_def=pt3d_params_def, + params_str="1 34 15", params=[["1", "34", "15"]]) +@insertTest(helper_name="parse", params_def=pt3d_params_def, + params_str="[1 34 15]", params=[["1", "34", "15"]]) +@insertTest(helper_name="parse", params_def=pt3d_params_def, + params_str="[1 [] 15]", params=[["1", [], "15"]]) +@insertTest(helper_name="parse", params_def=pt5_params_def, + params_str="mot1 1 3", params=["mot1", ["1", "3"]]) +@insertTest(helper_name="parse", params_def=pt5_params_def, + params_str="mot1 [1 3]", params=["mot1", ["1", "3"]]) +@insertTest(helper_name="parse", params_def=pt7_params_def, + params_str="mot1 1 mot2 3", + params=[[["mot1", "1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt7_params_def, + params_str="[[mot1 1] [mot2 3]]", + params=[[["mot1", "1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt10_params_def, + params_str="[1 3] mot1", params=[["1", "3"], "mot1"]) +@insertTest(helper_name="parse", params_def=pt10_params_def, + params_str="1 mot1", params=[["1"], "mot1"]) +@insertTest(helper_name="parse", params_def=pt13_params_def, + params_str="[[mot1 mot2] [mot3 mot4]]", + params=[[["mot1", "mot2"], ["mot3", "mot4"]]]) +@insertTest(helper_name="parse", params_def=pt14_params_def, + params_str="[[[mot1 mot2] 3] [[mot3] 5]]", + params=[[[["mot1", "mot2"], "3"], [["mot3"], "5"]]]) +class ParamParserWithDefTestCase(unittest.TestCase): + """Unit tests for ParamParser class initialized with parameters + definition. + """ + def parse(self, params_def, params_str, params): + p = ParamParser(params_def) + result = p.parse(params_str) + msg = "Parsing failed (result: %r; expected: %r)" % \ + (result, params) + self.assertListEqual(result, params, msg) From 1adbb8f13b1d3bfbc5293565278587e9582ee940 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 21 Sep 2018 14:04:22 +0200 Subject: [PATCH 103/652] Add inteligence to ParamParser to use parameters definition --- src/sardana/spock/parser.py | 183 ++++++++++++++++++++++++++++++++---- 1 file changed, 165 insertions(+), 18 deletions(-) diff --git a/src/sardana/spock/parser.py b/src/sardana/spock/parser.py index 7668b6b668..5472b1f5f4 100644 --- a/src/sardana/spock/parser.py +++ b/src/sardana/spock/parser.py @@ -58,6 +58,26 @@ def generate_tokens(text): yield tok +def is_repeat_param(param_def): + return isinstance(param_def["type"], list) + + +def is_repeat_param_single(param_def): + return len(param_def) == 1 + + +class ParseError(Exception): + pass + + +class UnrecognizedParamValue(ParseError): + pass + + +class ExcessParamValue(ParseError): + pass + + class ParamParser: """Implementation of a recursive descent parser. Use the ._accept() method to test and accept the current lookahead token. Use the ._expect() @@ -67,12 +87,17 @@ class ParamParser: Inspired on Python Cookbook 3 (chapter 2.19) """ + def __init__(self, params_def=None): + self._params_def = params_def + def parse(self, text): self.tokens = generate_tokens(text) self.tok = None # Last symbol consumed self.nexttok = None # Next symbol tokenized self._advance() # Load first lookahead token - return self.param() + params = self._params() + self._end_check() + return params def _advance(self): """Advance one token ahead""" @@ -93,24 +118,146 @@ def _expect(self, toktype): # Grammar rules follow - def param(self): - """Interpret parameters by iterating over generated tokens. Respect - quotes for string parameters and parenthesis for repeat parameters. + def _params(self, params_def=None): + """Interpret parameter values by iterating over generated tokens + according to parameters definition. + + It is used either at the macro level or a the repeat parameter + repetition level. + + :param params_def: parameters definition as used by the + :meth:`sardana.macroserver.msmetamacro.Parametrizable.get_parameter` + or by the + `attr:`sardana.taurus.core.tango.sardana.macro.MacroInfo.parameters` + :type params_def: list + :param end_check: whether to check if there are parameter values + exceeding parameters definition + :type end_check: bool + :return: parameter values + :rtype: list """ + params_def = params_def or self._params_def + len_params_def = len(params_def) params = [] - while True: - if self._accept("QUOTEDPARAM"): - # quoted parameters allows using quotes escaped by \\ - string = self.tok.value - string = string.replace('\\"', '"') - params.append(string) - elif self._accept("SINGQUOTEDPARAM"): - params.append(self.tok.value) - elif self._accept("PARAM"): - params.append(self.tok.value) - elif self._accept("LPAREN"): - params.append(self.param()) - self._expect("RPAREN") + if self.nexttok is not None: + for param_idx, param_def in enumerate(params_def): + if is_repeat_param(param_def): + last_param = False + if param_idx == len_params_def - 1: + last_param = True + repeat_param_def = param_def["type"] + param_value = self._repeat_param(repeat_param_def, last_param) + else: + param_value = self._param() + params.append(param_value) + return params + + def _param(self): + """Interpret normal parameter value. Respect quotes for string + parameters. + + :return: parameter value + :rtype: str + """ + if self._accept("QUOTEDPARAM"): + # quoted parameters allows using quotes escaped by \\ + string = self.tok.value + string = string.replace('\\"', '"') + param = string + elif self._accept("SINGQUOTEDPARAM"): + param = self.tok.value + elif self._accept("PARAM"): + tok_value = self.tok.value + param = tok_value + else: + msg = "%s is not a valid param value" % self.tok.value + raise UnrecognizedParamValue(msg) + return param + + def _repeat_param(self, repeat_param_def, last_param): + """Interpret repeat parameter. + + Accepts repeat parameters using the following rules: + * enclosed in parenthesis + * non-enclosed in parenthesis multiple repetitions of the last repeat + parameter (can be single or multiple) + * non-enclosed in parenthesis one repetition of single repeat + parameter at arbitrary position + + :param repeat_param_def: repeat parameter definition + :type repeat_param_def: list + :param last_param: whether this repeat parameter is the last in the + definition + :type last_param: bool + :return: repeat parameter value + :rtype: list + """ + repeats = [] + + if self._accept("LPAREN"): + while True: + repeat = self._repeat(repeat_param_def) + if repeat is None: + break + repeats.append(repeat) + self._expect("RPAREN") + else: + single = is_repeat_param_single(repeat_param_def) + if last_param: + while True: + repeat = [] + for _ in repeat_param_def: + try: + param = self._param() + except UnrecognizedParamValue: + return repeats + if single: + repeat = param + else: + repeat.append(param) + repeats.append(repeat) + elif single: + param = self._param() + repeats = [param] + return repeats + + def _repeat(self, repeat_param_def): + """Interpret one repetition of the repeat parameter. + + :param repeat_param_def: repeat parameter definition + :type repeat_param_def: list + :return: repeat value + :rtype: list or None + """ + repeat = None + if self._accept("LPAREN"): + # empty brackets will be interpreted as a default value + if self._accept("RPAREN"): + repeat = [] else: + repeat = self._params(repeat_param_def) + # repetitions of single repeat parameters are not enclosed + # in parenthesis so remove it + if is_repeat_param_single(repeat_param_def): + repeat = repeat[0] + self._expect("RPAREN") + else: + try: + repeat = self._param() + except UnrecognizedParamValue: + # no repeat found - return None + pass + return repeat + + def _end_check(self): + """Check if there are excessive tokens.""" + excess_tokens = "" + if len(self._params_def) == 0 and self.nexttok is not None: + excess_tokens += self.nexttok.value + while True: + self._advance() + if self.nexttok is None: break - return params + excess_tokens += self.nexttok.value + if len(excess_tokens) > 0: + raise ExcessParamValue("excess tokens are %s" % excess_tokens) \ No newline at end of file From 1e61bbdcb1d1536d49af9a83e038cd7d96fa580c Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 21 Sep 2018 14:05:04 +0200 Subject: [PATCH 104/652] Pass parameters definition to ParamParser in spock --- src/sardana/spock/spockms.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/sardana/spock/spockms.py b/src/sardana/spock/spockms.py index 934563f6d6..cca3035748 100755 --- a/src/sardana/spock/spockms.py +++ b/src/sardana/spock/spockms.py @@ -589,16 +589,20 @@ def _addMacro(self, macro_info): # IPython < 1 magic commands have different API if genutils.get_ipython_version_list() < [1, 0]: def macro_fn(shell, parameter_s='', name=macro_name): - parameters = split_macro_parameters(parameter_s) door = genutils.get_door() + ms = genutils.get_macro_server() + params_def = ms.getMacroInfoObj(name).parameters + parameters = split_macro_parameters(parameter_s, params_def) door.runMacro(macro_name, parameters, synch=True) macro = door.getLastRunningMacro() if macro is not None: # maybe none if macro was aborted return macro.getResult() else: def macro_fn(parameter_s='', name=macro_name): - parameters = split_macro_parameters(parameter_s) door = genutils.get_door() + ms = genutils.get_macro_server() + params_def = ms.getMacroInfoObj(name).parameters + parameters = split_macro_parameters(parameter_s, params_def) door.runMacro(macro_name, parameters, synch=True) macro = door.getLastRunningMacro() if macro is not None: # maybe none if macro was aborted @@ -620,19 +624,18 @@ def _removeMacro(self, macro_info): del self._local_magic[macro_name] -def split_macro_parameters(parameters_s): +def split_macro_parameters(parameters_s, params_def): """Split string with macro parameters into a list with macro parameters. Whitespaces are the separators between the parameters. - When the input string contains square brackets it indicates an advanced - syntax for representing repeat parameters. Repeat parameters are encapsulated - in square brackets and its internal repetitions, if composed from more than - one item are also encapsulated in brackets. In this case the output list - contains lists internally. + Repeat parameters are encapsulated in square brackets and its internal + repetitions, if composed from more than one item are also encapsulated + in brackets. In this case the output list contains lists internally. - :param parameters_s (string): input string containing parameters - :returns (list): parameters represented as a list (may contain internal - lists) + :param parameters_s: input string containing parameters + :type parameters_s: string + :return: parameters represented as a list (may contain internal lists + :rtype: list """ - parser = ParamParser() + parser = ParamParser(params_def) return parser.parse(parameters_s) From a2158f028fb13afa357b75780e4a8cc0300af9e4 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 21 Sep 2018 14:09:24 +0200 Subject: [PATCH 105/652] Create MacroNode relying on correct macro parameters Now ParamParser knows the parameters definition and always correctly parses parameters. There is no need to interpret parameter values based on the old/new interface and the MacroNode can be directly populated from parameter values list. --- .../taurus/core/tango/sardana/macro.py | 66 +------------------ 1 file changed, 1 insertion(+), 65 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py index 28db7afb4d..4b73b24d68 100755 --- a/src/sardana/taurus/core/tango/sardana/macro.py +++ b/src/sardana/taurus/core/tango/sardana/macro.py @@ -1303,69 +1303,5 @@ def createMacroNode(macro_name, params_def, macro_params): unify them and place in some common location. """ macro_node = MacroNode(name=macro_name, params_def=params_def) - # Check if ParamRepeat used in advanced interface - new_interface = False - for param in macro_params: - if isinstance(param, list): - new_interface = True - break - - if not new_interface: - param_nodes = macro_node.params() - len_param_nodes = len(param_nodes) - param_idx = 0 - for param_node, param_raw in zip(param_nodes, macro_params): - if isinstance(param_node, SingleParamNode): - param_node.setValue(param_raw) - # Repeat parameters that are not at the end. - elif (isinstance(param_node, RepeatParamNode) and - param_idx < (len_param_nodes - 1)): - repeat_node = param_node.child(0) - # Add a new repeat node. This is needed when the raw values - # fill more repeat nodes that the minimum number of - # repetitions e.g. min=0. - if repeat_node is None: - repeat_node = param_node.addRepeat() - if len(repeat_node.children()) > 1: - msg = ("repeat parameter with more than one member must " - "be defined at the end when intended to " - "be used with spock syntax") - raise Exception(msg) - member_node = repeat_node.child(0) - if isinstance(member_node, RepeatParamNode): - msg = ("nested repeat parameters are not allowed when " - "intended to be used with spock syntax") - raise Exception(msg) - member_node.setValue(param_raw) - # The resting values are interpreted as repeat parameter values. - # This ignores parameter values which exceeds the parameters - # definition. - else: - params_info = param_node.paramsInfo() - params_info_len = len(params_info) - last_param_idx = len_param_nodes - 1 - rep = 0 - mem = 0 - rest_raw = macro_params[last_param_idx:] - for member_raw in rest_raw: - repeat_node = param_node.child(rep) - # Add a new repeat node. This is needed when the raw - # values fill more repeat nodes that the minimum number - # of repetitions e.g. min=0. - if repeat_node is None: - repeat_node = param_node.addRepeat() - member_node = repeat_node.child(mem) - if isinstance(member_node, RepeatParamNode): - msg = ("nested repeat parameters are not allowed " - "when intended to be used with spock syntax") - raise Exception(msg) - member_node.setValue(member_raw) - mem += 1 - mem %= params_info_len - if mem == 0: - rep += 1 - break - param_idx += 1 - else: - macro_node.fromList(macro_params) + macro_node.fromList(macro_params) return macro_node From 7e7f7240a50cd33f51d35e96c0375c49bf3b5185 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 21 Sep 2018 14:16:18 +0200 Subject: [PATCH 106/652] Comment old ParamParser test TODO: these should be converted to the new ParamParser (with parameters definition) tests. --- src/sardana/spock/test/test_parser.py | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/sardana/spock/test/test_parser.py b/src/sardana/spock/test/test_parser.py index 808d4b41cc..cbe99b068c 100644 --- a/src/sardana/spock/test/test_parser.py +++ b/src/sardana/spock/test/test_parser.py @@ -30,25 +30,25 @@ from sardana.spock.parser import ParamParser -@insertTest(helper_name="parse", - params_str='ScanFile "[\\"file.nxs\\", \\"file.dat\\"]"', - params=["ScanFile", '["file.nxs", "file.dat"]']) -@insertTest(helper_name="parse", params_str="[1 [] 3]", - params=[["1", [], "3"]]) -@insertTest(helper_name="parse", - params_str="2 3 ['Hello world!' 'How are you?']", - params=["2", "3", ["Hello world!", "How are you?"]]) -@insertTest(helper_name="parse", params_str="ScanFile file.dat", - params=["ScanFile", "file.dat"]) -@insertTest(helper_name="parse", params_str="'2 3'", params=["2 3"]) -@insertTest(helper_name="parse", params_str='"2 3"', params=["2 3"]) -@insertTest(helper_name="parse", params_str="[[mot01 3][mot02 5]] ct01 999", - params=[[["mot01", "3"], ["mot02", "5"]], "ct01", "999"]) -@insertTest(helper_name="parse", params_str="[[2 3][4 5]]", - params=[[["2", "3"], ["4", "5"]]]) -@insertTest(helper_name="parse", params_str="1 [2 3]", - params=["1", ["2", "3"]]) -@insertTest(helper_name="parse", params_str="2 3", params=["2", "3"]) +# @insertTest(helper_name="parse", +# params_str='ScanFile "[\\"file.nxs\\", \\"file.dat\\"]"', +# params=["ScanFile", '["file.nxs", "file.dat"]']) +# @insertTest(helper_name="parse", params_str="[1 [] 3]", +# params=[["1", [], "3"]]) +# @insertTest(helper_name="parse", +# params_str="2 3 ['Hello world!' 'How are you?']", +# params=["2", "3", ["Hello world!", "How are you?"]]) +# @insertTest(helper_name="parse", params_str="ScanFile file.dat", +# params=["ScanFile", "file.dat"]) +# @insertTest(helper_name="parse", params_str="'2 3'", params=["2 3"]) +# @insertTest(helper_name="parse", params_str='"2 3"', params=["2 3"]) +# @insertTest(helper_name="parse", params_str="[[mot01 3][mot02 5]] ct01 999", +# params=[[["mot01", "3"], ["mot02", "5"]], "ct01", "999"]) +# @insertTest(helper_name="parse", params_str="[[2 3][4 5]]", +# params=[[["2", "3"], ["4", "5"]]]) +# @insertTest(helper_name="parse", params_str="1 [2 3]", +# params=["1", ["2", "3"]]) +# @insertTest(helper_name="parse", params_str="2 3", params=["2", "3"]) class ParamParserTestCase(unittest.TestCase): """Unit tests for ParamParser class.""" From 335fad162ad3d4de582786097e6f5aff9ab1eada Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 24 Sep 2018 09:08:13 +0200 Subject: [PATCH 107/652] Type in phi name --- src/sardana/macroserver/macros/hkl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py index b7ea6b43f2..515848af15 100644 --- a/src/sardana/macroserver/macros/hkl.py +++ b/src/sardana/macroserver/macros/hkl.py @@ -383,7 +383,7 @@ def run(self, H, K, L, Trajectory): str_pos[self.labelmotor["Mu"]], str_pos[self.labelmotor["Omega"]], str_pos[self.labelmotor["Chi"]], - str_pos[self.labelmotor["Phui"]], + str_pos[self.labelmotor["Phi"]], str_pos[self.labelmotor["Gamma"]], str_pos[self.labelmotor["Delta"]])) From 9d1e3fceba5d5a9be55278f5cb4a2c405facca40 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 25 Sep 2018 10:03:11 +0200 Subject: [PATCH 108/652] Fix flake8 errors --- src/sardana/macroserver/macros/examples/parameters.py | 2 +- src/sardana/spock/parser.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sardana/macroserver/macros/examples/parameters.py b/src/sardana/macroserver/macros/examples/parameters.py index 04e8539a68..681aed83b8 100644 --- a/src/sardana/macroserver/macros/examples/parameters.py +++ b/src/sardana/macroserver/macros/examples/parameters.py @@ -23,7 +23,7 @@ """This module contains macros that demonstrate the usage of macro parameters""" -from sardana.macroserver.macro import * +from sardana.macroserver.macro import Macro, Type, ParamRepeat __all__ = ["pt0", "pt1", "pt2", "pt3", "pt3d", "pt4", "pt5", "pt6", "pt7", "pt7d1", "pt7d2", "pt8", "pt9", "pt10", "pt11", "pt12", "pt13", diff --git a/src/sardana/spock/parser.py b/src/sardana/spock/parser.py index 5472b1f5f4..13d1550534 100644 --- a/src/sardana/spock/parser.py +++ b/src/sardana/spock/parser.py @@ -146,7 +146,8 @@ def _params(self, params_def=None): if param_idx == len_params_def - 1: last_param = True repeat_param_def = param_def["type"] - param_value = self._repeat_param(repeat_param_def, last_param) + param_value = self._repeat_param(repeat_param_def, + last_param) else: param_value = self._param() params.append(param_value) From 802d1dce2d0ef36796c4bf372d53cbe47b249385 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 25 Sep 2018 11:28:14 +0200 Subject: [PATCH 109/652] Parse macro params on the server side when necessary --- src/sardana/macroserver/msmacromanager.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sardana/macroserver/msmacromanager.py b/src/sardana/macroserver/msmacromanager.py index 29d88d70a8..249e331d8a 100644 --- a/src/sardana/macroserver/msmacromanager.py +++ b/src/sardana/macroserver/msmacromanager.py @@ -719,9 +719,14 @@ def getMacroInfo(self, macro_names, format='json'): ret.append(json_codec.encode(('', macro_meta.serialize()))[1]) return ret - def _createMacroNode(self, macro_name, macro_params): + def _createMacroNode(self, macro_name, macro_params_raw): macro = self.getMacro(macro_name) params_def = macro.get_parameter() + # merge params to a single, space separated, string (spock like) + macro_params_str = " ".join(macro_params_raw) + param_parser = ParamParser(params_def) + # parse string with macro params to the correct list representation + macro_params = param_parser.parse(macro_params_str) return createMacroNode(macro_name, params_def, macro_params) def decodeMacroParameters(self, door, raw_params): From da8c5502044b4e252e238256e31bab6068655f8b Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 25 Sep 2018 17:08:34 +0200 Subject: [PATCH 110/652] Break parsing if there are no next tokens --- src/sardana/spock/parser.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/sardana/spock/parser.py b/src/sardana/spock/parser.py index 13d1550534..b046f4bf40 100644 --- a/src/sardana/spock/parser.py +++ b/src/sardana/spock/parser.py @@ -95,6 +95,7 @@ def parse(self, text): self.tok = None # Last symbol consumed self.nexttok = None # Next symbol tokenized self._advance() # Load first lookahead token + #import pdb; pdb.set_trace() params = self._params() self._end_check() return params @@ -139,18 +140,20 @@ def _params(self, params_def=None): params_def = params_def or self._params_def len_params_def = len(params_def) params = [] - if self.nexttok is not None: - for param_idx, param_def in enumerate(params_def): - if is_repeat_param(param_def): - last_param = False - if param_idx == len_params_def - 1: - last_param = True - repeat_param_def = param_def["type"] - param_value = self._repeat_param(repeat_param_def, - last_param) - else: - param_value = self._param() - params.append(param_value) + for param_idx, param_def in enumerate(params_def): + # no next tokens means that the string being parsed had finished + if self.nexttok is None: + break + if is_repeat_param(param_def): + last_param = False + if param_idx == len_params_def - 1: + last_param = True + repeat_param_def = param_def["type"] + param_value = self._repeat_param(repeat_param_def, + last_param) + else: + param_value = self._param() + params.append(param_value) return params def _param(self): From c0066f5e65b72b5eb5ec35521693743a8c99b6d8 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 25 Sep 2018 18:23:39 +0200 Subject: [PATCH 111/652] Adapt test to new API of createMacroNode --- src/sardana/taurus/core/tango/sardana/test/test_macro.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/test/test_macro.py b/src/sardana/taurus/core/tango/sardana/test/test_macro.py index 65ba237852..8ed8d271f5 100755 --- a/src/sardana/taurus/core/tango/sardana/test/test_macro.py +++ b/src/sardana/taurus/core/tango/sardana/test/test_macro.py @@ -41,6 +41,7 @@ pt14d_param_def) # TODO: Use unittest.mock instead of this fake class. from sardana.macroserver.mstypemanager import TypeManager +from sardana.spock.parser import ParamParser class FakeMacroServer(object): @@ -72,7 +73,7 @@ class FakeMacroServer(object): "max": None } ] -pt8_params_value = ["mot73", "5.0", "mot74", "8.0"] +pt8_params_str = "mot73 5.0 mot74 8.0" # pt8_xml = \ @@ -91,7 +92,7 @@ class FakeMacroServer(object): @insertTest(helper_name='verifyXML', macro_name="pt8", param_def=pt8_params_def, - param_value=pt8_params_value, expected_xml_rep=pt8_xml) + param_str=pt8_params_str, expected_xml_rep=pt8_xml) class MacroNodeTestCase(unittest.TestCase): def _validateXML(self, macronode_xml, expected_xml): @@ -106,7 +107,7 @@ def _validateXML(self, macronode_xml, expected_xml): # at the end. strips should not be necessary self.assertEquals(expected_str.strip(), macronode_str.strip(), msg) - def verifyXML(self, macro_name, param_def, param_value, expected_xml_rep): + def verifyXML(self, macro_name, param_def, param_str, expected_xml_rep): """ Helper to verify the generated XML of a macroNode :param macro_name: (str) name of the macro @@ -116,6 +117,8 @@ def verifyXML(self, macro_name, param_def, param_value, expected_xml_rep): :param expected_xml_rep: "pretty print" string representation of a XML macroNode """ + param_parser = ParamParser(param_def) + param_value = param_parser.parse(param_str) # Create the MacroNide with the inputs macronode = createMacroNode(macro_name, param_def, param_value) # Get the MacroNode equivalent XML tree From 53f04f665bf9340479106b1735af4cf18001ec3a Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 25 Sep 2018 18:27:26 +0200 Subject: [PATCH 112/652] Fix flake8 --- src/sardana/macroserver/msmacromanager.py | 6 +++--- src/sardana/spock/parser.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sardana/macroserver/msmacromanager.py b/src/sardana/macroserver/msmacromanager.py index 249e331d8a..992d0a03f8 100644 --- a/src/sardana/macroserver/msmacromanager.py +++ b/src/sardana/macroserver/msmacromanager.py @@ -733,9 +733,9 @@ def decodeMacroParameters(self, door, raw_params): """Decode macro parameters :param door: (sardana.macroserver.msdoor.MSDoor) door object - :param raw_params: (lxml.etree._Element or list) xml element representing - macro with subelements representing parameters or list - with macro name followed by parameter values + :param raw_params: (lxml.etree._Element or list) xml element + representing macro with subelements representing parameters or + list with macro name followed by parameter values """ if isinstance(raw_params, etree._Element): macro_name = raw_params.get("name") diff --git a/src/sardana/spock/parser.py b/src/sardana/spock/parser.py index b046f4bf40..b01e57c6aa 100644 --- a/src/sardana/spock/parser.py +++ b/src/sardana/spock/parser.py @@ -95,7 +95,6 @@ def parse(self, text): self.tok = None # Last symbol consumed self.nexttok = None # Next symbol tokenized self._advance() # Load first lookahead token - #import pdb; pdb.set_trace() params = self._params() self._end_check() return params @@ -264,4 +263,4 @@ def _end_check(self): break excess_tokens += self.nexttok.value if len(excess_tokens) > 0: - raise ExcessParamValue("excess tokens are %s" % excess_tokens) \ No newline at end of file + raise ExcessParamValue("excess tokens are %s" % excess_tokens) From f3b576896e996929885c6450b1699f3ab9aa52df Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 26 Sep 2018 10:53:02 +0200 Subject: [PATCH 113/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe5cbb284b..c0ca91c008 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ This file follows the formats and conventions from [keepachangelog.com] - Avoid final padding in timescan when it was stopped by user (#869, #935) - Hook places advertised by continuous scans so the `allowHooks` hint and the code are coherent (#936) +- Macro/controller module description when module does not have a docstring + (#945) ### Changed - Move pre-scan and post-scan hooks out of `scan_loop` method (#920, #922, From fd88ef493f49925d17f7a018dadceb12e689b544 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 26 Sep 2018 10:58:08 +0200 Subject: [PATCH 114/652] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0ca91c008..6614b25863 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ This file follows the formats and conventions from [keepachangelog.com] ### Added - Possibility to define macros with optional parameters. These must be the last - ones in the definition (#285, #876) + ones in the definition (#285, #876, #943, #941) - Workaround for API_DeviceTimedOut errors on MeasurementGroup Start. Call Stop in case this error occured (#764). - Optional measurement group parameter to `ct` and `uct` macros (#940, #473) From 03abe97504b70538d76287f0ed31de023d3a6c0f Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 28 Sep 2018 08:25:03 +0200 Subject: [PATCH 115/652] Implement PoolMGSynchronization class --- src/sardana/pool/poolmeasurementgroup.py | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 0ad982b431..0d0462bb1b 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -122,6 +122,48 @@ def _to_fqdn(name, logger=None): return full_name +class PoolMGSynchronization(list): + + def _get_param(self, param, domain=SynchDomain.Time): + """ + Extract parameter from synchronization dict. If there is only + one group in the synchronization than returns float with the value. + Otherwise a list of floats with different values. + + :param param: parameter type + :type param: SynchParam + :param domain: domain + :type param: SynchDomain + :return: + :rtype float or [float] + """ + + if len(self) == 1: + return self[0][param][domain] + + values = [] + for group in self: + value = group[param][domain] + repeats = group[SynchParam.Repeats] + values += [value] * repeats + return values + + @property + def repetitions(self): + repetitions = 0 + for group in self: + repetitions += group[SynchParam.Repeats] + return repetitions + + @property + def integration_time(self): + return self._get_param(SynchParam.Active) + + @property + def total_time(self): + return self._get_param(SynchParam.Total) + + class PoolMeasurementGroup(PoolGroupElement): DFT_DESC = 'General purpose measurement group' From 72376ebd189e44740c1f4c36ffd3e99b2c44a4c1 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 28 Sep 2018 08:28:40 +0200 Subject: [PATCH 116/652] Adapt to use PoolMGSynchronization --- src/sardana/pool/poolacquisition.py | 48 +----------------------- src/sardana/pool/poolmeasurementgroup.py | 14 +++---- 2 files changed, 9 insertions(+), 53 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 3d5719ed6c..63353ec383 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -164,50 +164,6 @@ def getTGConfiguration(MGcfg): return TGcfg, _tg_element_list -def extract_integ_time(synchronization): - """Extract integration time(s) from synchronization dict. If there is only - one group in the synchronization than returns float with the integration - time. Otherwise a list of floats with different integration times. - - TODO: (technical debt) All the MeasurementGroup synchronization - logic should be encapsulate in a dedicated class instead of - using a basic data structures like dict or lists... - - :param synchronization: group(s) where each group is described by - SynchParam(s) - :type synchronization: list(dict) - :return list(float) or float - """ - if len(synchronization) == 1: - integ_time = synchronization[0][SynchParam.Active][SynchDomain.Time] - else: - integ_time = [] - for group in synchronization: - active_time = group[SynchParam.Active][SynchDomain.Time] - repeats = group[SynchParam.Repeats] - integ_time += [active_time] * repeats - return integ_time - - -def extract_repetitions(synchronization): - """Extract repetitions from synchronization dict. - - TODO: (technical debt) All the MeasurementGroup synchronization - logic should be encapsulate in a dedicated class instead of - using a basic data structures like dict or lists... - - :param synchronization: group(s) where each group is described by - SynchParam(s) - :type synchronization: list(dict) - :return: number of repetitions - :rtype: int - """ - repetitions = 0 - for group in synchronization: - repetitions += group[SynchParam.Repeats] - return repetitions - - def is_value_error(value): if isinstance(value, SardanaValue) and value.error: return True @@ -308,8 +264,8 @@ def run(self, *args, **kwargs): pseudo_elem.clear_value_buffer() config = kwargs['config'] synchronization = kwargs["synchronization"] - integ_time = extract_integ_time(synchronization) - repetitions = extract_repetitions(synchronization) + integ_time = synchronization.integration_time + repetitions = synchronization.repetitions # TODO: this code splits the global mg configuration into # experimental channels triggered by hw and experimental channels # triggered by sw. Refactor it!!!! diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 0d0462bb1b..d5f56e4716 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -180,7 +180,7 @@ def __init__(self, **kwargs): # by default software synchronizer initial domain is set to Position self._sw_synch_initial_domain = SynchDomain.Position - self._synchronization = [] + self._synchronization = PoolMGSynchronization() # dict with channel and its acquisition synchronization # key: PoolBaseChannel; value: AcqSynch self._channel_to_acq_synch = {} @@ -623,14 +623,14 @@ def get_timer(self): # ------------------------------------------------------------------------- def get_integration_time(self): - if len(self._synchronization) == 0: + integration_time = self._synchronization.integration_time + if type(integration_time) == float: + return integration_time + elif len(integration_time) == 0: raise Exception("The synchronization group has not been" " initialized") - elif len(self._synchronization) > 1: + elif len(integration_time) > 1: raise Exception("There are more than one synchronization groups") - else: - return self._synchronization[0][SynchParam.Active][ - SynchDomain.Time] def set_integration_time(self, integration_time, propagate=1): total_time = integration_time + self.latency_time @@ -691,7 +691,7 @@ def get_synchronization(self): return self._synchronization def set_synchronization(self, synchronization, propagate=1): - self._synchronization = synchronization + self._synchronization = PoolMGSynchronization(synchronization) self._config_dirty = True # acquisition mode goes to configuration if not propagate: return From becdfed1663d01374cc886734395f95ce6ac8d89 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 28 Sep 2018 17:15:55 +0200 Subject: [PATCH 117/652] Rename PoolMgSynchronization to SynchronizationDescription --- src/sardana/pool/poolmeasurementgroup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index d5f56e4716..d090a67263 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -122,7 +122,7 @@ def _to_fqdn(name, logger=None): return full_name -class PoolMGSynchronization(list): +class SynchronizationDescription(list): def _get_param(self, param, domain=SynchDomain.Time): """ @@ -180,7 +180,7 @@ def __init__(self, **kwargs): # by default software synchronizer initial domain is set to Position self._sw_synch_initial_domain = SynchDomain.Position - self._synchronization = PoolMGSynchronization() + self._synchronization = SynchronizationDescription() # dict with channel and its acquisition synchronization # key: PoolBaseChannel; value: AcqSynch self._channel_to_acq_synch = {} @@ -691,7 +691,7 @@ def get_synchronization(self): return self._synchronization def set_synchronization(self, synchronization, propagate=1): - self._synchronization = PoolMGSynchronization(synchronization) + self._synchronization = SynchronizationDescription(synchronization) self._config_dirty = True # acquisition mode goes to configuration if not propagate: return From 5487ba537e283eadeedc8fad3cf3160b66d587d5 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 28 Sep 2018 17:16:21 +0200 Subject: [PATCH 118/652] Complement docstrings --- src/sardana/pool/poolmeasurementgroup.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index d090a67263..d6de4f723e 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -123,18 +123,23 @@ def _to_fqdn(name, logger=None): class SynchronizationDescription(list): + """Synchronization description. It is composed from groups - repetitions + of equidistant synchronization events. Each group is described by + :class:`~sardana.pool.pooldefs.SynchParam` parameters which may have + values in :class:`~sardana.pool.pooldefs.SynchDomain` domains. + """ def _get_param(self, param, domain=SynchDomain.Time): """ - Extract parameter from synchronization dict. If there is only - one group in the synchronization than returns float with the value. - Otherwise a list of floats with different values. + Extract parameter from synchronization description and its groups. If + there is only one group in the synchronization then returns float + with the value. Otherwise a list of floats with different values. :param param: parameter type - :type param: SynchParam + :type param: :class:`~sardana.pool.pooldefs.SynchParam` :param domain: domain - :type param: SynchDomain - :return: + :type param: :class:`~sardana.pool.pooldefs.SynchDomain` + :return: parameter value(s) :rtype float or [float] """ From 164a724657edee9034060551fdfb4d25a9719f97 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 28 Sep 2018 17:17:13 +0200 Subject: [PATCH 119/652] Expose class properties first --- src/sardana/pool/poolmeasurementgroup.py | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index d6de4f723e..b7e0abd019 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -129,6 +129,21 @@ class SynchronizationDescription(list): values in :class:`~sardana.pool.pooldefs.SynchDomain` domains. """ + @property + def repetitions(self): + repetitions = 0 + for group in self: + repetitions += group[SynchParam.Repeats] + return repetitions + + @property + def integration_time(self): + return self._get_param(SynchParam.Active) + + @property + def total_time(self): + return self._get_param(SynchParam.Total) + def _get_param(self, param, domain=SynchDomain.Time): """ Extract parameter from synchronization description and its groups. If @@ -153,21 +168,6 @@ def _get_param(self, param, domain=SynchDomain.Time): values += [value] * repeats return values - @property - def repetitions(self): - repetitions = 0 - for group in self: - repetitions += group[SynchParam.Repeats] - return repetitions - - @property - def integration_time(self): - return self._get_param(SynchParam.Active) - - @property - def total_time(self): - return self._get_param(SynchParam.Total) - class PoolMeasurementGroup(PoolGroupElement): From 91c0debbb1e666eeb7cc68a1826c567ac0df307e Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 28 Sep 2018 17:19:33 +0200 Subject: [PATCH 120/652] Move SynchronizationDescription to poolsynchronization module --- src/sardana/pool/poolmeasurementgroup.py | 48 +---------------------- src/sardana/pool/poolsynchronization.py | 50 +++++++++++++++++++++++- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index b7e0abd019..280821e746 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -46,6 +46,7 @@ SynchDomain) from sardana.pool.poolgroupelement import PoolGroupElement from sardana.pool.poolacquisition import PoolAcquisition +from sardana.pool.poolsynchronization import SynchronizationDescription from sardana.pool.poolexternal import PoolExternalObject from sardana.taurus.core.tango.sardana import PlotType, Normalization @@ -122,53 +123,6 @@ def _to_fqdn(name, logger=None): return full_name -class SynchronizationDescription(list): - """Synchronization description. It is composed from groups - repetitions - of equidistant synchronization events. Each group is described by - :class:`~sardana.pool.pooldefs.SynchParam` parameters which may have - values in :class:`~sardana.pool.pooldefs.SynchDomain` domains. - """ - - @property - def repetitions(self): - repetitions = 0 - for group in self: - repetitions += group[SynchParam.Repeats] - return repetitions - - @property - def integration_time(self): - return self._get_param(SynchParam.Active) - - @property - def total_time(self): - return self._get_param(SynchParam.Total) - - def _get_param(self, param, domain=SynchDomain.Time): - """ - Extract parameter from synchronization description and its groups. If - there is only one group in the synchronization then returns float - with the value. Otherwise a list of floats with different values. - - :param param: parameter type - :type param: :class:`~sardana.pool.pooldefs.SynchParam` - :param domain: domain - :type param: :class:`~sardana.pool.pooldefs.SynchDomain` - :return: parameter value(s) - :rtype float or [float] - """ - - if len(self) == 1: - return self[0][param][domain] - - values = [] - for group in self: - value = group[param][domain] - repeats = group[SynchParam.Repeats] - values += [value] * repeats - return values - - class PoolMeasurementGroup(PoolGroupElement): DFT_DESC = 'General purpose measurement group' diff --git a/src/sardana/pool/poolsynchronization.py b/src/sardana/pool/poolsynchronization.py index 11d536779a..850dff9378 100644 --- a/src/sardana/pool/poolsynchronization.py +++ b/src/sardana/pool/poolsynchronization.py @@ -27,13 +27,14 @@ """This module is part of the Python Pool libray. It defines the class for the trigger/gate generation""" -__all__ = ["PoolSynchronization", "TGChannel"] +__all__ = ["PoolSynchronization", "SynchronizationDescription", "TGChannel"] import time from functools import partial from taurus.core.util.log import DebugIt from sardana import State from sardana.sardanathreadpool import get_thread_pool +from sardana.pool.pooldefs import SynchDomain, SynchParam from sardana.pool.poolaction import ActionContext, PoolActionItem, PoolAction from sardana.util.funcgenerator import FunctionGenerator @@ -60,6 +61,53 @@ def __getattr__(self, name): return getattr(self.element, name) +class SynchronizationDescription(list): + """Synchronization description. It is composed from groups - repetitions + of equidistant synchronization events. Each group is described by + :class:`~sardana.pool.pooldefs.SynchParam` parameters which may have + values in :class:`~sardana.pool.pooldefs.SynchDomain` domains. + """ + + @property + def repetitions(self): + repetitions = 0 + for group in self: + repetitions += group[SynchParam.Repeats] + return repetitions + + @property + def integration_time(self): + return self._get_param(SynchParam.Active) + + @property + def total_time(self): + return self._get_param(SynchParam.Total) + + def _get_param(self, param, domain=SynchDomain.Time): + """ + Extract parameter from synchronization description and its groups. If + there is only one group in the synchronization then returns float + with the value. Otherwise a list of floats with different values. + + :param param: parameter type + :type param: :class:`~sardana.pool.pooldefs.SynchParam` + :param domain: domain + :type param: :class:`~sardana.pool.pooldefs.SynchDomain` + :return: parameter value(s) + :rtype float or [float] + """ + + if len(self) == 1: + return self[0][param][domain] + + values = [] + for group in self: + value = group[param][domain] + repeats = group[SynchParam.Repeats] + values += [value] * repeats + return values + + class PoolSynchronization(PoolAction): '''Action class responsible for trigger/gate generation ''' From 72fc3bc19d4a47d9abbcd5e275a24ceb5b29e879 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Sat, 29 Sep 2018 00:52:18 +0200 Subject: [PATCH 121/652] Add implementation chapter --- doc/source/sep/SEP18.md | 49 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index e0d95ee7dd..23264e1a90 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -58,5 +58,50 @@ Design * Per acquisition preparation with repetitions=1 e.g. Load(One|All) 6. Modify acquisition actions (and synchronization action if necessary) so they support the new concepts added in points 2 and 4. -5. Extend GSF (step mode) with measurement preparation (repetitions=n) if -possible i.e. scan macro knows beforehand the number of points. +5. *Extend Generic Scan Framework* (GSF), more preciselly scan in step mode +with measurement preparation (repetitions=n) if possible i.e. scan macro knows +beforehand the number of points. + +Implementation +-------------- + +Measurement group is extended by the *prepare* command with two parameters: +synchronization description and number of repeats (these repeats is a +different concept then the one from the synchronization description). The +second one indicates how many times measurement group will be started, with +the *start* command, to measure according to the synchronization description. + +1. Measurement group - Tango device class + * Add `Prepare` command. TODO: investigate the best way to pass + synchronization description, as JSON serialized string, together with the + repeats integer. + * Remove `synchronization` attribute (experimental API) - no backwards + compatibility. +2. Measurement group - core class + * Add `prepare(synchronization, repeats=1)` method + * Remove `synchronization` property (experimental API) - no backwards + compatibility. +3. Measurement group - Taurus extension + * Add `prepare` method which simply maps to `Prepare` Tango command + * Add `acquire` method according to the following pseudo code: + * `Start()` + * `waitFinish()` + * Implement `count` method according to the following pseudo code: + * `prepare(synchronization & repeats = 1)` where synchronization + contains the integration time + * `acquire()` + * Implement `count_continuous` (previous `measure`) method according to + the following pseudo code: + * `prepare(synchronization & repeats = 1)` where synchronization may + contain the continuous acquisition description + * `subscribeValueBuffer()` + * `acquire()` + * `unsubscribeValueBuffer()` +4. GSF - step scan + * `SScan` implemented according to the following pseudo code: + * If number of points is known: + * `prepare(synchronization, repeats=n)` where synchronization + contains the integration time and n means number of points + * `for step in range(n): acquire()` + * If number of points is unknown: + * `while new_step: acquire()` From f1af662c707e1149a652e4a0ecaa358f9a896237 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 26 Sep 2018 17:57:15 +0200 Subject: [PATCH 122/652] Add Preparable controller interface --- src/sardana/pool/controller.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index 6b948902fb..f96dd2fcf8 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -655,6 +655,28 @@ def ReadOne(self, axis): raise NotImplementedError("ReadOne must be defined in the controller") +class Preparable(object): + """A Preparable interface. A controller for which its axis are + 'pareparable' for a measurement (like a counter, 1D or 2D for example) + should implement this interface + + .. note: Do not inherit directly from Preparable.""" + + def PrepareOne(self, axis, value, repetitions): + """**Controller API**. Override if necessary. + Called to load the integration time / monitor value and number of + repetitions. + Default implementation does nothing. + + :param int axis: axis number + :param float value: integration time /monitor value + :param int repetitions: number of repetitions + :param float value: integration time /monitor value + """ + raise NotImplementedError("PrepareOne must be defined in the " + "controller") + + class Loadable(object): """A Loadable interface. A controller for which it's axis are 'loadable' (like a counter, 1D or 2D for example) should implement this interface From 8140e23fbb66051463f9c39cfe23b92bfefcbf20 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 26 Sep 2018 18:02:41 +0200 Subject: [PATCH 123/652] Use Preparable interface for C/T, 1D and 2D controllers --- src/sardana/pool/controller.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index f96dd2fcf8..65c5aa762a 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -891,7 +891,8 @@ def DefinePosition(self, axis, position): pass -class CounterTimerController(Controller, Readable, Startable, Stopable, Loadable): +class CounterTimerController(Controller, Readable, Startable, Stopable, + Loadable, Preparable): """Base class for a counter/timer controller. Inherit from this class to implement your own counter/timer controller for the device pool. @@ -1054,7 +1055,8 @@ def AbortOne(self, axis): pass -class OneDController(Controller, Readable, Startable, Stopable, Loadable): +class OneDController(Controller, Readable, Startable, Stopable, Loadable, + Preparable): """Base class for a 1D controller. Inherit from this class to implement your own 1D controller for the device pool. @@ -1092,7 +1094,8 @@ def GetAxisPar(self, axis, parameter): return self.GetPar(axis, parameter) -class TwoDController(Controller, Readable, Startable, Stopable, Loadable): +class TwoDController(Controller, Readable, Startable, Stopable, Loadable, + Preparable): """Base class for a 2D controller. Inherit from this class to implement your own 2D controller for the device pool.""" From a93101517411e2d49d44d4b2d8c037c4728c8f4d Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 27 Sep 2018 16:44:16 +0200 Subject: [PATCH 124/652] Remove integration time / monitor counts from PrepareOne --- src/sardana/pool/controller.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index 65c5aa762a..ebafa22bf6 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -662,14 +662,12 @@ class Preparable(object): .. note: Do not inherit directly from Preparable.""" - def PrepareOne(self, axis, value, repetitions): + def PrepareOne(self, axis, repetitions): """**Controller API**. Override if necessary. - Called to load the integration time / monitor value and number of - repetitions. + Called to load the number of repetitions. Default implementation does nothing. :param int axis: axis number - :param float value: integration time /monitor value :param int repetitions: number of repetitions :param float value: integration time /monitor value """ From dbebd400f4e4fc5e04a8885da7146700fdc9c735 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 27 Sep 2018 16:44:42 +0200 Subject: [PATCH 125/652] Make PrepareOne implementation optional --- src/sardana/pool/controller.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index ebafa22bf6..e441e44c29 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -671,8 +671,7 @@ def PrepareOne(self, axis, repetitions): :param int repetitions: number of repetitions :param float value: integration time /monitor value """ - raise NotImplementedError("PrepareOne must be defined in the " - "controller") + pass class Loadable(object): From 2ef1b06de9ebd257d1687e8f980ce3f3f2e68595 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 1 Oct 2018 12:27:55 +0200 Subject: [PATCH 126/652] Add MGConfiguration class --- src/sardana/pool/poolmeasurementgroup.py | 380 +++++++++++++++++++++++ 1 file changed, 380 insertions(+) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 0ad982b431..796aba6cf3 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -31,6 +31,7 @@ __docformat__ = 'restructuredtext' import threading +import weakref try: from taurus.core.taurusvalidator import AttributeNameValidator as\ @@ -122,6 +123,385 @@ def _to_fqdn(name, logger=None): return full_name +class MGConfiguration(object): + + DFT_DESC = 'General purpose measurement group' + + def __init__(self, mg): + self._mg = weakref.ref(mg)() + self._config = None + self.use_fqdn = True + # list of controller with channels enabled. + self.enabled_ctrls = [] + # dict with channel and its acquisition synchronization + # key: PoolBaseChannel; value: AcqSynch + self.channel_to_acq_synch = {} + # dict with controller and its acquisition synchronization + # key: PoolController; value: AcqSynch + self.ctrl_to_acq_synch = {} + + def __check_config(func): + def wrapper(self, *args, **kwargs): + if self._config is None: + raise RuntimeError('The configuration is empty.') + return func(self, *args, **kwargs) + return wrapper + + def __getitem__(self, item): + return self._config.__getitem__(item) + + @property + @__check_config + def timer(self): + return self._config['timer'] + + @property + @__check_config + def monitor(self): + return self._config['monitor'] + + @property + @__check_config + def controllers(self): + return self._config['controllers'] + + @property + @__check_config + def configuration(self): + return self._config + + @configuration.setter + def configuration(self, config=None): + self._build_configuration(config) + + def set_configuration_from_user(self, cfg, to_fqdn=True): + config = {} + user_elements = self._mg.get_user_elements() + pool = self._mg.pool + if len(user_elements) == 0: + # All timers were disabled + default_timer = None + else: + default_timer = user_elements[0].full_name + + timer_name = cfg.get('timer', default_timer) + monitor_name = cfg.get('monitor', default_timer) + if to_fqdn: + timer_name = _to_fqdn(timer_name, logger=self._mg) + config['timer'] = pool.get_element_by_full_name(timer_name) + if to_fqdn: + monitor_name = _to_fqdn(monitor_name, logger=self._mg) + config['monitor'] = pool.get_element_by_full_name(monitor_name) + config['controllers'] = controllers = {} + + for c_name, c_data in cfg['controllers'].items(): + # backwards compatibility for measurement groups created before + # implementing feature-372: + # https://sourceforge.net/p/sardana/tickets/372/ + # WARNING: this is one direction backwards compatibility - it just + # reads channels from the units, but does not write channels to the + # units back + if 'units' in c_data: + c_data = c_data['units']['0'] + # discard controllers which don't have items (garbage) + ch_count = len(c_data['channels']) + if ch_count == 0: + continue + + external = c_name.startswith('__') + if external: + ctrl = c_name + else: + if to_fqdn: + c_name = _to_fqdn(c_name, logger=self._mg) + ctrl = pool.get_element_by_full_name(c_name) + assert ctrl.get_type() == ElementType.Controller + controllers[ctrl] = ctrl_data = {} + + # exclude external and not timerable elements + if not external and ctrl.is_timerable(): + timer_name = c_data['timer'] + if to_fqdn: + timer_name = _to_fqdn(timer_name, logger=self._mg) + timer = pool.get_element_by_full_name(timer_name) + ctrl_data['timer'] = timer + monitor_name = c_data['monitor'] + if to_fqdn: + monitor_name = _to_fqdn(monitor_name, logger=self._mg) + monitor = pool.get_element_by_full_name(monitor_name) + ctrl_data['monitor'] = monitor + synchronizer = c_data.get('synchronizer') + # for backwards compatibility purposes + # protect measurement groups without synchronizer defined + if synchronizer is None: + synchronizer = 'software' + elif synchronizer != 'software': + if to_fqdn: + synchronizer = _to_fqdn(synchronizer, logger=self._mg) + synchronizer = pool.get_element_by_full_name(synchronizer) + ctrl_data['synchronizer'] = synchronizer + try: + synchronization = c_data['synchronization'] + except KeyError: + # backwards compatibility for configurations before SEP6 + synchronization = c_data['trigger_type'] + msg = ("trigger_type configuration parameter is deprecated" + " in favor of synchronization. Re-apply " + "configuration in order to upgrade.") + self._mg.warning(msg) + ctrl_data['synchronization'] = synchronization + ctrl_data['channels'] = channels = {} + for ch_name, ch_data in c_data['channels'].items(): + if external: + validator = TangoAttributeNameValidator() + params = validator.getParams(ch_data['full_name']) + params['pool'] = self._mg.pool + channel = PoolExternalObject(**params) + else: + if to_fqdn: + ch_name = _to_fqdn(ch_name, logger=self._mg) + channel = pool.get_element_by_full_name(ch_name) + channels[channel] = dict(ch_data) + + config['label'] = cfg.get('label', self._mg.name) + config['description'] = cfg.get('description', self.DFT_DESC) + self.use_fqdn = to_fqdn + self._build_configuration(config) + + def get_configuration_for_user(self): + cfg = self._config + config = {} + + config['timer'] = cfg['timer'].full_name + config['monitor'] = cfg['monitor'].full_name + config['controllers'] = controllers = {} + + for c, c_data in cfg['controllers'].items(): + ctrl_name = c + if not isinstance(c, (str, unicode)): + ctrl_name = c.full_name + external = ctrl_name.startswith('__') + controllers[ctrl_name] = ctrl_data = {} + if not external and c.is_timerable(): + if 'timer' in c_data: + ctrl_data['timer'] = c_data['timer'].full_name + if 'monitor' in c_data: + ctrl_data['monitor'] = c_data['monitor'].full_name + if 'synchronizer' in c_data: + synchronizer = c_data['synchronizer'] + if synchronizer != 'software': + synchronizer = synchronizer.full_name + ctrl_data['synchronizer'] = synchronizer + if 'synchronization' in c_data: + ctrl_data['synchronization'] = c_data['synchronization'] + ctrl_data['channels'] = channels = {} + for ch, ch_data in c_data['channels'].items(): + channels[ch.full_name] = dict(ch_data) + + config['label'] = cfg['label'] + config['description'] = cfg['description'] + return config + + def _build_channel_defaults(self, channel_data, channel): + """ + Fills the channel default values for the given channel dictionary + """ + + external_from_name = isinstance(channel, (str, unicode)) + ndim = None + if external_from_name: + name = full_name = source = channel + ndim = 0 # TODO: this should somehow verify the dimension + else: + name = channel.name + full_name = channel.full_name + source = channel.get_source() + ndim = None + ctype = channel.get_type() + if ctype == ElementType.CTExpChannel: + ndim = 0 + elif ctype == ElementType.PseudoCounter: + ndim = 0 + elif ctype == ElementType.ZeroDExpChannel: + ndim = 0 + elif ctype == ElementType.OneDExpChannel: + ndim = 1 + elif ctype == ElementType.TwoDExpChannel: + ndim = 2 + elif ctype == ElementType.External: + config = channel.get_config() + if config is not None: + ndim = int(config.data_format) + elif ctype == ElementType.IORegister: + ndim = 0 + + # Definitively should be initialized by measurement group + # index MUST be here already (asserting this in the following line) + channel_data['index'] = channel_data['index'] + channel_data['name'] = channel_data.get('name', name) + channel_data['full_name'] = channel_data.get('full_name', full_name) + channel_data['source'] = channel_data.get('source', source) + channel_data['enabled'] = channel_data.get('enabled', True) + channel_data['label'] = channel_data.get('label', channel_data['name']) + channel_data['ndim'] = ndim + # Probably should be initialized by measurement group + channel_data['output'] = channel_data.get('output', True) + + # Perhaps should NOT be initialized by measurement group + channel_data['plot_type'] = channel_data.get('plot_type', PlotType.No) + channel_data['plot_axes'] = channel_data.get('plot_axes', []) + channel_data['conditioning'] = channel_data.get('conditioning', '') + channel_data['normalization'] = channel_data.get( + 'normalization', Normalization.No) + + return channel_data + + def _build_configuration(self, config=None): + """Builds a configuration object from the list of elements""" + if config is None: + config = {} + user_elements = self._mg.get_user_elements() + ctrls = self._mg.get_pool_controllers() + + # find the first CT + first_timerable = None + for elem in user_elements: + if elem.get_type() in TYPE_TIMERABLE_ELEMENTS: + first_timerable = elem + break + if first_timerable is None: + raise Exception("It is not possible to construct a " + "measurement group without at least one " + "timer able channel (Counter/timer, 1D or 2D)") + g_timer = g_monitor = first_timerable + config['timer'] = g_timer + config['monitor'] = g_monitor + config['controllers'] = controllers = {} + + external_user_elements = [] + self.enabled_ctrls = [] + for index, element in enumerate(user_elements): + elem_type = element.get_type() + if elem_type == ElementType.External: + external_user_elements.append((index, element)) + continue + + ctrl = element.controller + ctrl_data = controllers.get(ctrl) + # include all controller in the enabled list + self.enabled_ctrls.append(ctrl) + if ctrl_data is None: + controllers[ctrl] = ctrl_data = {} + ctrl_data['channels'] = channels = {} + if elem_type in TYPE_TIMERABLE_ELEMENTS: + elements = ctrls[ctrl] + if g_timer in elements: + ctrl_data['timer'] = g_timer + else: + ctrl_data['timer'] = elements[0] + if g_monitor in elements: + ctrl_data['monitor'] = g_monitor + else: + ctrl_data['monitor'] = elements[0] + ctrl_data['synchronization'] = AcqSynchType.Trigger + ctrl_data['synchronizer'] = 'software' + self.ctrl_to_acq_synch[ctrl] = AcqSynch.SoftwareTrigger + self.channel_to_acq_synch[ + element] = AcqSynch.SoftwareTrigger + else: + channels = ctrl_data['channels'] + channels[element] = channel_data = {} + channel_data['index'] = user_elements.index(element) + channel_data = self._build_channel_defaults(channel_data, + element) + config['label'] = self._mg.name + config['description'] = self.DFT_DESC + + if len(external_user_elements) > 0: + controllers['__tango__'] = ctrl_data = {} + ctrl_data['channels'] = channels = {} + for index, element in external_user_elements: + channels[element] = channel_data = {} + channel_data['index'] = index + channel_data = self._build_channel_defaults(channel_data, + element) + else: + # create a configuration based on a new configuration + self.enabled_ctrls = [] + user_elem_ids = {} + tg_elem_ids = [] + pool = self._mg.pool + for c, c_data in config['controllers'].items(): + synchronizer = c_data.get('synchronizer') + acq_synch_type = c_data.get('synchronization') + software = synchronizer == 'software' + external = isinstance(c, (str, unicode)) + # only timerable elements are configured with acq_synch + acq_synch = None + ctrl_enabled = False + ctrl_to_acq_synch = False + if not external and c.is_timerable(): + acq_synch = AcqSynch.from_synch_type( + software, acq_synch_type) + for channel_data in c_data['channels'].values(): + if external: + element = _id = channel_data['full_name'] + channel_data['source'] = _id + else: + full_name = channel_data['full_name'] + if self.use_fqdn: + full_name = _to_fqdn(full_name, logger=self._mg) + element = pool.get_element_by_full_name(full_name) + _id = element.id + channel_data = self._build_channel_defaults( + channel_data, element) + if channel_data["enabled"]: + ctrl_enabled = True + if acq_synch is not None: + ctrl_to_acq_synch = True + self.channel_to_acq_synch[element] = acq_synch + if not software: + tg_elem_ids.append(synchronizer.id) + user_elem_ids[channel_data['index']] = _id + + if ctrl_to_acq_synch: + self.ctrl_to_acq_synch[c] = acq_synch + if ctrl_enabled: + self.enabled_ctrls.append(c) + + # sorted ids may not be consecutive (if a channel is disabled) + indexes = sorted(user_elem_ids.keys()) + user_elem_ids_list = [user_elem_ids[idx] for idx in indexes] + user_elem_ids_list.extend(tg_elem_ids) + self._mg.set_user_element_ids(user_elem_ids_list) + + g_timer, g_monitor = config['timer'], config['monitor'] + + timer_ctrl_data = config['controllers'][g_timer.controller] + if timer_ctrl_data['timer'] != g_timer: + self._mg.warning('controller timer and global timer ' + 'mismatch. Using global timer') + self._mg.debug('For controller %s, timer is defined as ' + 'channel %s. The global timer is set to ' + 'channel %s which belongs to the same ' + 'controller', g_timer.controller.name, + timer_ctrl_data['timer'].name, g_timer.name) + timer_ctrl_data['timer'] = g_timer + + monitor_ctrl_data = config['controllers'][g_monitor.controller] + if monitor_ctrl_data['monitor'] != g_monitor: + self._mg.warning('controller monitor and global ' + 'monitor mismatch. Using global monitor') + self._mg.debug('For controller %s, monitor is defined as ' + 'channel %s. The global timer is set to ' + 'channel %s which belongs to the same ' + 'controller', g_monitor.controller.name, + monitor_ctrl_data['monitor'].name, + g_monitor.name) + monitor_ctrl_data['monitor'] != g_monitor + self._config = config + + class PoolMeasurementGroup(PoolGroupElement): DFT_DESC = 'General purpose measurement group' From 75b4cfc49e2cfa6daa233b9742fa5d0d50d6d329 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 1 Oct 2018 12:29:50 +0200 Subject: [PATCH 127/652] Adapt to use MGConfiguration --- src/sardana/pool/poolmeasurementgroup.py | 356 ++--------------------- 1 file changed, 21 insertions(+), 335 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 796aba6cf3..9143ee1569 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -504,14 +504,12 @@ def _build_configuration(self, config=None): class PoolMeasurementGroup(PoolGroupElement): - DFT_DESC = 'General purpose measurement group' - def __init__(self, **kwargs): self._state_lock = threading.Lock() self._monitor_count = None self._repetitions = 1 self._acquisition_mode = AcqMode.Timer - self._config = None + self._config = MGConfiguration(self) self._config_dirty = True self._moveable = None self._moveable_obj = None @@ -519,24 +517,17 @@ def __init__(self, **kwargs): self._sw_synch_initial_domain = SynchDomain.Position self._synchronization = [] - # dict with channel and its acquisition synchronization - # key: PoolBaseChannel; value: AcqSynch - self._channel_to_acq_synch = {} - # dict with controller and its acquisition synchronization - # key: PoolController; value: AcqSynch - self._ctrl_to_acq_synch = {} - # list of controller with channels enabled. - self._enabled_ctrls = [] + kwargs['elem_type'] = ElementType.MeasurementGroup PoolGroupElement.__init__(self, **kwargs) configuration = kwargs.get("configuration") self.set_configuration(configuration) # if the configuration was never "really" written e.g. newly created MG - # just sets it now so the _channe_to_acq_synch and _ctrl_to_acq_synch + # just sets it now so the _channe_to_acq_synch and ctrl_to_acq_synch # are properly populated # TODO: make it more elegant if configuration is None: - configuration = self.get_configuration() + configuration = self.configuration.configuration self.set_configuration(configuration, propagate=0, to_fqdn=False) def _create_action_cache(self): @@ -592,344 +583,39 @@ def _is_managed_element(self, element): return (element_type in TYPE_EXP_CHANNEL_ELEMENTS or element_type is ElementType.TriggerGate) - """Fills the channel default values for the given channel dictionary""" - - def _build_channel_defaults(self, channel_data, channel): - - external_from_name = isinstance(channel, (str, unicode)) - ndim = None - if external_from_name: - name = full_name = source = channel - ndim = 0 # TODO: this should somehow verify the dimension - else: - name = channel.name - full_name = channel.full_name - source = channel.get_source() - ndim = None - ctype = channel.get_type() - if ctype == ElementType.CTExpChannel: - ndim = 0 - elif ctype == ElementType.PseudoCounter: - ndim = 0 - elif ctype == ElementType.ZeroDExpChannel: - ndim = 0 - elif ctype == ElementType.OneDExpChannel: - ndim = 1 - elif ctype == ElementType.TwoDExpChannel: - ndim = 2 - elif ctype == ElementType.External: - config = channel.get_config() - if config is not None: - ndim = int(config.data_format) - elif ctype == ElementType.IORegister: - ndim = 0 - - # Definitively should be initialized by measurement group - # index MUST be here already (asserting this in the following line) - channel_data['index'] = channel_data['index'] - channel_data['name'] = channel_data.get('name', name) - channel_data['full_name'] = channel_data.get('full_name', full_name) - channel_data['source'] = channel_data.get('source', source) - channel_data['enabled'] = channel_data.get('enabled', True) - channel_data['label'] = channel_data.get('label', channel_data['name']) - channel_data['ndim'] = ndim - # Probably should be initialized by measurement group - channel_data['output'] = channel_data.get('output', True) - - # Perhaps should NOT be initialized by measurement group - channel_data['plot_type'] = channel_data.get('plot_type', PlotType.No) - channel_data['plot_axes'] = channel_data.get('plot_axes', []) - channel_data['conditioning'] = channel_data.get('conditioning', '') - channel_data['normalization'] = channel_data.get( - 'normalization', Normalization.No) - - return channel_data - - def _build_configuration(self): - """Builds a configuration object from the list of elements""" - config = {} - user_elements = self.get_user_elements() - ctrls = self.get_pool_controllers() - - # find the first CT - first_timerable = None - for elem in user_elements: - if elem.get_type() in TYPE_TIMERABLE_ELEMENTS: - first_timerable = elem - break - if first_timerable is None: - raise Exception("It is not possible to construct a measurement " - "group without at least one timer able channel " - "(Counter/timer, 1D or 2D)") - g_timer = g_monitor = first_timerable - config['timer'] = g_timer - config['monitor'] = g_monitor - config['controllers'] = controllers = {} - - external_user_elements = [] - self._enabled_ctrls = [] - for index, element in enumerate(user_elements): - elem_type = element.get_type() - if elem_type == ElementType.External: - external_user_elements.append((index, element)) - continue - - ctrl = element.controller - ctrl_data = controllers.get(ctrl) - # include all controller in the enabled list - self._enabled_ctrls.append(ctrl) - if ctrl_data is None: - controllers[ctrl] = ctrl_data = {} - ctrl_data['channels'] = channels = {} - if elem_type in TYPE_TIMERABLE_ELEMENTS: - elements = ctrls[ctrl] - if g_timer in elements: - ctrl_data['timer'] = g_timer - else: - ctrl_data['timer'] = elements[0] - if g_monitor in elements: - ctrl_data['monitor'] = g_monitor - else: - ctrl_data['monitor'] = elements[0] - ctrl_data['synchronization'] = AcqSynchType.Trigger - ctrl_data['synchronizer'] = 'software' - self._ctrl_to_acq_synch[ctrl] = AcqSynch.SoftwareTrigger - self._channel_to_acq_synch[ - element] = AcqSynch.SoftwareTrigger - else: - channels = ctrl_data['channels'] - channels[element] = channel_data = {} - channel_data['index'] = user_elements.index(element) - channel_data = self._build_channel_defaults(channel_data, element) - config['label'] = self.name - config['description'] = self.DFT_DESC - - if len(external_user_elements) > 0: - controllers['__tango__'] = ctrl_data = {} - ctrl_data['channels'] = channels = {} - for index, element in external_user_elements: - channels[element] = channel_data = {} - channel_data['index'] = index - channel_data = self._build_channel_defaults( - channel_data, element) - return config + @property + def configuration(self): + return self._config def set_configuration(self, config=None, propagate=1, to_fqdn=True): - self._enabled_ctrls = [] - if config is None: - config = self._build_configuration() - else: - # create a configuration based on a new configuration - user_elem_ids = {} - tg_elem_ids = [] - pool = self.pool - for c, c_data in config['controllers'].items(): - synchronizer = c_data.get('synchronizer') - acq_synch_type = c_data.get('synchronization') - software = synchronizer == 'software' - external = isinstance(c, (str, unicode)) - # only timerable elements are configured with acq_synch - acq_synch = None - ctrl_enabled = False - ctrl_to_acq_synch = False - if not external and c.is_timerable(): - acq_synch = AcqSynch.from_synch_type( - software, acq_synch_type) - for channel_data in c_data['channels'].values(): - if external: - element = _id = channel_data['full_name'] - channel_data['source'] = _id - else: - full_name = channel_data['full_name'] - if to_fqdn: - full_name = _to_fqdn(full_name, logger=self) - element = pool.get_element_by_full_name(full_name) - _id = element.id - channel_data = self._build_channel_defaults( - channel_data, element) - if channel_data["enabled"]: - ctrl_enabled = True - if acq_synch is not None: - ctrl_to_acq_synch = True - self._channel_to_acq_synch[element] = acq_synch - if not software: - tg_elem_ids.append(synchronizer.id) - user_elem_ids[channel_data['index']] = _id - - if ctrl_to_acq_synch: - self._ctrl_to_acq_synch[c] = acq_synch - if ctrl_enabled: - self._enabled_ctrls.append(c) - - # sorted ids may not be consecutive (if a channel is disabled) - indexes = sorted(user_elem_ids.keys()) - user_elem_ids_list = [user_elem_ids[idx] for idx in indexes] - user_elem_ids_list.extend(tg_elem_ids) - self.set_user_element_ids(user_elem_ids_list) - - g_timer, g_monitor = config['timer'], config['monitor'] - - timer_ctrl_data = config['controllers'][g_timer.controller] - if timer_ctrl_data['timer'] != g_timer: - self.warning('controller timer and global timer mismatch. ' - 'Using global timer') - self.debug('For controller %s, timer is defined as channel %s. ' - 'The global timer is set to channel %s which belongs ' - 'to the same controller', g_timer.controller.name, - timer_ctrl_data['timer'].name, g_timer.name) - timer_ctrl_data['timer'] = g_timer - - monitor_ctrl_data = config['controllers'][g_monitor.controller] - if monitor_ctrl_data['monitor'] != g_monitor: - self.warning('controller monitor and global monitor mismatch. ' - 'Using global monitor') - self.debug('For controller %s, monitor is defined as channel %s. ' - 'The global timer is set to channel %s which belongs ' - 'to the same controller', g_monitor.controller.name, - monitor_ctrl_data['monitor'].name, g_monitor.name) - monitor_ctrl_data['monitor'] != g_monitor - - self._config = config + self._config.use_fqdn = to_fqdn + self._config.configuration = config self._config_dirty = True if not propagate: return self.fire_event(EventType("configuration", priority=propagate), config) def set_configuration_from_user(self, cfg, propagate=1, to_fqdn=True): - config = {} - user_elements = self.get_user_elements() - pool = self.pool - timer_name = cfg.get('timer', user_elements[0].full_name) - monitor_name = cfg.get('monitor', user_elements[0].full_name) - if to_fqdn: - timer_name = _to_fqdn(timer_name, logger=self) - config['timer'] = pool.get_element_by_full_name(timer_name) - if to_fqdn: - monitor_name = _to_fqdn(monitor_name, logger=self) - config['monitor'] = pool.get_element_by_full_name(monitor_name) - config['controllers'] = controllers = {} - - for c_name, c_data in cfg['controllers'].items(): - # backwards compatibility for measurement groups created before - # implementing feature-372: - # https://sourceforge.net/p/sardana/tickets/372/ - # WARNING: this is one direction backwards compatibility - it just - # reads channels from the units, but does not write channels to the - # units back - if 'units' in c_data: - c_data = c_data['units']['0'] - # discard controllers which don't have items (garbage) - ch_count = len(c_data['channels']) - if ch_count == 0: - continue - - external = c_name.startswith('__') - if external: - ctrl = c_name - else: - if to_fqdn: - c_name = _to_fqdn(c_name, logger=self) - ctrl = pool.get_element_by_full_name(c_name) - assert ctrl.get_type() == ElementType.Controller - controllers[ctrl] = ctrl_data = {} - - # exclude external and not timerable elements - if not external and ctrl.is_timerable(): - timer_name = c_data['timer'] - if to_fqdn: - timer_name = _to_fqdn(timer_name, logger=self) - timer = pool.get_element_by_full_name(timer_name) - ctrl_data['timer'] = timer - monitor_name = c_data['monitor'] - if to_fqdn: - monitor_name = _to_fqdn(monitor_name, logger=self) - monitor = pool.get_element_by_full_name(monitor_name) - ctrl_data['monitor'] = monitor - synchronizer = c_data.get('synchronizer') - # for backwards compatibility purposes - # protect measurement groups without synchronizer defined - if synchronizer is None: - synchronizer = 'software' - elif synchronizer != 'software': - if to_fqdn: - synchronizer = _to_fqdn(synchronizer, logger=self) - synchronizer = pool.get_element_by_full_name(synchronizer) - ctrl_data['synchronizer'] = synchronizer - try: - synchronization = c_data['synchronization'] - except KeyError: - # backwards compatibility for configurations before SEP6 - synchronization = c_data['trigger_type'] - msg = ("trigger_type configuration parameter is deprecated" - " in favor of synchronization. Re-apply " - "configuration in order to upgrade.") - self.warning(msg) - ctrl_data['synchronization'] = synchronization - ctrl_data['channels'] = channels = {} - for ch_name, ch_data in c_data['channels'].items(): - if external: - validator = TangoAttributeNameValidator() - params = validator.getParams(ch_data['full_name']) - params['pool'] = self.pool - channel = PoolExternalObject(**params) - else: - if to_fqdn: - ch_name = _to_fqdn(ch_name, logger=self) - channel = pool.get_element_by_full_name(ch_name) - channels[channel] = dict(ch_data) - - config['label'] = cfg.get('label', self.name) - config['description'] = cfg.get('description', self.DFT_DESC) - - self.set_configuration(config, propagate=propagate, to_fqdn=to_fqdn) - - def get_configuration(self): - return self._config + self._config.set_configuration_from_user(cfg, to_fqdn) + self._config_dirty = True + if not propagate: + return + self.fire_event(EventType("configuration", priority=propagate), + self._config.configuration) def get_user_configuration(self): - cfg = self.get_configuration() - config = {} - - config['timer'] = cfg['timer'].full_name - config['monitor'] = cfg['monitor'].full_name - config['controllers'] = controllers = {} - - for c, c_data in cfg['controllers'].items(): - ctrl_name = c - if not isinstance(c, (str, unicode)): - ctrl_name = c.full_name - external = ctrl_name.startswith('__') - controllers[ctrl_name] = ctrl_data = {} - if not external and c.is_timerable(): - if 'timer' in c_data: - ctrl_data['timer'] = c_data['timer'].full_name - if 'monitor' in c_data: - ctrl_data['monitor'] = c_data['monitor'].full_name - if 'synchronizer' in c_data: - synchronizer = c_data['synchronizer'] - if synchronizer != 'software': - synchronizer = synchronizer.full_name - ctrl_data['synchronizer'] = synchronizer - if 'synchronization' in c_data: - ctrl_data['synchronization'] = c_data['synchronization'] - ctrl_data['channels'] = channels = {} - for ch, ch_data in c_data['channels'].items(): - channels[ch.full_name] = dict(ch_data) - - config['label'] = cfg['label'] - config['description'] = cfg['description'] - return config + return self._config.get_configuration_for_user() def load_configuration(self, force=False): """Loads the current configuration to all involved controllers""" - cfg = self.get_configuration() + # g_timer, g_monitor = cfg['timer'], cfg['monitor'] - for ctrl, ctrl_data in cfg['controllers'].items(): + for ctrl, ctrl_data in self._config.controllers.items(): if isinstance(ctrl, str): # skip external channels continue if not ctrl.is_online(): continue - if ctrl not in self._enabled_ctrls: + if ctrl not in self._config.enabled_ctrls: continue ctrl.set_ctrl_par('acquisition_mode', self.acquisition_mode) @@ -944,7 +630,7 @@ def load_configuration(self, force=False): # ctrl.set_ctrl_par('monitor', g_monitor.axis) ctrl.set_ctrl_par('timer', ctrl_data['timer'].axis) ctrl.set_ctrl_par('monitor', ctrl_data['monitor'].axis) - synchronization = self._ctrl_to_acq_synch.get(ctrl) + synchronization = self._config.ctrl_to_acq_synch.get(ctrl) self.debug('load_configuration: setting trigger_type: %s ' 'to ctrl: %s' % (synchronization, ctrl)) ctrl.set_ctrl_par('synchronization', synchronization) @@ -952,7 +638,7 @@ def load_configuration(self, force=False): self._config_dirty = False def get_timer(self): - return self.get_configuration()['timer'] + return self._config.timer timer = property(get_timer) From 64e9f96dd9e3690cf336f929cf5d2041732524ba Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 1 Oct 2018 12:51:03 +0200 Subject: [PATCH 128/652] Adapt PoolAcquisition --- src/sardana/pool/poolacquisition.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 63353ec383..1bfc2f3987 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -299,7 +299,8 @@ def _get_action_for_element(self, element): elem_type = element.get_type() if elem_type in TYPE_TIMERABLE_ELEMENTS: main_element = self.main_element - channel_to_acq_synch = main_element._channel_to_acq_synch + channel_to_acq_synch = \ + main_element.configuration.channel_to_acq_synch acq_synch = channel_to_acq_synch.get(element) if acq_synch in (AcqSynch.SoftwareTrigger, AcqSynch.SoftwareGate): From 706fae20a86d83208d7dc722ca450e87f4cf69de Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 1 Oct 2018 15:21:02 +0200 Subject: [PATCH 129/652] Rename acquire to count_single --- doc/source/sep/SEP18.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 23264e1a90..f6ae6a96eb 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -83,25 +83,27 @@ the *start* command, to measure according to the synchronization description. compatibility. 3. Measurement group - Taurus extension * Add `prepare` method which simply maps to `Prepare` Tango command - * Add `acquire` method according to the following pseudo code: + * Add `count_single` (TODO: find the best name for this + method, other candidates are `count_raw`, `acquire`) method according to + the following pseudo code: * `Start()` * `waitFinish()` * Implement `count` method according to the following pseudo code: * `prepare(synchronization & repeats = 1)` where synchronization contains the integration time - * `acquire()` + * `count_single()` * Implement `count_continuous` (previous `measure`) method according to the following pseudo code: * `prepare(synchronization & repeats = 1)` where synchronization may contain the continuous acquisition description * `subscribeValueBuffer()` - * `acquire()` + * `count_single()` * `unsubscribeValueBuffer()` 4. GSF - step scan * `SScan` implemented according to the following pseudo code: * If number of points is known: * `prepare(synchronization, repeats=n)` where synchronization contains the integration time and n means number of points - * `for step in range(n): acquire()` + * `for step in range(n): count_single()` * If number of points is unknown: - * `while new_step: acquire()` + * `while new_step: count()` From f57d0be0893b3c44146980e302f166c85023158b Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 1 Oct 2018 15:25:58 +0200 Subject: [PATCH 130/652] Add controllers implementation --- doc/source/sep/SEP18.md | 133 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index f6ae6a96eb..655afc58f5 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -65,6 +65,8 @@ beforehand the number of points. Implementation -------------- +### Measurement Group + Measurement group is extended by the *prepare* command with two parameters: synchronization description and number of repeats (these repeats is a different concept then the one from the synchronization description). The @@ -107,3 +109,134 @@ the *start* command, to measure according to the synchronization description. * `for step in range(n): count_single()` * If number of points is unknown: * `while new_step: count()` + * `CTScan` does not require changes, it simply calls `count_continuous` + +### Controllers + +C/T, 1D and 2D controllers (plugins) API is extended. TODO: Choose between +the following options: + +#### Option 1 + +* Add `Preparable` interface with `PrepareOne(axis, starts)` method` +* Make C/T, 1D and 2D controllers inherit from this interface +* Add extra argument to `LoadOne`, etc. methods of the `Loadable` interface +`latency_time`: `LoadOne(axis, integ_time, repeats, latency_time)` + +This option maintains backwards compatibility. + +The following examples demonstrates the sequence of calls (only the ones +relevant to the SEP18) of one channel (axis 1) involved in the given +acquisition. This channel is at the same time the timer. + +* **step scan** 5 acquisitions x 0.1 s of integration time +```python +PrepareOne(1, 5) +for acquisition in range(5): + LoadOne(1, 0.1, 1, 0) + StartOne(1) +``` + +* **continuous scan (hw trigger)** 5 acquisitions x 0.1 s of integration +time and 0.05 s of latency time +```python +PrepareOne(1, 1) +LoadOne(1, 0.1, 5, 0.05) # latency time can be ignored +StartOne(1) +``` + +* **continuous scan (sw trigger)** +```python +PrepareOne(1, 5) +for trigger in range(5): + LoadOne(1, 0.1, 1, 0.05) # latency time can be ignored + StartOne(1) +``` + +* **continuous scan (hw gate)** +```python +PrepareOne(1, 1) +LoadOne(1, 0.1, 5, 0.05) # integration time and latency time can be ignored +StartOne(1) +``` + +* **continuous scan (sw gate)** +```python +PrepareOne(1, 5) +for gate in range(5): + LoadOne(1, 0.1, 1, 0.05) # integration time and latency time can be ignored + StartOne(1) +``` +* **continuous scan (hw start)** +```python +PrepareOne(1, 1) +LoadOne(1, 0.1, 5, 0.05) +StartOne(1) +``` + +* **continuous scan (sw start)** +```python +PrepareOne(1, 1) +LoadOne(1, 0.1, 5, 0.05) +StartOne(1) +``` + +#### Option 2 + +* Add extra arguments to `LoadOne`, etc. methods of the `Loadable` interface +`latency_time` and `starts` and switch the order of arguments so the API is: +`LoadOne(axis, integ_time, latency_time, repeats, starts)` +* Make the `LoadOne`, etc. be called only once, in the measurement group +prepare command, per measurement. + +This option **breaks** backwards compatibility. + +The following examples demonstrates the sequence of calls (only the ones +relevant to the SEP18) of one channel (axis 1) involved in the given +acquisition. This channel is at the same time the timer. + +* **step scan** 5 acquisitions x 0.1 s of integration time +```python +LoadOne(1, 0.1, 0, 1, 5) +for acquisition in range(5): + StartOne(1) +``` + +* **continuous scan (hw trigger)** 5 acquisitions x 0.1 s of integration +time and 0.05 s of latency time +```python +LoadOne(1, 0.1, 0.05, 5, 1) # latency time can be ignored +StartOne(1) +``` + +* **continuous scan (sw trigger)** +```python +LoadOne(1, 0.1, 0.05, 1, 5) # latency time can be ignored +for trigger in range(5): + StartOne(1) +``` + +* **continuous scan (hw gate)** +```python +LoadOne(1, 0.1, 0.05, 5, 1) # integration time and latency time can be ignored +StartOne(1) +``` + +* **continuous scan (sw gate)** +```python +LoadOne(1, 0.1, 0.05, 1, 5) # integration time and latency time can be ignored +for gate in range(5): + StartOne(1) +``` + +* **continuous scan (hw start)** +```python +LoadOne(1, 0.1, 0.05, 5, 1) +StartOne(1) +``` + +* **continuous scan (sw start)** +```python +LoadOne(1, 0.1, 0.05, 5, 1) +StartOne(1) +``` From 82bfe477d5745d1f0b13d3354f2da246ab7811b6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 1 Oct 2018 15:41:52 +0200 Subject: [PATCH 131/652] Rename repeats to start --- doc/source/sep/SEP18.md | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 655afc58f5..212ad1c0a2 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -67,21 +67,20 @@ Implementation ### Measurement Group -Measurement group is extended by the *prepare* command with two parameters: -synchronization description and number of repeats (these repeats is a -different concept then the one from the synchronization description). The -second one indicates how many times measurement group will be started, with -the *start* command, to measure according to the synchronization description. +Measurement group is extended by the *prepare* command with two parameters: +synchronization description and number of starts. The second one indicates +how many times measurement group will be started, with the *start* command, +to measure according to the synchronization description. 1. Measurement group - Tango device class * Add `Prepare` command. TODO: investigate the best way to pass - synchronization description, as JSON serialized string, together with the - repeats integer. - * Remove `synchronization` attribute (experimental API) - no backwards + synchronization description, as JSON serialized string, together with the + starts integer. + * Remove `synchronization` attribute (experimental API) - no backwards compatibility. 2. Measurement group - core class - * Add `prepare(synchronization, repeats=1)` method - * Remove `synchronization` property (experimental API) - no backwards + * Add `prepare(synchronization, starts=1)` method + * Remove `synchronization` property (experimental API) - no backwards compatibility. 3. Measurement group - Taurus extension * Add `prepare` method which simply maps to `Prepare` Tango command @@ -91,12 +90,12 @@ the *start* command, to measure according to the synchronization description. * `Start()` * `waitFinish()` * Implement `count` method according to the following pseudo code: - * `prepare(synchronization & repeats = 1)` where synchronization + * `prepare(synchronization & starts = 1)` where synchronization contains the integration time * `count_single()` - * Implement `count_continuous` (previous `measure`) method according to + * Implement `count_continuous` (previous `measure`) method according to the following pseudo code: - * `prepare(synchronization & repeats = 1)` where synchronization may + * `prepare(synchronization & starts = 1)` where synchronization may contain the continuous acquisition description * `subscribeValueBuffer()` * `count_single()` @@ -104,7 +103,7 @@ the *start* command, to measure according to the synchronization description. 4. GSF - step scan * `SScan` implemented according to the following pseudo code: * If number of points is known: - * `prepare(synchronization, repeats=n)` where synchronization + * `prepare(synchronization, start=n)` where synchronization contains the integration time and n means number of points * `for step in range(n): count_single()` * If number of points is unknown: From cbe7f3fa5f7186a4dbf82dca22d6e91f3c0c995d Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 1 Oct 2018 18:32:25 +0200 Subject: [PATCH 132/652] Move GSF to a separate chapter --- doc/source/sep/SEP18.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 212ad1c0a2..b1f0e22049 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -65,6 +65,18 @@ beforehand the number of points. Implementation -------------- +### GSF + +* `SScan` (step scan) implemented according to the following pseudo code: + * If number of points is known: + * `prepare(synchronization, start=n)` where synchronization + contains the integration time and n means number of points + * `for step in range(n): count_single()` + * If number of points is unknown: + * `while new_step: count()` +* `CTScan` (continuous scan) does not require changes, it simply calls +`count_continuous` + ### Measurement Group Measurement group is extended by the *prepare* command with two parameters: @@ -100,15 +112,6 @@ to measure according to the synchronization description. * `subscribeValueBuffer()` * `count_single()` * `unsubscribeValueBuffer()` -4. GSF - step scan - * `SScan` implemented according to the following pseudo code: - * If number of points is known: - * `prepare(synchronization, start=n)` where synchronization - contains the integration time and n means number of points - * `for step in range(n): count_single()` - * If number of points is unknown: - * `while new_step: count()` - * `CTScan` does not require changes, it simply calls `count_continuous` ### Controllers From d606dc086d30df2115f109fbe77a040e3206a125 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 3 Oct 2018 11:07:20 +0200 Subject: [PATCH 133/652] Add method to prepare acquisition variable Include variables for the acquisition actions. Implement methods to prepare the configuration for the acquisition actions. --- src/sardana/pool/poolmeasurementgroup.py | 78 +++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 0d5cd7e29f..f398532a51 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -132,6 +132,9 @@ def __init__(self, mg): self._mg = weakref.ref(mg)() self._config = None self.use_fqdn = True + self._init_data() + + def _init_data(self): # list of controller with channels enabled. self.enabled_ctrls = [] # dict with channel and its acquisition synchronization @@ -140,6 +143,18 @@ def __init__(self, mg): # dict with controller and its acquisition synchronization # key: PoolController; value: AcqSynch self.ctrl_to_acq_synch = {} + # TODO: Do the documentation + self.ctrl_sw_sync = {} + self.ctrl_hw_sync = {} + self.ctrl_sw_start = {} + self.ctrl_0d_sync = {} + # TODO: Do the documentation + self.sw_sync_timer = None + self.sw_sync_monitor = None + self.sw_start_timer = None + self.sw_start_monitor = None + self.hw_sync_timer = None + self.hw_sync_monitor = None def __check_config(func): def wrapper(self, *args, **kwargs): @@ -359,6 +374,8 @@ def _build_channel_defaults(self, channel_data, channel): def _build_configuration(self, config=None): """Builds a configuration object from the list of elements""" + self._init_data() + if config is None: config = {} user_elements = self._mg.get_user_elements() @@ -380,7 +397,6 @@ def _build_configuration(self, config=None): config['controllers'] = controllers = {} external_user_elements = [] - self.enabled_ctrls = [] for index, element in enumerate(user_elements): elem_type = element.get_type() if elem_type == ElementType.External: @@ -415,6 +431,7 @@ def _build_configuration(self, config=None): channel_data['index'] = user_elements.index(element) channel_data = self._build_channel_defaults(channel_data, element) + config['label'] = self._mg.name config['description'] = self.DFT_DESC @@ -428,7 +445,6 @@ def _build_configuration(self, config=None): element) else: # create a configuration based on a new configuration - self.enabled_ctrls = [] user_elem_ids = {} tg_elem_ids = [] pool = self._mg.pool @@ -500,7 +516,65 @@ def _build_configuration(self, config=None): monitor_ctrl_data['monitor'].name, g_monitor.name) monitor_ctrl_data['monitor'] != g_monitor + self._config = config + self._prepare_data() + + def _prepare_data(self): + """ + Split MeasurementGroup configuration with channels + triggered by SW Trigger and channels triggered by HW trigger + + """ + + ctrls_in = self._config['controllers'] + for ctrl, ctrl_info in ctrls_in.items(): + external = isinstance(ctrl, str) and ctrl.startswith('__') + # skipping external controllers e.g. Tango attributes + if external: + continue + # splitting ZeroD based on the type + if ctrl.get_ctrl_types()[0] == ElementType.ZeroDExpChannel: + self.ctrl_0d_sync[ctrl] = ctrl_info + # ignoring PseudoCounter + elif ctrl.get_ctrl_types()[0] == ElementType.PseudoCounter: + pass + # splitting rest of the channels based on the assigned trigger + else: + synchronizer = ctrl_info.get('synchronizer') + if synchronizer is None or synchronizer == 'software': + synchronization = ctrl_info.get('synchronization') + if synchronization in [AcqSynch.SoftwareTrigger, + AcqSynch.SoftwareGate]: + self.ctrl_sw_sync[ctrl] = ctrl_info + else: + self.ctrl_sw_start[ctrl] = ctrl_info + else: + self.ctrl_hw_sync[ctrl] = ctrl_info + + def find_master(ctrls, role): + master_idx = float("+inf") + master = None + for ctrl_info in ctrls.values(): + element = ctrl_info[role] + if element in ctrl_info["channels"]: + element_idx = ctrl_info["channels"][element]["index"] + element_enabled = ctrl_info["channels"][element]["enabled"] + # Find master only if is enabled + if element_idx < master_idx and element_enabled: + master = element + master_idx = element_idx + return master + + if len(self.ctrl_sw_sync): + self.sw_sync_timer = find_master(self.ctrl_sw_sync, "timer") + self.sw_sync_monitor = find_master(self.ctrl_sw_sync, "monitor") + if len(self.ctrl_sw_start): + self.sw_start_timer = find_master(self.ctrl_sw_start, "timer") + self.sw_start_monitor = find_master(self.ctrl_sw_start, "monitor") + if len(self.ctrl_hw_sync): + self.hw_sync_timer = find_master(self.ctrl_hw_sync, "timer") + self.hw_sync_monitor = find_master(self.ctrl_hw_sync, "monitor") class PoolMeasurementGroup(PoolGroupElement): From 1eb0cd786df2ab030f30845c36be2167158e03e3 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 3 Oct 2018 11:13:21 +0200 Subject: [PATCH 134/652] Adapt PoolAcquisition to use MGConfiguration API --- src/sardana/pool/poolacquisition.py | 87 +++++------------------------ 1 file changed, 14 insertions(+), 73 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 1bfc2f3987..c948643778 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -62,62 +62,6 @@ } -def split_MGConfigurations(mg_cfg_in): - """Split MeasurementGroup configuration with channels - triggered by SW Trigger and channels triggered by HW trigger - - TODO: (technical debt) All the MeasurementGroup configuration - logic should be encapsulate in a dedicated class instead of - using a basic data structures like dict or lists... - """ - ctrls_in = mg_cfg_in['controllers'] - mg_sw_cfg_out = {} - mg_0d_cfg_out = {} - mg_hw_cfg_out = {} - mg_sw_cfg_out['controllers'] = ctrls_sw_out = {} - mg_0d_cfg_out['controllers'] = ctrls_0d_out = {} - mg_hw_cfg_out['controllers'] = ctrls_hw_out = {} - for ctrl, ctrl_info in ctrls_in.items(): - external = isinstance(ctrl, str) and ctrl.startswith('__') - # skipping external controllers e.g. Tango attributes - if external: - continue - # splitting ZeroD based on the type - if ctrl.get_ctrl_types()[0] == ElementType.ZeroDExpChannel: - ctrls_0d_out[ctrl] = ctrl_info - # ignoring PseudoCounter - elif ctrl.get_ctrl_types()[0] == ElementType.PseudoCounter: - pass - # splitting rest of the channels based on the assigned trigger - else: - synchronizer = ctrl_info.get('synchronizer') - if synchronizer is None or synchronizer == 'software': - ctrls_sw_out[ctrl] = ctrl_info - else: - ctrls_hw_out[ctrl] = ctrl_info - - def find_master(ctrls, role): - master_idx = float("+inf") - master = None - for ctrl_info in ctrls.values(): - element = ctrl_info[role] - element_idx = ctrl_info["channels"][element]["index"] - element_enabled = ctrl_info["channels"][element]["enabled"] - # Find master only if is enabled - if element_idx < master_idx and element_enabled: - master = element - master_idx = element_idx - return master - - if len(ctrls_sw_out): - mg_sw_cfg_out["timer"] = find_master(ctrls_sw_out, "timer") - mg_sw_cfg_out["monitor"] = find_master(ctrls_sw_out, "monitor") - if len(ctrls_hw_out): - mg_hw_cfg_out["timer"] = find_master(ctrls_hw_out, "timer") - mg_hw_cfg_out["monitor"] = find_master(ctrls_hw_out, "monitor") - return (mg_hw_cfg_out, mg_sw_cfg_out, mg_0d_cfg_out) - - def getTGConfiguration(MGcfg): '''Build TG configuration from complete MG configuration. @@ -266,30 +210,24 @@ def run(self, *args, **kwargs): synchronization = kwargs["synchronization"] integ_time = synchronization.integration_time repetitions = synchronization.repetitions - # TODO: this code splits the global mg configuration into - # experimental channels triggered by hw and experimental channels - # triggered by sw. Refactor it!!!! - (hw_acq_cfg, sw_acq_cfg, zerod_acq_cfg) = split_MGConfigurations( - config) + synch_cfg, _ = getTGConfiguration(config) # starting continuous acquisition only if there are any controllers - if len(hw_acq_cfg['controllers']): + if len(config.ctrl_hw_sync): cont_acq_kwargs = dict(kwargs) - cont_acq_kwargs['config'] = hw_acq_cfg cont_acq_kwargs['integ_time'] = integ_time cont_acq_kwargs['repetitions'] = repetitions self._hw_acq.run(*args, **cont_acq_kwargs) - if len(sw_acq_cfg['controllers']) or len(zerod_acq_cfg['controllers']): + if len(config.ctrl_sw_sync) or len(config.ctrl_0d_sync): self._synch.add_listener(self) - if len(sw_acq_cfg['controllers']): + if len(config.ctrl_sw_sync): sw_acq_kwargs = dict(kwargs) - sw_acq_kwargs['config'] = sw_acq_cfg sw_acq_kwargs['integ_time'] = integ_time sw_acq_kwargs['repetitions'] = 1 self.set_sw_config(sw_acq_kwargs) - if len(zerod_acq_cfg['controllers']): + if len(config.ctrl_0d_sync): zerod_acq_kwargs = dict(kwargs) - zerod_acq_kwargs['config'] = zerod_acq_cfg + # TODO: Ask why self.set_0d_config(zerod_acq_kwargs) synch_kwargs = dict(kwargs) synch_kwargs['config'] = synch_cfg @@ -453,7 +391,6 @@ def start_action(self, *args, **kwargs): involved controllers and channels) """ pool = self.pool - self._aborted = False self._stopped = False @@ -475,14 +412,18 @@ def start_action(self, *args, **kwargs): _ = kwargs.get("items", self.get_elements()) cfg = kwargs['config'] # determine which is the controller which holds the master channel - + master = None + if integ_time is not None and mon_count is not None: + raise RuntimeError('The acquisition must have only one role: ' + 'timer or count') if integ_time is not None: master_key = 'timer' master_value = integ_time + master = cfg.timer if mon_count is not None: master_key = 'monitor' master_value = -mon_count - master = cfg[master_key] + master = cfg.monitor if master is None: self.main_element.set_state(State.Fault, propagate=2) msg = "master {0} is unknown (probably disabled)".format( @@ -490,7 +431,7 @@ def start_action(self, *args, **kwargs): raise RuntimeError(msg) master_ctrl = master.controller - pool_ctrls_dict = dict(cfg['controllers']) + pool_ctrls_dict = dict(cfg.controllers) pool_ctrls_dict.pop('__tango__', None) # controllers to be started (only enabled) in the right order @@ -906,7 +847,7 @@ def start_action(self, *args, **kwargs): items = self.get_elements() cfg = kwargs['config'] - pool_ctrls_dict = dict(cfg['controllers']) + pool_ctrls_dict = dict(cfg.controllers) pool_ctrls_dict.pop('__tango__', None) pool_ctrls = [] for ctrl in pool_ctrls_dict: From 756c82d5e438200876f1ab6356915324b32c45de Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 3 Oct 2018 11:42:23 +0200 Subject: [PATCH 135/652] SEP: Add integ_time, repeats and latency time to PrepapreOne --- doc/source/sep/SEP18.md | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index b1f0e22049..23a58ca653 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -120,7 +120,9 @@ the following options: #### Option 1 -* Add `Preparable` interface with `PrepareOne(axis, starts)` method` +* Add `Preparable` interface with +`PrepareOne(axis, integ_time, repeats, latency_time, starts)` TODO: or +directly add it to the Loadable interface * Make C/T, 1D and 2D controllers inherit from this interface * Add extra argument to `LoadOne`, etc. methods of the `Loadable` interface `latency_time`: `LoadOne(axis, integ_time, repeats, latency_time)` @@ -133,7 +135,7 @@ acquisition. This channel is at the same time the timer. * **step scan** 5 acquisitions x 0.1 s of integration time ```python -PrepareOne(1, 5) +PrepareOne(1, 0.1, 1, 0, 5) for acquisition in range(5): LoadOne(1, 0.1, 1, 0) StartOne(1) @@ -142,43 +144,48 @@ for acquisition in range(5): * **continuous scan (hw trigger)** 5 acquisitions x 0.1 s of integration time and 0.05 s of latency time ```python -PrepareOne(1, 1) +PrepareOne(1, 0.1, 5, 0.05, 1) # latency time can be ignored LoadOne(1, 0.1, 5, 0.05) # latency time can be ignored StartOne(1) ``` -* **continuous scan (sw trigger)** +* **continuous scan (sw trigger)** 5 acquisitions x 0.1 s of integration +time and 0.05 s of latency time ```python -PrepareOne(1, 5) +PrepareOne(1, 0.1, 1, 0.05, 5) # latency time can be ignored for trigger in range(5): LoadOne(1, 0.1, 1, 0.05) # latency time can be ignored StartOne(1) ``` -* **continuous scan (hw gate)** +* **continuous scan (hw gate)** 5 acquisitions x 0.1 s of integration +time and 0.05 s of latency time ```python -PrepareOne(1, 1) +PrepareOne(1, 0.1, 5, 0.05, 1) # integration time and latency time can be ignored LoadOne(1, 0.1, 5, 0.05) # integration time and latency time can be ignored StartOne(1) ``` -* **continuous scan (sw gate)** +* **continuous scan (sw gate)** 5 acquisitions x 0.1 s of integration +time and 0.05 s of latency time ```python -PrepareOne(1, 5) +PrepareOne(1, 0.1, 1, 0.05, 5) for gate in range(5): LoadOne(1, 0.1, 1, 0.05) # integration time and latency time can be ignored StartOne(1) ``` -* **continuous scan (hw start)** +* **continuous scan (hw start)** 5 acquisitions x 0.1 s of integration +time and 0.05 s of latency time ```python -PrepareOne(1, 1) +PrepareOne(1, 0.1, 5, 0.05, 1) LoadOne(1, 0.1, 5, 0.05) StartOne(1) ``` -* **continuous scan (sw start)** +* **continuous scan (sw start)** 5 acquisitions x 0.1 s of integration +time and 0.05 s of latency time ```python -PrepareOne(1, 1) +PrepareOne(1, 0.1, 5, 0.05, 1) LoadOne(1, 0.1, 5, 0.05) StartOne(1) ``` From 88cfc331235d03536b2d68c481ffadc6a6545e90 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 3 Oct 2018 11:49:27 +0200 Subject: [PATCH 136/652] SEP: Re-phrase option 2 to be more readable --- doc/source/sep/SEP18.md | 6 +++--- src/sardana/macroserver/scan/gscan.py | 1 + src/sardana/pool/poolacquisition.py | 9 +++++++++ src/sardana/pool/poolmeasurementgroup.py | 7 +++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 23a58ca653..1e8311c7a8 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -194,9 +194,9 @@ StartOne(1) * Add extra arguments to `LoadOne`, etc. methods of the `Loadable` interface `latency_time` and `starts` and switch the order of arguments so the API is: -`LoadOne(axis, integ_time, latency_time, repeats, starts)` -* Make the `LoadOne`, etc. be called only once, in the measurement group -prepare command, per measurement. +`LoadOne(axis, integ_time, latency_time, repeats, starts)`. +* Make the `LoadOne`, etc. be called only once per measurement, in the +measurement group prepare command. This option **breaks** backwards compatibility. diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index a61da2bee4..380fcba53f 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -1007,6 +1007,7 @@ def scan_loop(self): scream = False if hasattr(macro, "nr_points"): + self.measurement_group.prepare() nr_points = float(macro.nr_points) scream = True else: diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 63353ec383..9a998b35d2 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -241,6 +241,15 @@ def event_received(self, *args, **kwargs): self.debug('Stopping ZeroD acquisition.') self._0d_acq.stop_action() + def prepare(self, config, repetitions): + """Prepare measurement.""" + timers = config.get_timers(enabled=True) + for timer in timers: + axis = timer.axis + timer_ctrl = timer.controller + ctrl = timer_ctrl.ctrl + ctrl.PrepareOne(axis, repetitions) + def is_running(self): return self._0d_acq.is_running() or\ self._sw_acq.is_running() or\ diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 280821e746..c7279ee7ee 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -715,6 +715,13 @@ def set_sw_synch_initial_domain(self, domain): # acquisition # ------------------------------------------------------------------------- + def prepare(self): + self.load_configuration() + config = self.get_configuration() + repetitions = self.synchronization.repetitions + self.acquisition.prepare(config, repetitions) + + def start_acquisition(self, value=None, multiple=1): self._aborted = False if not self._simulation_mode: From d7491210548a947fc67f67977d7dadb6acd9205d Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 3 Oct 2018 12:49:09 +0200 Subject: [PATCH 137/652] SEP: Add software sync, acquisitions and dummy C/T implementation --- doc/source/sep/SEP18.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 1e8311c7a8..9878067caf 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -113,6 +113,17 @@ to measure according to the synchronization description. * `count_single()` * `unsubscribeValueBuffer()` +### Software synchronizer + +* Add `start` and `end` events. Start is emitted before the first `active` +event and end is emitted after the last `passive` event. + +### Acquisition actions + +* Add `PoolAcquisitionSoftwareStart` action that will start channels on +software synchronizer `start` event and stop channels on software +synchronizer `end` event. + ### Controllers C/T, 1D and 2D controllers (plugins) API is extended. TODO: Choose between @@ -249,3 +260,8 @@ StartOne(1) LoadOne(1, 0.1, 0.05, 5, 1) StartOne(1) ``` + +### Dummy C/T controller +Implement `SoftwareStart` and `HardwareStart` in the +`DummyCounterTimerController` - minimal implementation. + \ No newline at end of file From ceeb292472121e64b303dbb8435d1f9ba7a06cd8 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 3 Oct 2018 13:27:44 +0200 Subject: [PATCH 138/652] SEP: add more information to design chapter --- doc/source/sep/SEP18.md | 44 +++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 9878067caf..f7e190a0bf 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -40,27 +40,37 @@ Overcome the above limitations. Design ------ - -1. Document well that: - * Software(Trigger|Gate) are synonyms to Internal (Trigger|Gate). +1. Use of the measurement group will change: + * From now on, in order to start the measurement group, it is mandatory + to prepare it. + * The measurement group will be armed for as many starts as specified in + the preparation and the preparation will expire whenever all starts gets + called or in case of stop/abort. + * Setting the integration time via the attribute will de deprecated in + favor of using prepare command with the synchronization description, but + backwards compatibility will be maintained. +2. Allow different types of preparation of channels - this still depends on +the option selected in the implementation of controllers. The following +assumes option 1. + * Per measurement preparation with number of starts = n e.g. + Prepare(One|All) or a controller parameter + * Per acquisition preparation with repetitions = n e.g. Load(One|All) +3. Extend AcqSynch with two new options: + * SoftwareStart (which means internal start) + * HardwareStart (which means external start) +4. Extend AcqSynchType with one new option (supported from expconf): + * Start +5. Modify acquisition actions (and synchronization action if necessary) so +they support the new concepts added in points 2 and 3. +6. *Extend Generic Scan Framework* (GSF), more precisely scan in step mode +with measurement preparation (number of starts = n) if possible i.e. scan +macro knows beforehand the number of points. +7. Document well that: + * Software(Trigger|Gate) are synonyms to Internal (Trigger|Gate). Internal means that Sardana will synchronize the acquisitions. * Hardware(Trigger|Gate) are synonyms to External(Trigger|Gate). External means that an external to Sardana object (could be hardware) will synchronize the acquisitions. -2. Extend AcqSynch with two new options: - * SoftwareStart (which means internal start) - * HardwareStart (which means external start) -3. Extend AcqSynchType with one new option (supported from expconf): - * Start -4. Allow different types of preparation of channels: - * Per measurement preparation with repetitions=n e.g. Prepare(One|All) - or a controller parameter - * Per acquisition preparation with repetitions=1 e.g. Load(One|All) -6. Modify acquisition actions (and synchronization action if necessary) so -they support the new concepts added in points 2 and 4. -5. *Extend Generic Scan Framework* (GSF), more preciselly scan in step mode -with measurement preparation (repetitions=n) if possible i.e. scan macro knows -beforehand the number of points. Implementation -------------- From 0cfd3130905efad796de00c07e69d226ae5bd9ef Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 3 Oct 2018 13:28:06 +0200 Subject: [PATCH 139/652] SEP: add backwards compatibility for integration time --- doc/source/sep/SEP18.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index f7e190a0bf..d0490772ed 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -104,7 +104,10 @@ to measure according to the synchronization description. * Add `prepare(synchronization, starts=1)` method * Remove `synchronization` property (experimental API) - no backwards compatibility. -3. Measurement group - Taurus extension +3. Backwards compatibility for integration time attribute will be solved in +the following way: setting of integration time attribute will allow starts +until the next preparation. +4. Measurement group - Taurus extension * Add `prepare` method which simply maps to `Prepare` Tango command * Add `count_single` (TODO: find the best name for this method, other candidates are `count_raw`, `acquire`) method according to From 6e99f91ea1fba9efcfff0eb63959d8dcf1fd2011 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 3 Oct 2018 13:35:27 +0200 Subject: [PATCH 140/652] SEP: add option 3 to controllers implementation --- doc/source/sep/SEP18.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index d0490772ed..bcc8b19115 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -274,7 +274,15 @@ LoadOne(1, 0.1, 0.05, 5, 1) StartOne(1) ``` +#### Option 3 + +The same as option 2 but maintaining the backwards compatibility in the +following way: +* Developing a new C/T, 1D, 2D will require implementing `ControllerAPI` +class member with 2.6 value. +* Acquisition actions will call the `LoadOne`, etc. methods depending on the +`ControllerAPI` values. + ### Dummy C/T controller Implement `SoftwareStart` and `HardwareStart` in the `DummyCounterTimerController` - minimal implementation. - \ No newline at end of file From 79d8c509ddf705240ced6519c9d437e10217f0a6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 3 Oct 2018 14:57:49 +0200 Subject: [PATCH 141/652] SEP: fix typos --- doc/source/sep/SEP18.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index bcc8b19115..2979b7f7e3 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -46,7 +46,7 @@ Design * The measurement group will be armed for as many starts as specified in the preparation and the preparation will expire whenever all starts gets called or in case of stop/abort. - * Setting the integration time via the attribute will de deprecated in + * Setting the integration time via the attribute will be deprecated in favor of using prepare command with the synchronization description, but backwards compatibility will be maintained. 2. Allow different types of preparation of channels - this still depends on @@ -79,9 +79,9 @@ Implementation * `SScan` (step scan) implemented according to the following pseudo code: * If number of points is known: - * `prepare(synchronization, start=n)` where synchronization - contains the integration time and n means number of points - * `for step in range(n): count_single()` + * `prepare(synchronization, starts=n)` where synchronization + contains the integration time and n means number of scan points + * `for step in range(n): count_raw()` * If number of points is unknown: * `while new_step: count()` * `CTScan` (continuous scan) does not require changes, it simply calls From 9721ad7f0f265567b2f88a7dd79cadd74e2b06ce Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 3 Oct 2018 14:58:33 +0200 Subject: [PATCH 142/652] SEP: rename count_single to count_raw --- doc/source/sep/SEP18.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 2979b7f7e3..d731581034 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -109,21 +109,19 @@ the following way: setting of integration time attribute will allow starts until the next preparation. 4. Measurement group - Taurus extension * Add `prepare` method which simply maps to `Prepare` Tango command - * Add `count_single` (TODO: find the best name for this - method, other candidates are `count_raw`, `acquire`) method according to - the following pseudo code: - * `Start()` + * Add `count_raw` method according to the following pseudo code: + * `start()` * `waitFinish()` * Implement `count` method according to the following pseudo code: * `prepare(synchronization & starts = 1)` where synchronization contains the integration time - * `count_single()` + * `count_raw()` * Implement `count_continuous` (previous `measure`) method according to the following pseudo code: * `prepare(synchronization & starts = 1)` where synchronization may contain the continuous acquisition description * `subscribeValueBuffer()` - * `count_single()` + * `count_raw()` * `unsubscribeValueBuffer()` ### Software synchronizer From b84d0b58e26103044c7d46a34f94d3ee0e035401 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 3 Oct 2018 17:19:45 +0200 Subject: [PATCH 143/652] Update SEP18.md --- doc/source/sep/SEP18.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index d731581034..7cee6e1400 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -132,8 +132,11 @@ event and end is emitted after the last `passive` event. ### Acquisition actions * Add `PoolAcquisitionSoftwareStart` action that will start channels on -software synchronizer `start` event and stop channels on software -synchronizer `end` event. +software synchronizer `start` event. +* `PoolAcquisitionSoftware` will stop channels on software synchronizer +`end` event. TODO: decide if we wait for the acquisition in progress +until it finises or we stop immediatelly (finish hook could be used if +we choose to wait). ### Controllers From 8bfce2307c5286e600cbeef2c80fed8f46a7d126 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 3 Oct 2018 17:27:03 +0200 Subject: [PATCH 144/652] SEP: refine option 3 --- doc/source/sep/SEP18.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 7cee6e1400..6c03386b67 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -279,10 +279,10 @@ StartOne(1) The same as option 2 but maintaining the backwards compatibility in the following way: -* Developing a new C/T, 1D, 2D will require implementing `ControllerAPI` -class member with 2.6 value. * Acquisition actions will call the `LoadOne`, etc. methods depending on the -`ControllerAPI` values. +controllers implementations (more preciselly using the `inspect.getargspec` +and counting the number of arguments). This will require much more complicated +acquisition actions. ### Dummy C/T controller Implement `SoftwareStart` and `HardwareStart` in the From 684ee26c4e5437969d593688798ef3bbe9681645 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 4 Oct 2018 12:46:03 +0200 Subject: [PATCH 145/652] In step scan prepare MG if nr_points and integ_time is known --- src/sardana/macroserver/scan/gscan.py | 6 +++++- src/sardana/taurus/core/tango/sardana/pool.py | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index 380fcba53f..efe88df81a 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -1007,8 +1007,12 @@ def scan_loop(self): scream = False if hasattr(macro, "nr_points"): - self.measurement_group.prepare() nr_points = float(macro.nr_points) + if hasattr(macro, "integ_time"): + integ_time = macro.integ_time + group = {SynchParam.Active: {SynchDomain.Time: integ_time}} + synchronization = [group] + self.measurement_group.prepare(synchronization, nr_points) scream = True else: yield 0.0 diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index c0978afed0..bed33eea26 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1795,6 +1795,8 @@ def _start(self, *args, **kwargs): self.debug("stopped") raise e + def prepare(self, synchronization, nr_of_starts=1): + pass def go(self, *args, **kwargs): start_time = time.time() From afc040fc4bde8f8c4dc3e64ecba47e9a1bf058c5 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Fri, 5 Oct 2018 11:04:47 +0200 Subject: [PATCH 146/652] (m) (doc) Fix typo --- doc/source/devel/howto_macros/macros_general.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index d1681eb938..3ef5acfccb 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -331,7 +331,7 @@ Optional parameters ~~~~~~~~~~~~~~~~~~~ A special parameter default value is the ``Optional``. It allows to -execute a macro even the given parameter value is not specified by the user. +execute a macro even if the given parameter value is not specified by the user. So, here is an example how to define and use the optional parameter:: From 6f761a3fc61eb0df971abc36a02c57486c1abfeb Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 27 Sep 2018 18:02:06 +0200 Subject: [PATCH 147/652] Add start event to funtion generator --- src/sardana/util/funcgenerator.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sardana/util/funcgenerator.py b/src/sardana/util/funcgenerator.py index 340595b9d9..44b7088da2 100644 --- a/src/sardana/util/funcgenerator.py +++ b/src/sardana/util/funcgenerator.py @@ -64,6 +64,7 @@ def __init__(self, name="FunctionGenerator"): self._initial_domain = None self._active_domain = None self._position_event = threading.Event() + self._position = None self._initial_domain_in_use = None self._active_domain_in_use = None self._active_events = list() @@ -75,6 +76,7 @@ def __init__(self, name="FunctionGenerator"): self._direction = None self._condition = None self._id = None + self._start_fired = False def get_name(self): return self._name @@ -167,6 +169,7 @@ def start(self): self._stopped = False self._started = True self._position = None + self._start_fired = False self._position_event.clear() self._id = 0 self.fire_event(EventType("state"), State.Moving) @@ -211,6 +214,13 @@ def sleep(self, period): break time.sleep(nap) + def fire_start(self): + self.fire_event(EventType("start")) + self._start_fired = True + if self._id > 0: + msg = "start was fired with {0} delay".format(self._id) + self.warning(msg) + def wait_active(self): candidate = self.active_events[0] if self.initial_domain_in_use == SynchDomain.Time: @@ -244,6 +254,8 @@ def fire_active(self): else: break self._id += i + if not self._start_fired: + self.fire_start() self.fire_event(EventType("active"), self._id) self.active_events = self.active_events[i + 1:] self.passive_events = self.passive_events[i:] From 3818ab9b780a7281a231f2a6735b24288712b848 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 5 Oct 2018 12:22:58 +0200 Subject: [PATCH 148/652] Fix optional param for python 2.6 --- src/sardana/macroserver/msparameter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/macroserver/msparameter.py b/src/sardana/macroserver/msparameter.py index 0d75e69e1c..bf7f8c67d5 100644 --- a/src/sardana/macroserver/msparameter.py +++ b/src/sardana/macroserver/msparameter.py @@ -50,8 +50,9 @@ def __init__(self, obj): attributes = dir(self) for attr in attributes: + # iteritems is necessary fo python 2.6 implementation of json if attr in ['__setattr__', '__repr__', 'raise_error', '__class__', - '__dict__', '__weakref__']: + '__dict__', '__weakref__', 'iteritems']: continue self.__setattr__(attr, self.raise_error) self.__setattr__ = self.raise_error From 5890002a8f1117a939b01dc49127792bcd3c04e9 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Fri, 5 Oct 2018 12:46:17 +0200 Subject: [PATCH 149/652] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6614b25863..6dbda64311 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ This file follows the formats and conventions from [keepachangelog.com] ### Added - Possibility to define macros with optional parameters. These must be the last - ones in the definition (#285, #876, #943, #941) + ones in the definition (#285, #876, #943, #941, #955) - Workaround for API_DeviceTimedOut errors on MeasurementGroup Start. Call Stop in case this error occured (#764). - Optional measurement group parameter to `ct` and `uct` macros (#940, #473) From f30aa97757349e4fb856be34c0c4d8f1f4525021 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Fri, 5 Oct 2018 12:49:37 +0200 Subject: [PATCH 150/652] Update funcgenerator.py --- src/sardana/util/funcgenerator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/util/funcgenerator.py b/src/sardana/util/funcgenerator.py index 44b7088da2..f30fddd237 100644 --- a/src/sardana/util/funcgenerator.py +++ b/src/sardana/util/funcgenerator.py @@ -215,7 +215,7 @@ def sleep(self, period): time.sleep(nap) def fire_start(self): - self.fire_event(EventType("start")) + self.fire_event(EventType("start"), self._id) self._start_fired = True if self._id > 0: msg = "start was fired with {0} delay".format(self._id) From 738c839ec783ed9d77dbdf14d09ef506bcec0a81 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 10:46:13 +0200 Subject: [PATCH 151/652] Allow to create a raw configuration --- src/sardana/pool/poolmeasurementgroup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index f398532a51..7835e3b93a 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -128,8 +128,10 @@ class MGConfiguration(object): DFT_DESC = 'General purpose measurement group' - def __init__(self, mg): - self._mg = weakref.ref(mg)() + def __init__(self, mg=None): + self._mg = None + if mg is not None: + self._mg = weakref.ref(mg)() self._config = None self.use_fqdn = True self._init_data() From b6580081e2dd7f271103721367c25fe53b2c31e5 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 10:51:08 +0200 Subject: [PATCH 152/652] Add internal getters to PoolAcquisitionBase Add getters to extract the controllers, timer and monitor according to the acquisition synchronization (hardware or software). --- src/sardana/pool/poolacquisition.py | 86 +++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index c948643778..37f67acb30 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -363,6 +363,30 @@ def __init__(self, main_element, name): # acquisition actions, uncomment this line # self.add_finish_hook(self.clear_value_buffers, True) + def _get_ctrls(self): + """ + Method to get the controller dict for the acquisition type + :return: + :rtype dict + """ + raise NotImplementedError() + + def _get_timer(self): + """ + Method to get the controller dict for the acquisition type + :return: + :rtype dict + """ + raise NotImplementedError() + + def _get_monitor(self): + """ + Method to get the controller dict for the acquisition type + :return: + :rtype dict + """ + raise NotImplementedError() + def in_acquisition(self, states): """Determines if we are in acquisition or if the acquisition has ended based on the current unit trigger modes and states returned by the @@ -413,25 +437,25 @@ def start_action(self, *args, **kwargs): cfg = kwargs['config'] # determine which is the controller which holds the master channel master = None + if integ_time is not None and mon_count is not None: raise RuntimeError('The acquisition must have only one role: ' 'timer or count') if integ_time is not None: master_key = 'timer' master_value = integ_time - master = cfg.timer + master = self._get_timer() if mon_count is not None: master_key = 'monitor' master_value = -mon_count - master = cfg.monitor + master = self._get_monitor() if master is None: self.main_element.set_state(State.Fault, propagate=2) - msg = "master {0} is unknown (probably disabled)".format( - master_key) + msg = "master {0} ({1})is unknown (probably disabled)".format( + master_key, master) raise RuntimeError(msg) master_ctrl = master.controller - - pool_ctrls_dict = dict(cfg.controllers) + pool_ctrls_dict = dict(self._get_ctrls()) pool_ctrls_dict.pop('__tango__', None) # controllers to be started (only enabled) in the right order @@ -587,6 +611,31 @@ class PoolAcquisitionHardware(PoolAcquisitionBase): def __init__(self, main_element, name="AcquisitionHardware"): PoolAcquisitionBase.__init__(self, main_element, name) + def _get_ctrls(self): + """ + Method to get the controller dict for the acquisition type + :return: + :rtype dict + """ + return self.main_element.configuration.ctrl_hw_sync + + def _get_timer(self): + """ + Method to get the controller dict for the acquisition type + :return: + :rtype dict + """ + return self.main_element.configuration.hw_sync_timer + + def _get_monitor(self): + """ + Method to get the controller dict for the acquisition type + :return: + :rtype dict + """ + return self.main_element.configuration.hw_sync_monitor + + @DebugIt() def action_loop(self): i = 0 @@ -657,6 +706,31 @@ def __init__(self, main_element, name="AcquisitionSoftware", slaves=None): slaves = () self._slaves = slaves + def _get_ctrls(self): + """ + Method to get the controller dict for the acquisition type + :return: + :rtype dict + """ + return self.main_element.configuration.ctrl_sw_sync + + def _get_timer(self): + """ + Method to get the controller dict for the acquisition type + :return: + :rtype dict + """ + + return self.main_element.configuration.sw_sync_timer + + def _get_monitor(self): + """ + Method to get the controller dict for the acquisition type + :return: + :rtype dict + """ + return self.main_element.configuration.sw_sync_monitor + @DebugIt() def start_action(self, *args, **kwargs): """Prepares everything for acquisition and starts it. From d0368e300af07c80b5deb9af69c97557788a3586 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 10:53:02 +0200 Subject: [PATCH 153/652] Use the main_element configuration --- src/sardana/pool/poolacquisition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 37f67acb30..c154abf8e6 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -206,7 +206,8 @@ def run(self, *args, **kwargs): # participate directly in the acquisition for pseudo_elem in elem.get_pseudo_elements(): pseudo_elem.clear_value_buffer() - config = kwargs['config'] + + config = self.main_element.configuration synchronization = kwargs["synchronization"] integ_time = synchronization.integration_time repetitions = synchronization.repetitions @@ -434,7 +435,6 @@ def start_action(self, *args, **kwargs): raise Exception(msg) _ = kwargs.get("items", self.get_elements()) - cfg = kwargs['config'] # determine which is the controller which holds the master channel master = None From af253c32842359482e6224f68adbae40705a6ef7 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 10:54:15 +0200 Subject: [PATCH 154/652] Adapt helpers to use MGConfiguration class --- src/sardana/pool/test/helper.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index 927395549b..0f4597f709 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -41,7 +41,8 @@ from sardana.pool.poolmotor import PoolMotor from sardana.pool.poolpseudocounter import PoolPseudoCounter from sardana.pool.poolpseudomotor import PoolPseudoMotor -from sardana.pool.poolmeasurementgroup import PoolMeasurementGroup +from sardana.pool.poolmeasurementgroup import PoolMeasurementGroup, \ + MGConfiguration def createPoolController(pool, conf): @@ -195,7 +196,7 @@ def createCTAcquisitionConfiguration(ctrls, ctrl_channels): master_idx = 0 configuration = {} ctrls_configuration = {} - configuration['timer'] = ctrl_channels[master_ctrl_idx][master_idx] + configuration['timer'] = timer = ctrl_channels[master_ctrl_idx][master_idx] for ctrl, channels in zip(ctrls, ctrl_channels): ctrl_data = createConfFromObj(ctrl) ctrl_data['channels'] = {} @@ -205,7 +206,16 @@ def createCTAcquisitionConfiguration(ctrls, ctrl_channels): ctrl_data['timer'] = channels[master_idx] ctrls_configuration[ctrl] = ctrl_data configuration['controllers'] = ctrls_configuration - return configuration + mg_cfg = MGConfiguration() + mg_cfg._config = configuration + mg_cfg.hw_sync_monitor = timer + mg_cfg.hw_sync_timer = timer + mg_cfg.sw_sync_timer = timer + mg_cfg.sw_sync_monitor = timer + mg_cfg.ctrl_hw_sync = ctrls_configuration + mg_cfg.ctrl_sw_sync = ctrls_configuration + + return mg_cfg def createMGUserConfiguration(pool, channels): From de0d7d051fe14508c85da6f703614ecc615dc831 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 11:09:56 +0200 Subject: [PATCH 155/652] Adapt aquisition test to use MGConfiguration class --- src/sardana/pool/test/test_acquisition.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index 6e09954ad6..953e738e85 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -311,6 +311,9 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, self.sw_acq_cfg = createCTAcquisitionConfiguration((ct_ctrl_2,), ((ct_2_1,),)) # creating acquisition actions + # TODO: The CTExpChannel should have a configuration + ct_1_1.configuration = self.hw_acq_cfg + ct_2_1.configuration = self.sw_acq_cfg self.hw_acq = PoolAcquisitionHardware(ct_1_1) self.sw_acq = PoolAcquisitionSoftware(ct_2_1) # Since we deposit the software acquisition action on the PoolThread's From cede9f930613109ed7a4138aa0cc0959da3c1236 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 11:25:04 +0200 Subject: [PATCH 156/652] Remove typo error Remove line copied by mistake --- src/sardana/pool/poolmeasurementgroup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 30a443049c..1b883c3475 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -517,7 +517,6 @@ def _build_configuration(self, config=None): 'controller', g_monitor.controller.name, monitor_ctrl_data['monitor'].name, g_monitor.name) - monitor_ctrl_data['monitor'] != g_monitor self._config = config self._prepare_data() From 10e40f8f6803326cf8388a3d052c17c54559e092 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 8 Oct 2018 11:26:38 +0200 Subject: [PATCH 157/652] Add prepare method in MeasurementGroup Taurus ext --- src/sardana/taurus/core/tango/sardana/pool.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index bed33eea26..2ec007f69d 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1795,8 +1795,8 @@ def _start(self, *args, **kwargs): self.debug("stopped") raise e - def prepare(self, synchronization, nr_of_starts=1): - pass + def prepare(self): + self.command_inout("Prepare") def go(self, *args, **kwargs): start_time = time.time() From 38e217a4beb175551e48493533777bd0e9a89751 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 11:28:23 +0200 Subject: [PATCH 158/652] Rename MGConfiguration to MeasurementConfiguration The class will be used by the measurement groups and the counter/timer channels. --- src/sardana/pool/poolmeasurementgroup.py | 4 ++-- src/sardana/pool/test/helper.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 1b883c3475..a80da25005 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -124,7 +124,7 @@ def _to_fqdn(name, logger=None): return full_name -class MGConfiguration(object): +class MeasurementConfiguration(object): DFT_DESC = 'General purpose measurement group' @@ -585,7 +585,7 @@ def __init__(self, **kwargs): self._monitor_count = None self._repetitions = 1 self._acquisition_mode = AcqMode.Timer - self._config = MGConfiguration(self) + self._config = MeasurementConfiguration(self) self._config_dirty = True self._moveable = None self._moveable_obj = None diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index 0f4597f709..5d9cc97f8e 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -42,7 +42,7 @@ from sardana.pool.poolpseudocounter import PoolPseudoCounter from sardana.pool.poolpseudomotor import PoolPseudoMotor from sardana.pool.poolmeasurementgroup import PoolMeasurementGroup, \ - MGConfiguration + MeasurementConfiguration def createPoolController(pool, conf): @@ -206,7 +206,7 @@ def createCTAcquisitionConfiguration(ctrls, ctrl_channels): ctrl_data['timer'] = channels[master_idx] ctrls_configuration[ctrl] = ctrl_data configuration['controllers'] = ctrls_configuration - mg_cfg = MGConfiguration() + mg_cfg = MeasurementConfiguration() mg_cfg._config = configuration mg_cfg.hw_sync_monitor = timer mg_cfg.hw_sync_timer = timer From a3656ecddde6d63c15dc154471364cf9fab834e2 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 11:31:58 +0200 Subject: [PATCH 159/652] Rename internal variable Change "mg" to "parent" as it is more appropriate to the new use of the class. --- src/sardana/pool/poolmeasurementgroup.py | 76 ++++++++++++------------ 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index a80da25005..afc9165210 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -128,10 +128,10 @@ class MeasurementConfiguration(object): DFT_DESC = 'General purpose measurement group' - def __init__(self, mg=None): - self._mg = None - if mg is not None: - self._mg = weakref.ref(mg)() + def __init__(self, parent=None): + self._parent = None + if parent is not None: + self._parent = weakref.ref(parent)() self._config = None self.use_fqdn = True self._init_data() @@ -194,8 +194,8 @@ def configuration(self, config=None): def set_configuration_from_user(self, cfg, to_fqdn=True): config = {} - user_elements = self._mg.get_user_elements() - pool = self._mg.pool + user_elements = self._parent.get_user_elements() + pool = self._parent.pool if len(user_elements) == 0: # All timers were disabled default_timer = None @@ -205,10 +205,10 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): timer_name = cfg.get('timer', default_timer) monitor_name = cfg.get('monitor', default_timer) if to_fqdn: - timer_name = _to_fqdn(timer_name, logger=self._mg) + timer_name = _to_fqdn(timer_name, logger=self._parent) config['timer'] = pool.get_element_by_full_name(timer_name) if to_fqdn: - monitor_name = _to_fqdn(monitor_name, logger=self._mg) + monitor_name = _to_fqdn(monitor_name, logger=self._parent) config['monitor'] = pool.get_element_by_full_name(monitor_name) config['controllers'] = controllers = {} @@ -231,7 +231,7 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): ctrl = c_name else: if to_fqdn: - c_name = _to_fqdn(c_name, logger=self._mg) + c_name = _to_fqdn(c_name, logger=self._parent) ctrl = pool.get_element_by_full_name(c_name) assert ctrl.get_type() == ElementType.Controller controllers[ctrl] = ctrl_data = {} @@ -240,12 +240,12 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): if not external and ctrl.is_timerable(): timer_name = c_data['timer'] if to_fqdn: - timer_name = _to_fqdn(timer_name, logger=self._mg) + timer_name = _to_fqdn(timer_name, logger=self._parent) timer = pool.get_element_by_full_name(timer_name) ctrl_data['timer'] = timer monitor_name = c_data['monitor'] if to_fqdn: - monitor_name = _to_fqdn(monitor_name, logger=self._mg) + monitor_name = _to_fqdn(monitor_name, logger=self._parent) monitor = pool.get_element_by_full_name(monitor_name) ctrl_data['monitor'] = monitor synchronizer = c_data.get('synchronizer') @@ -255,7 +255,8 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): synchronizer = 'software' elif synchronizer != 'software': if to_fqdn: - synchronizer = _to_fqdn(synchronizer, logger=self._mg) + synchronizer = _to_fqdn(synchronizer, + logger=self._parent) synchronizer = pool.get_element_by_full_name(synchronizer) ctrl_data['synchronizer'] = synchronizer try: @@ -266,22 +267,22 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): msg = ("trigger_type configuration parameter is deprecated" " in favor of synchronization. Re-apply " "configuration in order to upgrade.") - self._mg.warning(msg) + self._parent.warning(msg) ctrl_data['synchronization'] = synchronization ctrl_data['channels'] = channels = {} for ch_name, ch_data in c_data['channels'].items(): if external: validator = TangoAttributeNameValidator() params = validator.getParams(ch_data['full_name']) - params['pool'] = self._mg.pool + params['pool'] = self._parent.pool channel = PoolExternalObject(**params) else: if to_fqdn: - ch_name = _to_fqdn(ch_name, logger=self._mg) + ch_name = _to_fqdn(ch_name, logger=self._parent) channel = pool.get_element_by_full_name(ch_name) channels[channel] = dict(ch_data) - config['label'] = cfg.get('label', self._mg.name) + config['label'] = cfg.get('label', self._parent.name) config['description'] = cfg.get('description', self.DFT_DESC) self.use_fqdn = to_fqdn self._build_configuration(config) @@ -380,8 +381,8 @@ def _build_configuration(self, config=None): if config is None: config = {} - user_elements = self._mg.get_user_elements() - ctrls = self._mg.get_pool_controllers() + user_elements = self._parent.get_user_elements() + ctrls = self._parent.get_pool_controllers() # find the first CT first_timerable = None @@ -434,7 +435,7 @@ def _build_configuration(self, config=None): channel_data = self._build_channel_defaults(channel_data, element) - config['label'] = self._mg.name + config['label'] = self._parent.name config['description'] = self.DFT_DESC if len(external_user_elements) > 0: @@ -449,7 +450,7 @@ def _build_configuration(self, config=None): # create a configuration based on a new configuration user_elem_ids = {} tg_elem_ids = [] - pool = self._mg.pool + pool = self._parent.pool for c, c_data in config['controllers'].items(): synchronizer = c_data.get('synchronizer') acq_synch_type = c_data.get('synchronization') @@ -469,7 +470,8 @@ def _build_configuration(self, config=None): else: full_name = channel_data['full_name'] if self.use_fqdn: - full_name = _to_fqdn(full_name, logger=self._mg) + full_name = _to_fqdn(full_name, + logger=self._parent) element = pool.get_element_by_full_name(full_name) _id = element.id channel_data = self._build_channel_defaults( @@ -492,31 +494,31 @@ def _build_configuration(self, config=None): indexes = sorted(user_elem_ids.keys()) user_elem_ids_list = [user_elem_ids[idx] for idx in indexes] user_elem_ids_list.extend(tg_elem_ids) - self._mg.set_user_element_ids(user_elem_ids_list) + self._parent.set_user_element_ids(user_elem_ids_list) g_timer, g_monitor = config['timer'], config['monitor'] timer_ctrl_data = config['controllers'][g_timer.controller] if timer_ctrl_data['timer'] != g_timer: - self._mg.warning('controller timer and global timer ' - 'mismatch. Using global timer') - self._mg.debug('For controller %s, timer is defined as ' - 'channel %s. The global timer is set to ' - 'channel %s which belongs to the same ' - 'controller', g_timer.controller.name, - timer_ctrl_data['timer'].name, g_timer.name) + self._parent.warning('controller timer and global timer ' + 'mismatch. Using global timer') + self._parent.debug('For controller %s, timer is defined as ' + 'channel %s. The global timer is set to ' + 'channel %s which belongs to the same ' + 'controller', g_timer.controller.name, + timer_ctrl_data['timer'].name, g_timer.name) timer_ctrl_data['timer'] = g_timer monitor_ctrl_data = config['controllers'][g_monitor.controller] if monitor_ctrl_data['monitor'] != g_monitor: - self._mg.warning('controller monitor and global ' - 'monitor mismatch. Using global monitor') - self._mg.debug('For controller %s, monitor is defined as ' - 'channel %s. The global timer is set to ' - 'channel %s which belongs to the same ' - 'controller', g_monitor.controller.name, - monitor_ctrl_data['monitor'].name, - g_monitor.name) + self._parent.warning('controller monitor and global ' + 'monitor mismatch. Using global monitor') + self._parent.debug('For controller %s, monitor is defined as ' + 'channel %s. The global timer is set to ' + 'channel %s which belongs to the same ' + 'controller', g_monitor.controller.name, + monitor_ctrl_data['monitor'].name, + g_monitor.name) self._config = config self._prepare_data() From 34354a674461ccf9a5ea96ad1fbbb7cba545c28a Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 12:01:35 +0200 Subject: [PATCH 160/652] SEP: remove arguments from prepare command --- doc/source/sep/SEP18.md | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 6c03386b67..165debefd4 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -89,36 +89,36 @@ Implementation ### Measurement Group -Measurement group is extended by the *prepare* command with two parameters: -synchronization description and number of starts. The second one indicates -how many times measurement group will be started, with the *start* command, -to measure according to the synchronization description. +Measurement group is extended by the *prepare* command (with no arguments) +*number of starts* attribute. The use of the attribute is optional and +it indicates how many times measurement group will be started, with the +*start* command, to measure according to the synchronization description or +integration time. When it is not used number of starts of 1 will be assumed. 1. Measurement group - Tango device class - * Add `Prepare` command. TODO: investigate the best way to pass - synchronization description, as JSON serialized string, together with the - starts integer. - * Remove `synchronization` attribute (experimental API) - no backwards - compatibility. + * Add `Prepare` command. + * Add `NrOfStarts` (`DevLong`) attribute. 2. Measurement group - core class - * Add `prepare(synchronization, starts=1)` method - * Remove `synchronization` property (experimental API) - no backwards - compatibility. -3. Backwards compatibility for integration time attribute will be solved in -the following way: setting of integration time attribute will allow starts -until the next preparation. + * Add `prepare()` method. + * Add `nr_of_starts` property. +3. Backwards compatibility for using just the integration time attribute with +the start command (without calling prepare command in-between) will be +solved in the following way: start command will internally call the prepare. 4. Measurement group - Taurus extension - * Add `prepare` method which simply maps to `Prepare` Tango command + * Add `prepare()` method which simply maps to `Prepare` Tango command * Add `count_raw` method according to the following pseudo code: * `start()` * `waitFinish()` - * Implement `count` method according to the following pseudo code: - * `prepare(synchronization & starts = 1)` where synchronization - contains the integration time + * Implement `count(integration_time)` method according to the following + pseudo + code: + * set `integration_time` + * set `nr_of_starts=1` + * `prepare()` * `count_raw()` * Implement `count_continuous` (previous `measure`) method according to the following pseudo code: - * `prepare(synchronization & starts = 1)` where synchronization may + * `prepare()` where synchronization may contain the continuous acquisition description * `subscribeValueBuffer()` * `count_raw()` @@ -280,7 +280,7 @@ StartOne(1) The same as option 2 but maintaining the backwards compatibility in the following way: * Acquisition actions will call the `LoadOne`, etc. methods depending on the -controllers implementations (more preciselly using the `inspect.getargspec` +controllers implementations (more precisely using the `inspect.getargspec` and counting the number of arguments). This will require much more complicated acquisition actions. From be43ea58e9d3e6a7bc8ea244ea65d1abc75b9215 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 12:06:29 +0200 Subject: [PATCH 161/652] Fix bug on test_aquisition --- src/sardana/pool/test/test_acquisition.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index 953e738e85..910abfbe29 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -181,6 +181,9 @@ def hw_step_acquisition(self, repetitions, integ_time): (channels,)) # creating acquisition actions main_element = FakeElement(self.pool) + # TODO: The main_element should have a configuration + main_element.configuration = self.acq_cfg + self.ct_acq = PoolAcquisitionSoftware(main_element) for channel in channels: self.ct_acq.add_element(channel) From 6f05436b00ee1e735312059cce873420f436512d Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 12:12:44 +0200 Subject: [PATCH 162/652] Add Prepare cmd to MG (Tango) --- src/sardana/tango/pool/MeasurementGroup.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sardana/tango/pool/MeasurementGroup.py b/src/sardana/tango/pool/MeasurementGroup.py index 027236e7f4..c6adc9bd00 100644 --- a/src/sardana/tango/pool/MeasurementGroup.py +++ b/src/sardana/tango/pool/MeasurementGroup.py @@ -269,6 +269,9 @@ def write_SoftwareSynchronizerInitialDomain(self, attr): raise Exception("Invalid domain (can be either Position or Time)") self.measurement_group.sw_synch_initial_domain = domain + def Prepare(self): + self.measurement_group.prepare() + def Start(self): try: self.wait_for_operation() @@ -300,6 +303,7 @@ class MeasurementGroupClass(PoolGroupDeviceClass): # Command definitions cmd_list = { + 'Prepare': [[DevVoid, ""], [DevVoid, ""]], 'Start': [[DevVoid, ""], [DevVoid, ""]], 'StartMultiple': [[DevLong, ""], [DevVoid, ""]], } From cfa965d4233d5159c79146f5a7cadc82ee3874cb Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 8 Oct 2018 12:21:12 +0200 Subject: [PATCH 163/652] Add NrOfStarts to MG taurus ext --- src/sardana/taurus/core/tango/sardana/pool.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 2ec007f69d..5bafd0068c 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1670,6 +1670,16 @@ def setSynchronization(self, synchronization): self.getSynchronizationObj().write(data) self._last_integ_time = None + # NrOfStarts Methods + def getNrOfStartsObj(self): + return self._getAttrEG('NrOfStarts') + + def setNrOfStarts(self, starts): + self.getNrOfStartsObj().write(starts) + + def getNrOfStarts(self): + return self._getAttrValue('NrOfStarts') + def getMoveableObj(self): return self._getAttrEG('Moveable') From 68c79e373ce5dfb79f4d7faa9d9e1a93fe7662f9 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 12:27:29 +0200 Subject: [PATCH 164/652] Add nr_of_starts MG property --- src/sardana/pool/poolmeasurementgroup.py | 29 ++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index c7279ee7ee..76c872ce56 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -130,7 +130,7 @@ class PoolMeasurementGroup(PoolGroupElement): def __init__(self, **kwargs): self._state_lock = threading.Lock() self._monitor_count = None - self._repetitions = 1 + self._nr_of_starts = 1 self._acquisition_mode = AcqMode.Timer self._config = None self._config_dirty = True @@ -698,6 +698,10 @@ def get_latency_time(self): doc="latency time between two consecutive " "acquisitions") + # ------------------------------------------------------------------------- + # software synchronizer initial domain + # ------------------------------------------------------------------------- + def get_sw_synch_initial_domain(self): return self._sw_synch_initial_domain @@ -711,16 +715,33 @@ def set_sw_synch_initial_domain(self, domain): "or SynchDomain.Position)" ) + # ------------------------------------------------------------------------- + # number of starts + # ------------------------------------------------------------------------- + + def get_nr_of_starts(self): + return self._nr_of_starts + + def set_nr_of_starts(self, nr_of_starts, propagate=1): + self._nr_of_starts = nr_of_starts + if not propagate: + return + self.fire_event(EventType("nr_of_starts", priority=propagate), + nr_of_starts) + + nr_of_starts = property(get_nr_of_starts, set_nr_of_starts, + doc="current number of starts") + # ------------------------------------------------------------------------- # acquisition # ------------------------------------------------------------------------- def prepare(self): + # load configuration into controller(s) if necessary self.load_configuration() config = self.get_configuration() - repetitions = self.synchronization.repetitions - self.acquisition.prepare(config, repetitions) - + nr_of_starts = self.nr_of_starts + self.acquisition.prepare(config, nr_of_starts) def start_acquisition(self, value=None, multiple=1): self._aborted = False From b2781a24ab82a1ad522317406d1c7720585894c9 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 12:38:24 +0200 Subject: [PATCH 165/652] Rename Repetitions (unused) Tango attr to NrOfStarts of MG --- src/sardana/tango/pool/MeasurementGroup.py | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sardana/tango/pool/MeasurementGroup.py b/src/sardana/tango/pool/MeasurementGroup.py index c6adc9bd00..aebfa64a49 100644 --- a/src/sardana/tango/pool/MeasurementGroup.py +++ b/src/sardana/tango/pool/MeasurementGroup.py @@ -74,9 +74,9 @@ def init_device(self): PoolGroupDevice.init_device(self) # state and status are already set by the super class detect_evts = "latencytime", "moveable", "synchronization", \ - "softwaresynchronizerinitialdomain" + "softwaresynchronizerinitialdomain", "nrofstarts" non_detect_evts = "configuration", "integrationtime", "monitorcount", \ - "acquisitionmode", "elementlist", "repetitions" + "acquisitionmode", "elementlist" self.set_change_events(detect_evts, non_detect_evts) self.Elements = list(self.Elements) @@ -220,14 +220,14 @@ def write_Configuration(self, attr): cfg = CodecFactory().decode(('json', data), ensure_ascii=True) self.measurement_group.set_configuration_from_user(cfg) - def read_Repetitions(self, attr): - repetitions = self.measurement_group.repetitions - if repetitions is None: - repetitions = int('nan') - attr.set_value(repetitions) + def read_NrOfStarts(self, attr): + nr_of_starts = self.measurement_group.nr_of_starts + if nr_of_starts is None: + nr_of_starts = int('nan') + attr.set_value(nr_of_starts) - def write_Repetitions(self, attr): - self.measurement_group.repetitions = attr.get_write_value() + def write_NrOfStarts(self, attr): + self.measurement_group.nr_of_starts = attr.get_write_value() def read_Moveable(self, attr): moveable = self.measurement_group.moveable @@ -323,9 +323,9 @@ class MeasurementGroupClass(PoolGroupDeviceClass): 'Configuration': [[DevString, SCALAR, READ_WRITE], {'Memorized': "true", 'Display level': DispLevel.EXPERT}], - 'Repetitions': [[DevLong, SCALAR, READ_WRITE], - {'Memorized': "true", - 'Display level': DispLevel.OPERATOR}], + 'NrOfStarts': [[DevLong, SCALAR, READ_WRITE], + {'Memorized': "true", + 'Display level': DispLevel.OPERATOR}], 'Moveable': [[DevString, SCALAR, READ_WRITE], {'Memorized': "true", 'Display level': DispLevel.EXPERT}], From 9e1961f6bc502fe5f91694fd832fa4cf3c74126a Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 8 Oct 2018 13:02:58 +0200 Subject: [PATCH 166/652] Add count method to MG taurus ext --- src/sardana/taurus/core/tango/sardana/pool.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 5bafd0068c..1dbcfbad5b 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1864,9 +1864,17 @@ class on a provisional basis. Backwards incompatible changes self._total_go_time = time.time() - start_time return ret + + def count(self, integration_time): + self.setIntegrationTime(integration_time) + self.setNrOfStarts(1) + self.prepare() + self.count_raw(self) + startCount = PoolElement.start waitCount = PoolElement.waitFinish count = go + count_raw = PoolElement.go stopCount = PoolElement.abort stop = PoolElement.stop From 331a0c87d00341732fecab494a0f85e63c295958 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 8 Oct 2018 13:04:10 +0200 Subject: [PATCH 167/652] Rename measure method to count_continuous, MG taurus ext --- src/sardana/macroserver/scan/gscan.py | 4 ++-- src/sardana/taurus/core/tango/sardana/pool.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index efe88df81a..0a085e8ce8 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -2662,8 +2662,8 @@ def scan_loop(self): hook() yield 0 - measurement_group.measure(synchronization, - self.value_buffer_changed) + measurement_group.count_continuous(synchronization, + self.value_buffer_changed) self.debug("Waiting for value buffer events to be processed") self.wait_value_buffer() self.join_thread_pool() diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 1dbcfbad5b..a23f2a251b 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1812,12 +1812,12 @@ def go(self, *args, **kwargs): start_time = time.time() cfg = self.getConfiguration() cfg.prepare() - duration = args[0] - if duration is None or duration == 0: + integration_time = args[0] + if integration_time is None or integration_time == 0: return self.getStateEG().readValue(), self.getValues() - self.putIntegrationTime(duration) + self.putIntegrationTime(integration_time) self.setMoveable(None) - PoolElement.go(self, *args, **kwargs) + self.count_raw(self) state = self.getStateEG().readValue() if state == Fault: msg = "Measurement group ended acquisition with Fault state" @@ -1827,7 +1827,7 @@ def go(self, *args, **kwargs): self._total_go_time = time.time() - start_time return ret - def measure(self, synchronization, value_buffer_cb=None): + def count_continuous(self, synchronization, value_buffer_cb=None): """Execute measurement process according to the given synchronization description. @@ -1850,7 +1850,7 @@ class on a provisional basis. Backwards incompatible changes cfg.prepare() self.setSynchronization(synchronization) self.subscribeValueBuffer(value_buffer_cb) - PoolElement.go(self) + self.count_raw(self) self.unsubscribeValueBuffer(value_buffer_cb) state = self.getStateEG().readValue() if state == Fault: From 4ba148da4b4fba47ef5e945ee20913efd53edfb6 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Mon, 8 Oct 2018 13:29:56 +0200 Subject: [PATCH 168/652] (doc) Extend explanation of optional parameters The current explanation of optional macro parameters is too terse. Extend it. --- doc/source/devel/howto_macros/macros_general.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 3ef5acfccb..b179dea6c8 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -330,8 +330,13 @@ all available sardana interfaces (:obj:`~sardana.sardanadefs.Interface`) Optional parameters ~~~~~~~~~~~~~~~~~~~ -A special parameter default value is the ``Optional``. It allows to -execute a macro even if the given parameter value is not specified by the user. +A special parameter default value is the ``Optional`` keyword. A parameter +whose default value is set to ``Optional`` behaves just as one with a default +value, except that if the user does not provide a value explicitly, the +handling of its value is deferred to the run method (which gets ``None`` as +the parameter value). This allows for more complex handling of the value +(e.g. interactive prompting to the user, system introspection, reading from +files, etc.) So, here is an example how to define and use the optional parameter:: From 85828e42afed6b2a0c88064151592020773e3c14 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 14:22:01 +0200 Subject: [PATCH 169/652] Add backwards compatibility for direct use of MG start --- src/sardana/pool/poolmeasurementgroup.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 76c872ce56..6a65ecd050 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -131,6 +131,7 @@ def __init__(self, **kwargs): self._state_lock = threading.Lock() self._monitor_count = None self._nr_of_starts = 1 + self._pending_starts = 0 self._acquisition_mode = AcqMode.Timer self._config = None self._config_dirty = True @@ -741,13 +742,24 @@ def prepare(self): self.load_configuration() config = self.get_configuration() nr_of_starts = self.nr_of_starts + self._pending_starts = nr_of_starts self.acquisition.prepare(config, nr_of_starts) def start_acquisition(self, value=None, multiple=1): + if self._pending_starts == 0: + msg = "starting acquisition without prior preparing is " \ + "deprecated since version Jan18." + self.warning(msg) + self.debug("Preparing with number_of_starts equal to 1") + nr_of_starts = self.nr_of_starts + self.set_nr_of_starts(1, propagate=0) + try: + self.prepare() + finally: + self.set_nr_of_starts(nr_of_starts, propagate=0) self._aborted = False + self._pending_starts -= 1 if not self._simulation_mode: - # load configuration into controller(s) if necessary - self.load_configuration() # determining the acquisition parameters kwargs = dict(head=self, config=self._config, multiple=multiple) acquisition_mode = self.acquisition_mode @@ -770,5 +782,10 @@ def get_acquisition(self): acquisition = property(get_acquisition, doc="acquisition object") def stop(self): + self._pending_starts = 0 self.acquisition._synch._synch_soft.stop() PoolGroupElement.stop(self) + + def abort(self): + self._pending_starts = 0 + PoolGroupElement.abort(self) From f0aae07cbbfe62572fc73f8bd43fc0b43265e693 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Mon, 8 Oct 2018 14:30:58 +0200 Subject: [PATCH 170/652] Add support to new synchronization types in dummy C/T controller Extend LoadOne input parameters according SEP18 and add support to new synchronization types. --- .../DummyCounterTimerController.py | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py b/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py index 3f94eb7886..94b4a7bdda 100644 --- a/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py +++ b/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py @@ -30,17 +30,25 @@ Description, Memorize, NotMemorized -class Channel: +class Channel(object): def __init__(self, idx): self.idx = idx # 1 based index self.value = 0.0 self.is_counting = False self.active = True - self.repetitions = 0 + self.repetitions = 1 + self.acq_latency_time = 0 self._counter = 0 self.mode = AcqSynch.SoftwareTrigger self.buffer_values = [] + self.estimated_duration = None + + def calculate_duration(self, intergration_time): + if self.mode not in (AcqSynch.SoftwareStart, AcqSynch.HardwareStart): + self.acq_latency_time = 0 + self.estimated_duration = (intergration_time + + self.acq_latency_time) * self.repetitions class DummyCounterTimerController(CounterTimerController): @@ -117,12 +125,13 @@ def _updateChannelState(self, ind, elapsed_time): v = int(elapsed_time * 100 * ind) if v >= self.monitor_count: self._finish(elapsed_time) - elif channel.mode in (AcqSynch.HardwareTrigger, AcqSynch.HardwareGate): + elif channel.mode in (AcqSynch.HardwareTrigger, + AcqSynch.HardwareGate, + AcqSynch.SoftwareStart, + AcqSynch.HardwareStart): if self.integ_time is not None: # counting in time - # if elapsed_time >= self.integ_time*channel.repetitions: - if elapsed_time > channel.repetitions * (self.integ_time + - self._latency_time): + if elapsed_time > channel.estimated_duration: # if elapsed_time >= self.integ_time: self._finish(elapsed_time) @@ -142,7 +151,10 @@ def _updateChannelValue(self, ind, elapsed_time): if ind == self._monitor: if not channel.is_counting: channel.value = self.monitor_count - elif channel.mode in (AcqSynch.HardwareTrigger, AcqSynch.HardwareGate): + elif channel.mode in (AcqSynch.HardwareTrigger, + AcqSynch.HardwareGate, + AcqSynch.SoftwareStart, + AcqSynch.HardwareStart): if self.integ_time is not None: t = elapsed_time n = int(t / self.integ_time) @@ -192,7 +204,10 @@ def ReadOne(self, ind): self._log.debug('ReadOne(%d): entering...' % ind) channel = self.read_channels[ind] ret = None - if channel.mode in (AcqSynch.HardwareTrigger, AcqSynch.HardwareGate): + if channel.mode in (AcqSynch.HardwareTrigger, + AcqSynch.HardwareGate, + AcqSynch.SoftwareStart, + AcqSynch.HardwareStart): values = copy.deepcopy(channel.buffer_values) ret = [] for v in values: @@ -225,17 +240,19 @@ def StartOne(self, ind, value=None): def StartAll(self): self.start_time = time.time() - def LoadOne(self, ind, value, repetitions): + def LoadOne(self, ind, value, repetitions, latency_time): if value > 0: self.integ_time = value self.monitor_count = None else: self.integ_time = None self.monitor_count = -value - self._repetitions = repetitions + for channel in self.channels: if channel: channel.repetitions = repetitions + channel.acq_latency_time = latency_time + channel.calculate_duration(value) def AbortOne(self, ind): now = time.time() From 44082184ac177665875db618b36a11399301fbb0 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 8 Oct 2018 15:15:40 +0200 Subject: [PATCH 171/652] flake8 fix --- src/sardana/taurus/core/tango/sardana/pool.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index a23f2a251b..859e40b716 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1864,7 +1864,6 @@ class on a provisional basis. Backwards incompatible changes self._total_go_time = time.time() - start_time return ret - def count(self, integration_time): self.setIntegrationTime(integration_time) self.setNrOfStarts(1) @@ -1873,7 +1872,6 @@ def count(self, integration_time): startCount = PoolElement.start waitCount = PoolElement.waitFinish - count = go count_raw = PoolElement.go stopCount = PoolElement.abort stop = PoolElement.stop From 322febdfde6fc6757aa7827cccc68a5cccc88273 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 12:01:35 +0200 Subject: [PATCH 172/652] SEP: remove arguments from prepare command --- doc/source/sep/SEP18.md | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 6c03386b67..165debefd4 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -89,36 +89,36 @@ Implementation ### Measurement Group -Measurement group is extended by the *prepare* command with two parameters: -synchronization description and number of starts. The second one indicates -how many times measurement group will be started, with the *start* command, -to measure according to the synchronization description. +Measurement group is extended by the *prepare* command (with no arguments) +*number of starts* attribute. The use of the attribute is optional and +it indicates how many times measurement group will be started, with the +*start* command, to measure according to the synchronization description or +integration time. When it is not used number of starts of 1 will be assumed. 1. Measurement group - Tango device class - * Add `Prepare` command. TODO: investigate the best way to pass - synchronization description, as JSON serialized string, together with the - starts integer. - * Remove `synchronization` attribute (experimental API) - no backwards - compatibility. + * Add `Prepare` command. + * Add `NrOfStarts` (`DevLong`) attribute. 2. Measurement group - core class - * Add `prepare(synchronization, starts=1)` method - * Remove `synchronization` property (experimental API) - no backwards - compatibility. -3. Backwards compatibility for integration time attribute will be solved in -the following way: setting of integration time attribute will allow starts -until the next preparation. + * Add `prepare()` method. + * Add `nr_of_starts` property. +3. Backwards compatibility for using just the integration time attribute with +the start command (without calling prepare command in-between) will be +solved in the following way: start command will internally call the prepare. 4. Measurement group - Taurus extension - * Add `prepare` method which simply maps to `Prepare` Tango command + * Add `prepare()` method which simply maps to `Prepare` Tango command * Add `count_raw` method according to the following pseudo code: * `start()` * `waitFinish()` - * Implement `count` method according to the following pseudo code: - * `prepare(synchronization & starts = 1)` where synchronization - contains the integration time + * Implement `count(integration_time)` method according to the following + pseudo + code: + * set `integration_time` + * set `nr_of_starts=1` + * `prepare()` * `count_raw()` * Implement `count_continuous` (previous `measure`) method according to the following pseudo code: - * `prepare(synchronization & starts = 1)` where synchronization may + * `prepare()` where synchronization may contain the continuous acquisition description * `subscribeValueBuffer()` * `count_raw()` @@ -280,7 +280,7 @@ StartOne(1) The same as option 2 but maintaining the backwards compatibility in the following way: * Acquisition actions will call the `LoadOne`, etc. methods depending on the -controllers implementations (more preciselly using the `inspect.getargspec` +controllers implementations (more precisely using the `inspect.getargspec` and counting the number of arguments). This will require much more complicated acquisition actions. From 294326138497779825594d44ceef6ad1dc46a588 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 12:12:44 +0200 Subject: [PATCH 173/652] Add Prepare cmd to MG (Tango) --- src/sardana/tango/pool/MeasurementGroup.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sardana/tango/pool/MeasurementGroup.py b/src/sardana/tango/pool/MeasurementGroup.py index 027236e7f4..c6adc9bd00 100644 --- a/src/sardana/tango/pool/MeasurementGroup.py +++ b/src/sardana/tango/pool/MeasurementGroup.py @@ -269,6 +269,9 @@ def write_SoftwareSynchronizerInitialDomain(self, attr): raise Exception("Invalid domain (can be either Position or Time)") self.measurement_group.sw_synch_initial_domain = domain + def Prepare(self): + self.measurement_group.prepare() + def Start(self): try: self.wait_for_operation() @@ -300,6 +303,7 @@ class MeasurementGroupClass(PoolGroupDeviceClass): # Command definitions cmd_list = { + 'Prepare': [[DevVoid, ""], [DevVoid, ""]], 'Start': [[DevVoid, ""], [DevVoid, ""]], 'StartMultiple': [[DevLong, ""], [DevVoid, ""]], } From c9480ab86d15b4dbb25459073e24c2b4cc5c77de Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 12:27:29 +0200 Subject: [PATCH 174/652] Add nr_of_starts MG property --- src/sardana/pool/poolmeasurementgroup.py | 29 ++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index c7279ee7ee..76c872ce56 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -130,7 +130,7 @@ class PoolMeasurementGroup(PoolGroupElement): def __init__(self, **kwargs): self._state_lock = threading.Lock() self._monitor_count = None - self._repetitions = 1 + self._nr_of_starts = 1 self._acquisition_mode = AcqMode.Timer self._config = None self._config_dirty = True @@ -698,6 +698,10 @@ def get_latency_time(self): doc="latency time between two consecutive " "acquisitions") + # ------------------------------------------------------------------------- + # software synchronizer initial domain + # ------------------------------------------------------------------------- + def get_sw_synch_initial_domain(self): return self._sw_synch_initial_domain @@ -711,16 +715,33 @@ def set_sw_synch_initial_domain(self, domain): "or SynchDomain.Position)" ) + # ------------------------------------------------------------------------- + # number of starts + # ------------------------------------------------------------------------- + + def get_nr_of_starts(self): + return self._nr_of_starts + + def set_nr_of_starts(self, nr_of_starts, propagate=1): + self._nr_of_starts = nr_of_starts + if not propagate: + return + self.fire_event(EventType("nr_of_starts", priority=propagate), + nr_of_starts) + + nr_of_starts = property(get_nr_of_starts, set_nr_of_starts, + doc="current number of starts") + # ------------------------------------------------------------------------- # acquisition # ------------------------------------------------------------------------- def prepare(self): + # load configuration into controller(s) if necessary self.load_configuration() config = self.get_configuration() - repetitions = self.synchronization.repetitions - self.acquisition.prepare(config, repetitions) - + nr_of_starts = self.nr_of_starts + self.acquisition.prepare(config, nr_of_starts) def start_acquisition(self, value=None, multiple=1): self._aborted = False From ca4ff0cbfee798c0bfa4c386791c5712fed0b081 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 12:38:24 +0200 Subject: [PATCH 175/652] Rename Repetitions (unused) Tango attr to NrOfStarts of MG --- src/sardana/tango/pool/MeasurementGroup.py | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sardana/tango/pool/MeasurementGroup.py b/src/sardana/tango/pool/MeasurementGroup.py index c6adc9bd00..aebfa64a49 100644 --- a/src/sardana/tango/pool/MeasurementGroup.py +++ b/src/sardana/tango/pool/MeasurementGroup.py @@ -74,9 +74,9 @@ def init_device(self): PoolGroupDevice.init_device(self) # state and status are already set by the super class detect_evts = "latencytime", "moveable", "synchronization", \ - "softwaresynchronizerinitialdomain" + "softwaresynchronizerinitialdomain", "nrofstarts" non_detect_evts = "configuration", "integrationtime", "monitorcount", \ - "acquisitionmode", "elementlist", "repetitions" + "acquisitionmode", "elementlist" self.set_change_events(detect_evts, non_detect_evts) self.Elements = list(self.Elements) @@ -220,14 +220,14 @@ def write_Configuration(self, attr): cfg = CodecFactory().decode(('json', data), ensure_ascii=True) self.measurement_group.set_configuration_from_user(cfg) - def read_Repetitions(self, attr): - repetitions = self.measurement_group.repetitions - if repetitions is None: - repetitions = int('nan') - attr.set_value(repetitions) + def read_NrOfStarts(self, attr): + nr_of_starts = self.measurement_group.nr_of_starts + if nr_of_starts is None: + nr_of_starts = int('nan') + attr.set_value(nr_of_starts) - def write_Repetitions(self, attr): - self.measurement_group.repetitions = attr.get_write_value() + def write_NrOfStarts(self, attr): + self.measurement_group.nr_of_starts = attr.get_write_value() def read_Moveable(self, attr): moveable = self.measurement_group.moveable @@ -323,9 +323,9 @@ class MeasurementGroupClass(PoolGroupDeviceClass): 'Configuration': [[DevString, SCALAR, READ_WRITE], {'Memorized': "true", 'Display level': DispLevel.EXPERT}], - 'Repetitions': [[DevLong, SCALAR, READ_WRITE], - {'Memorized': "true", - 'Display level': DispLevel.OPERATOR}], + 'NrOfStarts': [[DevLong, SCALAR, READ_WRITE], + {'Memorized': "true", + 'Display level': DispLevel.OPERATOR}], 'Moveable': [[DevString, SCALAR, READ_WRITE], {'Memorized': "true", 'Display level': DispLevel.EXPERT}], From c7cbd13feb285d784844ae9d2e8f69a9721ef023 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 14:22:01 +0200 Subject: [PATCH 176/652] Add backwards compatibility for direct use of MG start --- src/sardana/pool/poolmeasurementgroup.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 76c872ce56..6a65ecd050 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -131,6 +131,7 @@ def __init__(self, **kwargs): self._state_lock = threading.Lock() self._monitor_count = None self._nr_of_starts = 1 + self._pending_starts = 0 self._acquisition_mode = AcqMode.Timer self._config = None self._config_dirty = True @@ -741,13 +742,24 @@ def prepare(self): self.load_configuration() config = self.get_configuration() nr_of_starts = self.nr_of_starts + self._pending_starts = nr_of_starts self.acquisition.prepare(config, nr_of_starts) def start_acquisition(self, value=None, multiple=1): + if self._pending_starts == 0: + msg = "starting acquisition without prior preparing is " \ + "deprecated since version Jan18." + self.warning(msg) + self.debug("Preparing with number_of_starts equal to 1") + nr_of_starts = self.nr_of_starts + self.set_nr_of_starts(1, propagate=0) + try: + self.prepare() + finally: + self.set_nr_of_starts(nr_of_starts, propagate=0) self._aborted = False + self._pending_starts -= 1 if not self._simulation_mode: - # load configuration into controller(s) if necessary - self.load_configuration() # determining the acquisition parameters kwargs = dict(head=self, config=self._config, multiple=multiple) acquisition_mode = self.acquisition_mode @@ -770,5 +782,10 @@ def get_acquisition(self): acquisition = property(get_acquisition, doc="acquisition object") def stop(self): + self._pending_starts = 0 self.acquisition._synch._synch_soft.stop() PoolGroupElement.stop(self) + + def abort(self): + self._pending_starts = 0 + PoolGroupElement.abort(self) From c0b3f6247cf802aff760ad9579e9bb4bd50b9dfd Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 15:05:59 +0200 Subject: [PATCH 177/652] Use new API of prepare in step scan --- src/sardana/macroserver/scan/gscan.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index 0a085e8ce8..17d7794918 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -1010,9 +1010,9 @@ def scan_loop(self): nr_points = float(macro.nr_points) if hasattr(macro, "integ_time"): integ_time = macro.integ_time - group = {SynchParam.Active: {SynchDomain.Time: integ_time}} - synchronization = [group] - self.measurement_group.prepare(synchronization, nr_points) + self.measurement_group.putIntegrationTime(integ_time) + self.measurement_group.setNrOfStarts(nr_points) + self.measurement_group.prepare() scream = True else: yield 0.0 From 38f66fc6d1393df88e33848ad134c162eff3f53e Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 15:07:12 +0200 Subject: [PATCH 178/652] Comment calls to new configuration API --- src/sardana/pool/poolacquisition.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 9a998b35d2..92f271a423 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -241,14 +241,14 @@ def event_received(self, *args, **kwargs): self.debug('Stopping ZeroD acquisition.') self._0d_acq.stop_action() - def prepare(self, config, repetitions): + def prepare(self, config, nr_of_starts): """Prepare measurement.""" - timers = config.get_timers(enabled=True) + timers = [] #config.get_timers(enabled=True) for timer in timers: axis = timer.axis timer_ctrl = timer.controller ctrl = timer_ctrl.ctrl - ctrl.PrepareOne(axis, repetitions) + ctrl.PrepareOne(axis, nr_of_starts) def is_running(self): return self._0d_acq.is_running() or\ From f26022b7fa60a463718bea03632bd5b1a51cdf47 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 15:21:32 +0200 Subject: [PATCH 179/652] Rename internal methods --- src/sardana/pool/poolmeasurementgroup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index afc9165210..097f4ba80e 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -134,9 +134,9 @@ def __init__(self, parent=None): self._parent = weakref.ref(parent)() self._config = None self.use_fqdn = True - self._init_data() + self._clean_variables() - def _init_data(self): + def _clean_variables(self): # list of controller with channels enabled. self.enabled_ctrls = [] # dict with channel and its acquisition synchronization @@ -377,7 +377,7 @@ def _build_channel_defaults(self, channel_data, channel): def _build_configuration(self, config=None): """Builds a configuration object from the list of elements""" - self._init_data() + self._clean_variables() if config is None: config = {} @@ -521,9 +521,9 @@ def _build_configuration(self, config=None): g_monitor.name) self._config = config - self._prepare_data() + self._split_sync() - def _prepare_data(self): + def _split_sync(self): """ Split MeasurementGroup configuration with channels triggered by SW Trigger and channels triggered by HW trigger From 1919226ae8a979cc847951e5d1541ac5a1603791 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 15:23:08 +0200 Subject: [PATCH 180/652] Add trigger gate configuration Add method to extract the trigger/gate configurations --- src/sardana/pool/poolmeasurementgroup.py | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 097f4ba80e..7e7d9eaa2d 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -150,6 +150,7 @@ def _clean_variables(self): self.ctrl_hw_sync = {} self.ctrl_sw_start = {} self.ctrl_0d_sync = {} + self.ctrl_tg_sync = {} # TODO: Do the documentation self.sw_sync_timer = None self.sw_sync_monitor = None @@ -522,6 +523,7 @@ def _build_configuration(self, config=None): self._config = config self._split_sync() + self._split_tg() def _split_sync(self): """ @@ -579,6 +581,39 @@ def find_master(ctrls, role): self.hw_sync_timer = find_master(self.ctrl_hw_sync, "timer") self.hw_sync_monitor = find_master(self.ctrl_hw_sync, "monitor") + def _split_tg(self): + """ + Build TG configuration from complete configuration. + """ + + # Create list with not repeated elements + _tg_element_list = [] + + for ctrl in self._config["controllers"]: + tg_element = self._config["controllers"][ctrl].get('synchronizer', + None) + if (tg_element is not None and + tg_element != "software" and + tg_element not in _tg_element_list): + _tg_element_list.append(tg_element) + + # Intermediate dictionary to organize each ctrl with its elements. + ctrl_tgelem_dict = {} + for tgelem in _tg_element_list: + tg_ctrl = tgelem.get_controller() + if tg_ctrl not in ctrl_tgelem_dict.keys(): + ctrl_tgelem_dict[tg_ctrl] = [tgelem] + else: + ctrl_tgelem_dict[tg_ctrl].append(tgelem) + + # Build TG configuration dictionary. + for ctrl in ctrl_tgelem_dict: + self.ctrl_tg_sync[ctrl] = ctrls = {} + ctrls['channels'] = {} + for tg_elem in ctrl_tgelem_dict[ctrl]: + ch = ctrls['channels'][tg_elem] = {} + ch['full_name'] = tg_elem.full_name + class PoolMeasurementGroup(PoolGroupElement): From 29f59746d8c9976a5de5e07ed29d2afb7879ff88 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 8 Oct 2018 15:24:19 +0200 Subject: [PATCH 181/652] Adapt go method to SEP18 --- src/sardana/taurus/core/tango/sardana/pool.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 859e40b716..5ce37c56ba 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1817,6 +1817,8 @@ def go(self, *args, **kwargs): return self.getStateEG().readValue(), self.getValues() self.putIntegrationTime(integration_time) self.setMoveable(None) + self.setNrOfStarts(1) + self.prepare() self.count_raw(self) state = self.getStateEG().readValue() if state == Fault: @@ -1864,14 +1866,9 @@ class on a provisional basis. Backwards incompatible changes self._total_go_time = time.time() - start_time return ret - def count(self, integration_time): - self.setIntegrationTime(integration_time) - self.setNrOfStarts(1) - self.prepare() - self.count_raw(self) - startCount = PoolElement.start waitCount = PoolElement.waitFinish + count = go count_raw = PoolElement.go stopCount = PoolElement.abort stop = PoolElement.stop From ab28ce6210abb6bfe2789cde8b69c2120376253c Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 15:27:16 +0200 Subject: [PATCH 182/652] Use trigger/gate configuration from MeasurementConfiguration --- src/sardana/pool/poolacquisition.py | 48 ----------------------------- 1 file changed, 48 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 22e69f7de6..9bd8406ebe 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -62,52 +62,6 @@ } -def getTGConfiguration(MGcfg): - '''Build TG configuration from complete MG configuration. - - TODO: (technical debt) All the MeasurementGroup configuration - logic should be encapsulate in a dedicated class instead of - using a basic data structures like dict or lists... - - :param MGcfg: configuration dictionary of the whole Measurement Group. - :type MGcfg: dict<> - :return: a configuration dictionary of TG elements organized by controller - :rtype: dict<> - ''' - - # Create list with not repeated elements - _tg_element_list = [] - - for ctrl in MGcfg["controllers"]: - tg_element = MGcfg["controllers"][ctrl].get('synchronizer', None) - if (tg_element is not None and - tg_element != "software" and - tg_element not in _tg_element_list): - _tg_element_list.append(tg_element) - - # Intermediate dictionary to organize each ctrl with its elements. - ctrl_tgelem_dict = {} - for tgelem in _tg_element_list: - tg_ctrl = tgelem.get_controller() - if tg_ctrl not in ctrl_tgelem_dict.keys(): - ctrl_tgelem_dict[tg_ctrl] = [tgelem] - else: - ctrl_tgelem_dict[tg_ctrl].append(tgelem) - - # Build TG configuration dictionary. - TGcfg = {} - TGcfg['controllers'] = {} - - for ctrl in ctrl_tgelem_dict: - TGcfg['controllers'][ctrl] = ctrls = {} - ctrls['channels'] = {} - for tg_elem in ctrl_tgelem_dict[ctrl]: - ch = ctrls['channels'][tg_elem] = {} - ch['full_name'] = tg_elem.full_name - # TODO: temporary returning tg_elements - return TGcfg, _tg_element_list - - def is_value_error(value): if isinstance(value, SardanaValue) and value.error: return True @@ -221,7 +175,6 @@ def run(self, *args, **kwargs): integ_time = synchronization.integration_time repetitions = synchronization.repetitions - synch_cfg, _ = getTGConfiguration(config) # starting continuous acquisition only if there are any controllers if len(config.ctrl_hw_sync): cont_acq_kwargs = dict(kwargs) @@ -240,7 +193,6 @@ def run(self, *args, **kwargs): # TODO: Ask why self.set_0d_config(zerod_acq_kwargs) synch_kwargs = dict(kwargs) - synch_kwargs['config'] = synch_cfg self._synch.run(*args, **synch_kwargs) def _get_action_for_element(self, element): From 1d796ba903e4c82ca53f740ba44e380acbfb3cba Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 15:28:10 +0200 Subject: [PATCH 183/652] Adapt to use MeasurementConfiguration class --- src/sardana/pool/poolsynchronization.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolsynchronization.py b/src/sardana/pool/poolsynchronization.py index 850dff9378..1cfca7ba09 100644 --- a/src/sardana/pool/poolsynchronization.py +++ b/src/sardana/pool/poolsynchronization.py @@ -140,11 +140,12 @@ def start_action(self, *args, **kwargs): - sw_synch_initial_domain (optional) - initial domain for software synchronizer, can be either SynchDomain.Time or SynchDomain.Position ''' - cfg = kwargs['config'] + + cfg = self.main_element.configuration synchronization = kwargs.get('synchronization') moveable = kwargs.get('moveable') sw_synch_initial_domain = kwargs.get('sw_synch_initial_domain', None) - ctrls_config = cfg.get('controllers') + ctrls_config = cfg.ctrl_tg_sync pool_ctrls = ctrls_config.keys() # Prepare a dictionary with the involved channels From d7fdbf7cf931d4f9ce3a6ee50a47d203e1929e7e Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 15:28:59 +0200 Subject: [PATCH 184/652] Adapt test to use MeasurementConfiguration class --- src/sardana/pool/test/helper.py | 6 +++++- src/sardana/pool/test/test_acquisition.py | 8 +++++--- src/sardana/pool/test/test_poolsynchronization.py | 2 ++ src/sardana/pool/test/test_synchronization.py | 5 ++++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index 5d9cc97f8e..6cd87dfe33 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -174,7 +174,11 @@ def createPoolSynchronizationConfiguration(ctrls, ctrl_channels): ctrl_data['channels'][channel] = channel_conf ctrls_configuration[ctrl] = ctrl_data configuration = {'controllers': ctrls_configuration} - return configuration + + mc = MeasurementConfiguration() + mc._config = configuration + mc.ctrl_tg_sync = ctrls_configuration + return mc def createCTAcquisitionConfiguration(ctrls, ctrl_channels): diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index 910abfbe29..dd18c2c51e 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -99,8 +99,10 @@ def setUp(self): self.l = AttributeListener() self.channel_names = [] - def createPoolSynchronization(self, tg_list): + def createPoolSynchronization(self, tg_list, tg_config=None): self.main_element = FakeElement(self.pool) + # TODO: The TriggerGate should have a configuration + self.main_element.configuration = tg_config self.tggeneration = PoolSynchronization(self.main_element) for tg in tg_list: self.tggeneration.add_element(tg) @@ -119,7 +121,7 @@ def hw_continuous_acquisition(self, offset, active_interval, tg_cfg = createPoolSynchronizationConfiguration((tg_ctrl,), ((tg,),)) # creating PoolSynchronization action - self.createPoolSynchronization([tg]) + self.createPoolSynchronization([tg], tg_config=tg_cfg) channels = [] for name in self.channel_names: @@ -305,7 +307,7 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, tg_cfg = createPoolSynchronizationConfiguration((tg_ctrl_2,), ((tg_2_1,),)) # creating TGGeneration action - self.createPoolSynchronization([tg_2_1]) + self.createPoolSynchronization([tg_2_1], tg_config=tg_cfg) # add_listeners self.addListeners([ct_1_1, ct_2_1]) # creating acquisition configurations diff --git a/src/sardana/pool/test/test_poolsynchronization.py b/src/sardana/pool/test/test_poolsynchronization.py index 9e4fcb0014..22c2c706ff 100644 --- a/src/sardana/pool/test/test_poolsynchronization.py +++ b/src/sardana/pool/test/test_poolsynchronization.py @@ -63,6 +63,8 @@ def setUp(self): self.mock_tg_ctrl.StateOne.return_value = (State.Moving, 'triggering') dummy_tg_ctrl.ctrl = self.mock_tg_ctrl + # TODO: The TriggerGate should have a configuration + self.dummy_tg.configuration = self.cfg self.tgaction = PoolSynchronization(self.dummy_tg) self.tgaction.add_element(self.dummy_tg) diff --git a/src/sardana/pool/test/test_synchronization.py b/src/sardana/pool/test/test_synchronization.py index 53f36cb8fc..abe73a0f67 100644 --- a/src/sardana/pool/test/test_synchronization.py +++ b/src/sardana/pool/test/test_synchronization.py @@ -61,7 +61,10 @@ def createElements(self, ctrl_klass, ctrl_lib, ctrl_props): self.pool.add_element(self.tg_elem) # create Synchronization action and its configuration self.tg_cfg = createPoolSynchronizationConfiguration((self.tg_ctrl,), - ((self.tg_elem,),),) + ((self.tg_elem,),) + ,) + # TODO: The TriggerGate should have a configuration + self.tg_elem.configuration = self.tg_cfg self.tgaction = PoolSynchronization(self.tg_elem) self.tgaction.add_element(self.tg_elem) From 91323fe397b5041681f113112a3dfb514f53a737 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 8 Oct 2018 15:55:56 +0200 Subject: [PATCH 185/652] Fix flake8 --- src/sardana/pool/poolacquisition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 92f271a423..8eeba4a104 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -243,7 +243,7 @@ def event_received(self, *args, **kwargs): def prepare(self, config, nr_of_starts): """Prepare measurement.""" - timers = [] #config.get_timers(enabled=True) + timers = [] # config.get_timers(enabled=True) for timer in timers: axis = timer.axis timer_ctrl = timer.controller From 1ea9b6661c64667bd06add1393b0eeb96574e40e Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 16:53:09 +0200 Subject: [PATCH 186/652] Remove unused properties --- src/sardana/pool/poolmeasurementgroup.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 4fef0bf8c3..4223fc3701 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -169,16 +169,6 @@ def wrapper(self, *args, **kwargs): def __getitem__(self, item): return self._config.__getitem__(item) - @property - @__check_config - def timer(self): - return self._config['timer'] - - @property - @__check_config - def monitor(self): - return self._config['monitor'] - @property @__check_config def controllers(self): From 56aaeab4825916b60b34838d6591a4816b85aa50 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 17:15:10 +0200 Subject: [PATCH 187/652] Add new attributes for acquisition actions Add lists for timers and monitor for each the acquisition action type. --- src/sardana/pool/poolmeasurementgroup.py | 52 +++++++++++++++++++----- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 4223fc3701..fa24573ad1 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -139,6 +139,13 @@ def __init__(self, parent=None): def _clean_variables(self): # list of controller with channels enabled. self.enabled_ctrls = [] + # list of timers and monitors by synchronization type. + self.sw_sync_timers_enabled = [] + self.sw_sync_monitors_enabled = [] + self.sw_start_timers_enabled = [] + self.sw_start_monitors_enabled = [] + self.hw_sync_timers_enabled = [] + self.hw_sync_monitors_enabled = [] # dict with channel and its acquisition synchronization # key: PoolBaseChannel; value: AcqSynch self.channel_to_acq_synch = {} @@ -547,29 +554,52 @@ def _split_sync(self): else: self.ctrl_hw_sync[ctrl] = ctrl_info - def find_master(ctrls, role): + def get_master_enables(ctrls, role): master_idx = float("+inf") master = None + elements = [] for ctrl_info in ctrls.values(): element = ctrl_info[role] if element in ctrl_info["channels"]: element_idx = ctrl_info["channels"][element]["index"] element_enabled = ctrl_info["channels"][element]["enabled"] # Find master only if is enabled - if element_idx < master_idx and element_enabled: - master = element - master_idx = element_idx - return master + if element_enabled: + elements.append(element) + if element_idx < master_idx: + master = element + master_idx = element_idx + return master, elements if len(self.ctrl_sw_sync): - self.sw_sync_timer = find_master(self.ctrl_sw_sync, "timer") - self.sw_sync_monitor = find_master(self.ctrl_sw_sync, "monitor") + timer, timers = get_master_enables(self.ctrl_sw_sync, "timer") + self.sw_sync_timer = timer + self.sw_sync_timers_enabled = timers + + monitor, monitors = get_master_enables(self.ctrl_sw_sync, + "monitor") + self.sw_sync_monitor = monitor + self.sw_sync_monitors_enabled = monitors + if len(self.ctrl_sw_start): - self.sw_start_timer = find_master(self.ctrl_sw_start, "timer") - self.sw_start_monitor = find_master(self.ctrl_sw_start, "monitor") + timer, timers = get_master_enables(self.ctrl_sw_start, "timer") + self.sw_start_timer = timer + self.sw_start_timers_enabled = timers + + monitor, monitors = get_master_enables(self.ctrl_sw_start, + "monitor") + self.sw_start_monitor = monitor + self.sw_start_monitors_enabled = monitors + if len(self.ctrl_hw_sync): - self.hw_sync_timer = find_master(self.ctrl_hw_sync, "timer") - self.hw_sync_monitor = find_master(self.ctrl_hw_sync, "monitor") + timer, timers = get_master_enables(self.ctrl_hw_sync, "timer") + self.hw_sync_timer = timer + self.hw_sync_timers_enabled = timers + + monitor, monitors = get_master_enables(self.ctrl_hw_sync, + "monitor") + self.hw_sync_monitor = monitor + self.hw_sync_monitors_enabled = monitors def _split_tg(self): """ From 26dda09efe0e94a467d626aab1c50d9a1f5fa2da Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 8 Oct 2018 17:15:36 +0200 Subject: [PATCH 188/652] Use MeasurementConfiguration API --- src/sardana/pool/poolacquisition.py | 5 ++++- src/sardana/pool/poolmeasurementgroup.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 9bd8406ebe..ae819cac8c 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -141,7 +141,10 @@ def event_received(self, *args, **kwargs): def prepare(self, config, repetitions): """Prepare measurement.""" - timers = config.get_timers(enabled=True) + timers = config.sw_sync_timers_enabled + \ + config.sw_start_timers_enabled + \ + config.hw_sync_timers_enabled + for timer in timers: axis = timer.axis timer_ctrl = timer.controller diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index fa24573ad1..71c49e7174 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -938,7 +938,7 @@ def set_nr_of_starts(self, nr_of_starts, propagate=1): def prepare(self): # load configuration into controller(s) if necessary self.load_configuration() - config = self.get_configuration() + config = self.configuration nr_of_starts = self.nr_of_starts self._pending_starts = nr_of_starts self.acquisition.prepare(config, nr_of_starts) From 7b3e315417734e70ef186a13b5fc21fe142f9911 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 8 Oct 2018 17:49:47 +0200 Subject: [PATCH 189/652] Add backwards compat. for loadable ctrls without latency time --- src/sardana/pool/poolacquisition.py | 63 ++++++++++++++++++----------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 8eeba4a104..a30fffd4ba 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -551,36 +551,53 @@ def start_action(self, *args, **kwargs): pool_ctrls.remove(master_ctrl) pool_ctrls.append(master_ctrl) + def load(ctrl, master_axis, value, repetitions, latency=0): + ctrl.PreLoadAll() + try: + res = ctrl.PreLoadOne(master_axis, value, repetitions, + latency) + except TypeError: + try: + res = ctrl.PreLoadOne(master_axis, value, repetitions) + msg = ("PreLoadOne(axis, value, repetitions) is " + "deprecated since version Jan19. Use PreLoadOne(" + "axis, value, repetitions, latency_time) instead.") + self.warning(msg) + except TypeError: + res = ctrl.PreLoadOne(master_axis, value) + msg = ("PreLoadOne(axis, value) is deprecated since " + "version 2.3.0. Use PreLoadOne(axis, value, " + "repetitions, latency_time) instead.") + self.warning(msg) + if not res: + msg = ("%s.PreLoadOne(%d) returned False" % + (pool_ctrl.name, master_axis)) + raise Exception(msg) + try: + ctrl.LoadOne(master_axis, value, repetitions, latency) + except TypeError: + try: + ctrl.LoadOne(master_axis, value, repetitions) + msg = ("LoadOne(axis, value, repetitions) is deprecated " + "since version Jan18. Use LoadOne(axis, value, " + "repetitions, latency_time) instead.") + self.warning(msg) + except TypeError: + ctrl.LoadOne(master_axis, value) + msg = ("LoadOne(axis, value) is deprecated since " + "version 2.3.0. Use LoadOne(axis, value, " + "repetitions) instead.") + self.warning(msg) + ctrl.LoadAll() + with ActionContext(self): # PreLoadAll, PreLoadOne, LoadOne and LoadAll for pool_ctrl in pool_ctrls: try: ctrl = pool_ctrl.ctrl pool_ctrl_data = pool_ctrls_dict[pool_ctrl] - ctrl.PreLoadAll() master = pool_ctrl_data[master_key] - axis = master.axis - try: - res = ctrl.PreLoadOne(axis, master_value, repetitions) - except TypeError: - msg = ("PreLoadOne(axis, value) is deprecated since " - "version 2.3.0. Use PreLoadOne(axis, value, " - "repetitions) instead.") - self.warning(msg) - res = ctrl.PreLoadOne(axis, master_value) - if not res: - msg = ("%s.PreLoadOne(%d) returned False" % - (pool_ctrl.name, axis)) - raise Exception(msg) - try: - ctrl.LoadOne(axis, master_value, repetitions) - except TypeError: - msg = ("LoadOne(axis, value) is deprecated since " - "version 2.3.0. Use LoadOne(axis, value, " - "repetitions) instead.") - self.warning(msg) - ctrl.LoadOne(axis, master_value) - ctrl.LoadAll() + load(ctrl, master.axis, master_value, repetitions) except Exception, e: self.debug(e, exc_info=True) master.set_state(State.Fault, propagate=2) From 90e336a51f521641bf6cf5d150684289c434968c Mon Sep 17 00:00:00 2001 From: flyingbot91 Date: Mon, 8 Oct 2018 23:17:35 +0200 Subject: [PATCH 190/652] Centralized PyTango.DevState match --- .../taurus/core/tango/sardana/motion.py | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/motion.py b/src/sardana/taurus/core/tango/sardana/motion.py index 1d33b5512a..93618ad089 100644 --- a/src/sardana/taurus/core/tango/sardana/motion.py +++ b/src/sardana/taurus/core/tango/sardana/motion.py @@ -34,6 +34,26 @@ from taurus.core.util.containers import CaselessDict +def get_pytango_devstate_match(states): + """ + Retrieve PyTango.DevState match + :param states: + :return: + """ + + import PyTango + state = PyTango.DevState.ON + if PyTango.DevState.FAULT in states: + state = PyTango.DevState.FAULT + elif PyTango.DevState.ALARM in states: + state = PyTango.DevState.ALARM + elif PyTango.DevState.UNKNOWN in states: + state = PyTango.DevState.UNKNOWN + elif PyTango.DevState.MOVING in states: + state = PyTango.DevState.MOVING + return state + + class Moveable: """ An item that can 'move'. In order to move it you need to provide a list of values (normally interpreted as motor positions). @@ -181,16 +201,7 @@ def move(self, new_pos, timeout=None): res = moveable.move(pos, timeout=timeout) states.append(res[0]) positions.extend(res[1]) - import PyTango - state = PyTango.DevState.ON - if PyTango.DevState.FAULT in states: - state = PyTango.DevState.FAULT - elif PyTango.DevState.ALARM in states: - state = PyTango.DevState.ALARM - elif PyTango.DevState.UNKNOWN in states: - state = PyTango.DevState.UNKNOWN - elif PyTango.DevState.MOVING in states: - state = PyTango.DevState.MOVING + state = get_pytango_devstate_match(states) self.__total_motion_time = time.time() - start_time return state, positions @@ -388,16 +399,7 @@ def move(self, new_pos, timeout=None): for moveable, id in zip(self.moveable_list, ids): moveable.waitMove(id=id, timeout=timeout) states, positions = self.readState(), self.readPosition() - import PyTango - state = PyTango.DevState.ON - if PyTango.DevState.FAULT in states: - state = PyTango.DevState.FAULT - elif PyTango.DevState.ALARM in states: - state = PyTango.DevState.ALARM - elif PyTango.DevState.UNKNOWN in states: - state = PyTango.DevState.UNKNOWN - elif PyTango.DevState.MOVING in states: - state = PyTango.DevState.MOVING + state = get_pytango_devstate_match(states) ret = state, positions self.__total_motion_time = time.time() return ret From 7598291746d35099ed2335eb7c6e50c04d923828 Mon Sep 17 00:00:00 2001 From: flyingbot91 Date: Mon, 8 Oct 2018 23:17:59 +0200 Subject: [PATCH 191/652] Removed unused variable --- src/sardana/taurus/core/tango/sardana/motion.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sardana/taurus/core/tango/sardana/motion.py b/src/sardana/taurus/core/tango/sardana/motion.py index 93618ad089..fdf360963c 100644 --- a/src/sardana/taurus/core/tango/sardana/motion.py +++ b/src/sardana/taurus/core/tango/sardana/motion.py @@ -384,7 +384,6 @@ def waitMove(self, timeout=None, id=None): moveable.waitMove(timeout=timeout, id=id[i]) def move(self, new_pos, timeout=None): - start_time = time.time() if len(self.moveable_list) == 1: moveable = self.moveable_list[0] ret = moveable.move(new_pos, timeout=timeout) From c6220d5dd3238be8a2b251ffe4d378cfe3c3b4b4 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 9 Oct 2018 08:39:08 +0200 Subject: [PATCH 192/652] Fix flake8 errors --- src/sardana/pool/poolacquisition.py | 5 ++--- src/sardana/pool/test/test_synchronization.py | 13 +++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index ae819cac8c..a326d5125f 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -142,8 +142,8 @@ def event_received(self, *args, **kwargs): def prepare(self, config, repetitions): """Prepare measurement.""" timers = config.sw_sync_timers_enabled + \ - config.sw_start_timers_enabled + \ - config.hw_sync_timers_enabled + config.sw_start_timers_enabled + \ + config.hw_sync_timers_enabled for timer in timers: axis = timer.axis @@ -599,7 +599,6 @@ def _get_monitor(self): """ return self.main_element.configuration.hw_sync_monitor - @DebugIt() def action_loop(self): i = 0 diff --git a/src/sardana/pool/test/test_synchronization.py b/src/sardana/pool/test/test_synchronization.py index abe73a0f67..869a2f5c04 100644 --- a/src/sardana/pool/test/test_synchronization.py +++ b/src/sardana/pool/test/test_synchronization.py @@ -60,9 +60,8 @@ def createElements(self, ctrl_klass, ctrl_lib, ctrl_props): self.pool.add_element(self.tg_ctrl) self.pool.add_element(self.tg_elem) # create Synchronization action and its configuration - self.tg_cfg = createPoolSynchronizationConfiguration((self.tg_ctrl,), - ((self.tg_elem,),) - ,) + self.tg_cfg = createPoolSynchronizationConfiguration( + (self.tg_ctrl,), ((self.tg_elem,),),) # TODO: The TriggerGate should have a configuration self.tg_elem.configuration = self.tg_cfg self.tgaction = PoolSynchronization(self.tg_elem) @@ -86,7 +85,8 @@ def tggeneration(self, ctrl_lib, ctrl_klass, ctrl_props, :type offset: float :param active_interval: signal at which triggers will be generated :type active_interval: float - :param passive_interval: temporal passive period between two active periods + :param passive_interval: temporal passive period between two active + periods :type passive_interval: float :param repetitions: number of generated triggers :type repetitions: int @@ -131,11 +131,12 @@ def abort_tggeneration(self, ctrl_lib, ctrl_klass, ctrl_props, :type offset: float :param active_interval: signal at which triggers will be generated :type active_interval: float - :param passive_interval: temporal passive period between two active periods + :param passive_interval: temporal passive period between two active + periods :type passive_interval: float :param repetitions: number of generated triggers :type repetitions: int - :param abort_time: wait this time before stopping the trigger generation. + :param abort_time: wait this time before stopping the trigger generation :type abort_time: float """ From 89a76f80d789341a5bf21d1e000d26b081f5a55b Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 9 Oct 2018 08:53:38 +0200 Subject: [PATCH 193/652] Change message error --- src/sardana/pool/poolacquisition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index e1bf077253..f5428893b7 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -404,7 +404,7 @@ def start_action(self, *args, **kwargs): if integ_time is not None and mon_count is not None: raise RuntimeError('The acquisition must have only one role: ' - 'timer or count') + 'timer or monitor') if integ_time is not None: master_key = 'timer' master_value = integ_time From 28045a9fcb30836fdaab498776e2a5fd88426149 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 9 Oct 2018 08:56:57 +0200 Subject: [PATCH 194/652] Fix docstrings --- src/sardana/pool/poolacquisition.py | 35 ++--------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index f5428893b7..963a444fec 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -338,7 +338,7 @@ def _get_ctrls(self): def _get_timer(self): """ - Method to get the controller dict for the acquisition type + Method to get the master timer for the acquisition type :return: :rtype dict """ @@ -346,7 +346,7 @@ def _get_timer(self): def _get_monitor(self): """ - Method to get the controller dict for the acquisition type + Method to get the master monitor for the acquisition type :return: :rtype dict """ @@ -593,27 +593,12 @@ def __init__(self, main_element, name="AcquisitionHardware"): PoolAcquisitionBase.__init__(self, main_element, name) def _get_ctrls(self): - """ - Method to get the controller dict for the acquisition type - :return: - :rtype dict - """ return self.main_element.configuration.ctrl_hw_sync def _get_timer(self): - """ - Method to get the controller dict for the acquisition type - :return: - :rtype dict - """ return self.main_element.configuration.hw_sync_timer def _get_monitor(self): - """ - Method to get the controller dict for the acquisition type - :return: - :rtype dict - """ return self.main_element.configuration.hw_sync_monitor @DebugIt() @@ -687,28 +672,12 @@ def __init__(self, main_element, name="AcquisitionSoftware", slaves=None): self._slaves = slaves def _get_ctrls(self): - """ - Method to get the controller dict for the acquisition type - :return: - :rtype dict - """ return self.main_element.configuration.ctrl_sw_sync def _get_timer(self): - """ - Method to get the controller dict for the acquisition type - :return: - :rtype dict - """ - return self.main_element.configuration.sw_sync_timer def _get_monitor(self): - """ - Method to get the controller dict for the acquisition type - :return: - :rtype dict - """ return self.main_element.configuration.sw_sync_monitor @DebugIt() From 722cf7754e0ecfb0a19df1577b5f75cf182f8893 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 9 Oct 2018 09:04:11 +0200 Subject: [PATCH 195/652] Adapt Pool0DAquisition to use MeasurementConfiguration API --- src/sardana/pool/poolacquisition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 963a444fec..2d815ba1c1 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -868,9 +868,9 @@ def start_action(self, *args, **kwargs): items = kwargs.get("items") if items is None: items = self.get_elements() - cfg = kwargs['config'] + cfg = self.main_element.configuration - pool_ctrls_dict = dict(cfg.controllers) + pool_ctrls_dict = dict(cfg.ctrl_0d_sync) pool_ctrls_dict.pop('__tango__', None) pool_ctrls = [] for ctrl in pool_ctrls_dict: From e2dc6016db156d923b614d821a445210222fc136 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 9 Oct 2018 09:07:58 +0200 Subject: [PATCH 196/652] Remove TODO --- src/sardana/pool/poolacquisition.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 2d815ba1c1..26ff8292b6 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -193,7 +193,6 @@ def run(self, *args, **kwargs): self.set_sw_config(sw_acq_kwargs) if len(config.ctrl_0d_sync): zerod_acq_kwargs = dict(kwargs) - # TODO: Ask why self.set_0d_config(zerod_acq_kwargs) synch_kwargs = dict(kwargs) self._synch.run(*args, **synch_kwargs) From 4de2b6e8ee4a70a4320e65acc1393de1374662b9 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 9 Oct 2018 10:03:03 +0200 Subject: [PATCH 197/652] Use nr_of_starts instead of repetitions --- src/sardana/pool/poolacquisition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 26ff8292b6..bb4f284778 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -139,7 +139,7 @@ def event_received(self, *args, **kwargs): self.debug('Stopping ZeroD acquisition.') self._0d_acq.stop_action() - def prepare(self, config, repetitions): + def prepare(self, config, nr_of_starts): """Prepare measurement.""" timers = config.sw_sync_timers_enabled + \ config.sw_start_timers_enabled + \ @@ -149,7 +149,7 @@ def prepare(self, config, repetitions): axis = timer.axis timer_ctrl = timer.controller ctrl = timer_ctrl.ctrl - ctrl.PrepareOne(axis, repetitions) + ctrl.PrepareOne(axis, nr_of_starts) def is_running(self): return self._0d_acq.is_running() or\ From a7ff748f46c558bc93dedc894f928aa312b6512a Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 9 Oct 2018 10:06:07 +0200 Subject: [PATCH 198/652] Adapt test to use MeasurementConfiguration API --- .../poolcontrollers/test/test_DummyTriggerGateController.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sardana/pool/poolcontrollers/test/test_DummyTriggerGateController.py b/src/sardana/pool/poolcontrollers/test/test_DummyTriggerGateController.py index 9119a6377d..f44063b0c7 100644 --- a/src/sardana/pool/poolcontrollers/test/test_DummyTriggerGateController.py +++ b/src/sardana/pool/poolcontrollers/test/test_DummyTriggerGateController.py @@ -46,6 +46,9 @@ def setUp(self): self.cfg = createPoolSynchronizationConfiguration((dummy_tg_ctrl,), ((self.dummy_tg,),)) + # TODO: The TriggerGate should have a configuration + self.dummy_tg.configuration = self.cfg + # marrying the element with the action self.tg_action = PoolSynchronization(self.dummy_tg) self.tg_action.add_element(self.dummy_tg) From 39bff386ecbcd6fecac140d242f019c954728e62 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 9 Oct 2018 15:37:48 +0200 Subject: [PATCH 199/652] Implement "end" event --- src/sardana/util/funcgenerator.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sardana/util/funcgenerator.py b/src/sardana/util/funcgenerator.py index f30fddd237..dadd72c426 100644 --- a/src/sardana/util/funcgenerator.py +++ b/src/sardana/util/funcgenerator.py @@ -279,6 +279,11 @@ def wait_passive(self): def fire_passive(self): self.fire_event(EventType("passive"), self._id) self.set_passive_events(self.passive_events[1:]) + if len(self.passive_events) == 0: + self.fire_end() + + def fire_end(self): + self.fire_event("end", self._id) def set_configuration(self, configuration): # make a copy since we may inject the initial time From 0f97a83846b8fa987e599b7e39d8e81f6448b5b1 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 9 Oct 2018 15:43:30 +0200 Subject: [PATCH 200/652] SEP: better explain backwards comp. for direct start of MG --- doc/source/sep/SEP18.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 165debefd4..9899a7f37f 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -43,12 +43,15 @@ Design 1. Use of the measurement group will change: * From now on, in order to start the measurement group, it is mandatory to prepare it. - * The measurement group will be armed for as many starts as specified in - the preparation and the preparation will expire whenever all starts gets - called or in case of stop/abort. - * Setting the integration time via the attribute will be deprecated in - favor of using prepare command with the synchronization description, but - backwards compatibility will be maintained. + * The measurement group is prepared for a number of starts. The + preparation will expire whenever all starts gets called or in case of + stop/abort. Afterwards measurement group requires another preparation. + **IMPORTANT**: Whenever we drop backwards compatibility explained in the + following point starting of the measurement group without prior + preparation will be considered as wrong usage and will cause exception. + * Direct start of the measurement group (after prior configuration of + the integration time or synchronization) will be supported as backwards + compatibility and the corresponding warning will be logged. 2. Allow different types of preparation of channels - this still depends on the option selected in the implementation of controllers. The following assumes option 1. From c2e23309a0230e477e1370f6f7ca618d2d691ed7 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 10 Oct 2018 09:47:14 +0200 Subject: [PATCH 201/652] Rename funtion to _get_tango_devstate_match Better use *private* scope for this internal helper. --- src/sardana/taurus/core/tango/sardana/motion.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/motion.py b/src/sardana/taurus/core/tango/sardana/motion.py index fdf360963c..19e7973643 100644 --- a/src/sardana/taurus/core/tango/sardana/motion.py +++ b/src/sardana/taurus/core/tango/sardana/motion.py @@ -34,7 +34,7 @@ from taurus.core.util.containers import CaselessDict -def get_pytango_devstate_match(states): +def _get_tango_devstate_match(states): """ Retrieve PyTango.DevState match :param states: @@ -201,7 +201,7 @@ def move(self, new_pos, timeout=None): res = moveable.move(pos, timeout=timeout) states.append(res[0]) positions.extend(res[1]) - state = get_pytango_devstate_match(states) + state = _get_tango_devstate_match(states) self.__total_motion_time = time.time() - start_time return state, positions @@ -398,7 +398,7 @@ def move(self, new_pos, timeout=None): for moveable, id in zip(self.moveable_list, ids): moveable.waitMove(id=id, timeout=timeout) states, positions = self.readState(), self.readPosition() - state = get_pytango_devstate_match(states) + state = _get_tango_devstate_match(states) ret = state, positions self.__total_motion_time = time.time() return ret From f8d96f8a7f79184551786d45f23681ad168b4086 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 10 Oct 2018 10:01:58 +0200 Subject: [PATCH 202/652] Fix calculation of total motion time in Motion.move --- src/sardana/taurus/core/tango/sardana/motion.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/core/tango/sardana/motion.py b/src/sardana/taurus/core/tango/sardana/motion.py index 19e7973643..099c83fcdb 100644 --- a/src/sardana/taurus/core/tango/sardana/motion.py +++ b/src/sardana/taurus/core/tango/sardana/motion.py @@ -384,6 +384,7 @@ def waitMove(self, timeout=None, id=None): moveable.waitMove(timeout=timeout, id=id[i]) def move(self, new_pos, timeout=None): + start_time = time.time() if len(self.moveable_list) == 1: moveable = self.moveable_list[0] ret = moveable.move(new_pos, timeout=timeout) @@ -400,7 +401,7 @@ def move(self, new_pos, timeout=None): states, positions = self.readState(), self.readPosition() state = _get_tango_devstate_match(states) ret = state, positions - self.__total_motion_time = time.time() + self.__total_motion_time = time.time() - start_time return ret def iterMove(self, new_pos, timeout=None): From 9a396fb468508a2c706c0050ff8cba6de71ededb Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 10 Oct 2018 11:04:58 +0200 Subject: [PATCH 203/652] Remove unused property --- src/sardana/pool/poolmeasurementgroup.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 71c49e7174..389c6c0fa9 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -176,11 +176,6 @@ def wrapper(self, *args, **kwargs): def __getitem__(self, item): return self._config.__getitem__(item) - @property - @__check_config - def controllers(self): - return self._config['controllers'] - @property @__check_config def configuration(self): From 23d7c70d6bb7258b7e798fdca15f5475ba50f6d2 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 10 Oct 2018 11:28:21 +0200 Subject: [PATCH 204/652] Fix fire end event --- src/sardana/util/funcgenerator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/util/funcgenerator.py b/src/sardana/util/funcgenerator.py index dadd72c426..f72bac46a7 100644 --- a/src/sardana/util/funcgenerator.py +++ b/src/sardana/util/funcgenerator.py @@ -283,7 +283,7 @@ def fire_passive(self): self.fire_end() def fire_end(self): - self.fire_event("end", self._id) + self.fire_event(EventType("end"), self._id) def set_configuration(self, configuration): # make a copy since we may inject the initial time From 8c41da7de846187c80b5be37956bfee8d8aab713 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 10 Oct 2018 11:30:19 +0200 Subject: [PATCH 205/652] funcgenerator tests: add asserts for start and end events --- src/sardana/util/test/test_funcgenerator.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sardana/util/test/test_funcgenerator.py b/src/sardana/util/test/test_funcgenerator.py index 3feb15dca2..b117fec21d 100644 --- a/src/sardana/util/test/test_funcgenerator.py +++ b/src/sardana/util/test/test_funcgenerator.py @@ -73,8 +73,10 @@ def __init__(self): self.init() def init(self): + self.start = False self.active_event_ids = list() self.passive_event_ids = list() + self.end = False def event_received(self, *args, **kwargs): _, type_, value = args @@ -83,6 +85,10 @@ def event_received(self, *args, **kwargs): self.active_event_ids.append(value) elif name == "passive": self.passive_event_ids.append(value) + elif name == "start": + self.start = True + elif name == "end": + self.end = True else: ValueError("wrong event type") @@ -122,9 +128,11 @@ def test_run_time(self): self.event.wait(100) active_event_ids = self.listener.active_event_ids active_event_ids_ok = range(0, 10) - msg = "Received active event ids: %s, expected: %s" % (active_event_ids, - active_event_ids_ok) + msg = "Received active event ids: %s, expected: %s" % ( + active_event_ids, active_event_ids_ok) self.assertListEqual(active_event_ids, active_event_ids_ok, msg) + self.assertTrue(self.listener.start, "Start event is missing") + self.assertTrue(self.listener.end, "End event is missing") def test_stop_time(self): self.func_generator.initial_domain = SynchDomain.Time From d56d514901222de240d04fb295c9020c9be6b06a Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 10 Oct 2018 11:37:22 +0200 Subject: [PATCH 206/652] Adapt load_configuration method --- src/sardana/pool/poolmeasurementgroup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 389c6c0fa9..e2486052dd 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -739,13 +739,11 @@ def load_configuration(self, force=False): """Loads the current configuration to all involved controllers""" # g_timer, g_monitor = cfg['timer'], cfg['monitor'] - for ctrl, ctrl_data in self._config.controllers.items(): + for ctrl in self._config.enabled_ctrls: if isinstance(ctrl, str): # skip external channels continue if not ctrl.is_online(): continue - if ctrl not in self._config.enabled_ctrls: - continue ctrl.set_ctrl_par('acquisition_mode', self.acquisition_mode) # @TODO: fix optimization and enable it again @@ -753,6 +751,8 @@ def load_configuration(self, force=False): continue ctrl.operator = self if ctrl.is_timerable(): + # TODO: Implement API to extract controller data + ctrl_data = self._config.configuration['controllers'][ctrl] # if ctrl == g_timer.controller: # ctrl.set_ctrl_par('timer', g_timer.axis) # if ctrl == g_monitor.controller: From 1ef22b0f77bc0a21def5e8e9b2cedd80156ebb4e Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 10 Oct 2018 12:07:12 +0200 Subject: [PATCH 207/652] Fix bug on get_timer method --- src/sardana/pool/poolmeasurementgroup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index e2486052dd..49f764605c 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -767,7 +767,8 @@ def load_configuration(self, force=False): self._config_dirty = False def get_timer(self): - return self._config.timer + # TODO: Adapt to the new future MeasurementConfiguration API + return self._config.configuration['timer'] timer = property(get_timer) From 68d0c1413d504dac4ad27ff4bbb8cad7cab37965 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 10 Oct 2018 12:50:08 +0200 Subject: [PATCH 208/652] SEP: warn about problems with step scan and hooks --- doc/source/sep/SEP18.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 9899a7f37f..bc36582711 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -48,9 +48,11 @@ Design stop/abort. Afterwards measurement group requires another preparation. **IMPORTANT**: Whenever we drop backwards compatibility explained in the following point starting of the measurement group without prior - preparation will be considered as wrong usage and will cause exception. - * Direct start of the measurement group (after prior configuration of - the integration time or synchronization) will be supported as backwards + preparation will be considered as wrong usage and will cause exception. + This will break step scans with attached hooks which measure with the + same measurement group as used by the scan. + * Direct start of the measurement group (after prior configuration of + the integration time or synchronization) will be supported as backwards compatibility and the corresponding warning will be logged. 2. Allow different types of preparation of channels - this still depends on the option selected in the implementation of controllers. The following From c3bdc5530c55a7cbe5eb5d9d20d8803926095d4e Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 10 Oct 2018 13:23:22 +0200 Subject: [PATCH 209/652] SEP: small corrections --- doc/source/sep/SEP18.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index bc36582711..47e4e5bf08 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -57,9 +57,8 @@ Design 2. Allow different types of preparation of channels - this still depends on the option selected in the implementation of controllers. The following assumes option 1. - * Per measurement preparation with number of starts = n e.g. - Prepare(One|All) or a controller parameter - * Per acquisition preparation with repetitions = n e.g. Load(One|All) + * Per measurement preparation with number of starts = n - `PrepareOne` + * Per acquisition preparation with repetitions = n - `Load(One|All)` 3. Extend AcqSynch with two new options: * SoftwareStart (which means internal start) * HardwareStart (which means external start) @@ -95,9 +94,9 @@ Implementation ### Measurement Group Measurement group is extended by the *prepare* command (with no arguments) -*number of starts* attribute. The use of the attribute is optional and -it indicates how many times measurement group will be started, with the -*start* command, to measure according to the synchronization description or +and *number of starts* attribute. The use of the attribute is optional and +it indicates how many times measurement group will be started (with the +*start* command) to measure according to the synchronization description or integration time. When it is not used number of starts of 1 will be assumed. 1. Measurement group - Tango device class @@ -111,7 +110,7 @@ the start command (without calling prepare command in-between) will be solved in the following way: start command will internally call the prepare. 4. Measurement group - Taurus extension * Add `prepare()` method which simply maps to `Prepare` Tango command - * Add `count_raw` method according to the following pseudo code: + * Add `count_raw()` method according to the following pseudo code: * `start()` * `waitFinish()` * Implement `count(integration_time)` method according to the following @@ -140,7 +139,7 @@ event and end is emitted after the last `passive` event. software synchronizer `start` event. * `PoolAcquisitionSoftware` will stop channels on software synchronizer `end` event. TODO: decide if we wait for the acquisition in progress -until it finises or we stop immediatelly (finish hook could be used if +until it finishes or we stop immediately (finish hook could be used if we choose to wait). ### Controllers From 96c365a6b51d1184865a04d84fbdf11266073fac Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 11 Oct 2018 16:46:30 +0200 Subject: [PATCH 210/652] SEP: DRAFT -> CANDIDATE --- doc/source/sep/SEP18.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 47e4e5bf08..cb9f79a4d2 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -1,6 +1,6 @@ Title: Extend acquisition and synchronization concepts for SEP2 needs. SEP: 18 - State: DRAFT + State: CANDIDATE Reason: New acquisition and synchronization concepts are necessary in order to properly integrate 1D and 2D experimental channels in Sardana (SEP2). From 4e24e6081e730c44446a0979292b0ddd6eb69d2e Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 11 Oct 2018 16:58:57 +0200 Subject: [PATCH 211/652] Refactors acqusition base action --- src/sardana/pool/poolacquisition.py | 248 +++++++++++++++------------- 1 file changed, 132 insertions(+), 116 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index bb4f284778..431f9c8e92 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -61,6 +61,14 @@ AS.Invalid: State.Invalid, } +MeasurementActions = Enumeration("MeasurementActions", ( + "AcquisitionHardware", + "AcquisitionSoftware", + "AcquisitionSoftwareStart", + "Acquisition0D", + "Synchronization") +) + def is_value_error(value): if isinstance(value, SardanaValue) and value.error: @@ -177,7 +185,8 @@ def run(self, *args, **kwargs): synchronization = kwargs["synchronization"] integ_time = synchronization.integration_time repetitions = synchronization.repetitions - + latency_time = 0 + ctrls_channels_acq_hw = config.get_ctrls_channels() # starting continuous acquisition only if there are any controllers if len(config.ctrl_hw_sync): cont_acq_kwargs = dict(kwargs) @@ -316,7 +325,7 @@ class PoolAcquisitionBase(PoolAction): def __init__(self, main_element, name): PoolAction.__init__(self, main_element, name) - self._channels = None + self._channels = [] # TODO: for the moment we can not clear value buffers at the end of # the acquisition. This is because of the pseudo counters that are # based on channels synchronized by hardware and software. @@ -367,7 +376,9 @@ def in_acquisition(self, states): return True @DebugIt() - def start_action(self, *args, **kwargs): + def start_action(self, ctrls_channels, ctrls_loadables, value, + repetitions=1, latency=0, master=None, *args, + **kwargs): """Prepares everything for acquisition and starts it. :param acq_sleep_time: sleep time between state queries :param nb_states_per_value: how many state queries between readouts @@ -387,123 +398,131 @@ def start_action(self, *args, **kwargs): self._nb_states_per_value = kwargs.pop("nb_states_per_value", pool.acq_loop_states_per_value) - self._integ_time = integ_time = kwargs.get("integ_time") - self._mon_count = mon_count = kwargs.get("monitor_count") - self._repetitions = repetitions = kwargs.get("repetitions") - if integ_time is None and mon_count is None: - raise Exception("must give integration time or monitor counts") - if integ_time is not None and mon_count is not None: - msg = ("must give either integration time or monitor counts " - "(not both)") - raise Exception(msg) - - _ = kwargs.get("items", self.get_elements()) - # determine which is the controller which holds the master channel - master = None - - if integ_time is not None and mon_count is not None: - raise RuntimeError('The acquisition must have only one role: ' - 'timer or monitor') - if integ_time is not None: - master_key = 'timer' - master_value = integ_time - master = self._get_timer() - if mon_count is not None: - master_key = 'monitor' - master_value = -mon_count - master = self._get_monitor() - if master is None: - self.main_element.set_state(State.Fault, propagate=2) - msg = "master {0} ({1})is unknown (probably disabled)".format( - master_key, master) - raise RuntimeError(msg) - master_ctrl = master.controller - pool_ctrls_dict = dict(self._get_ctrls()) - pool_ctrls_dict.pop('__tango__', None) + # self._integ_time = integ_time = kwargs.get("integ_time") + # self._mon_count = mon_count = kwargs.get("monitor_count") + # self._repetitions = repetitions = kwargs.get("repetitions") + # # if integ_time is None and mon_count is None: + # raise Exception("must give integration time or monitor counts") + # if integ_time is not None and mon_count is not None: + # msg = ("must give either integration time or monitor counts " + # "(not both)") + # raise Exception(msg) + # + # _ = kwargs.get("items", self.get_elements()) + # # determine which is the controller which holds the master channel + # master = None + # + # if integ_time is not None and mon_count is not None: + # raise RuntimeError('The acquisition must have only one role: ' + # 'timer or monitor') + # if integ_time is not None: + # master_key = 'timer' + # master_value = integ_time + # master = self._get_timer() + # if mon_count is not None: + # master_key = 'monitor' + # master_value = -mon_count + # master = self._get_monitor() + # if master is None: + # self.main_element.set_state(State.Fault, propagate=2) + # msg = "master {0} ({1})is unknown (probably disabled)".format( + # master_key, master) + # raise RuntimeError(msg) # controllers to be started (only enabled) in the right order - pool_ctrls = [] + pool_ctrls = ctrls_channels.keys() + + # make sure the controller which has the master channel is the last to + # be called + if master is not None: + master_ctrl = master.controller + pool_ctrls.remove(master_ctrl) + pool_ctrls.append(master_ctrl) + + # pool_ctrls_dict = dict(self._get_ctrls()) + # pool_ctrls_dict.pop('__tango__', None) + # controllers that will be read at the end of the action - self._pool_ctrl_dict_loop = _pool_ctrl_dict_loop = {} + self._pool_ctrl_dict_loop = ctrls_channels # channels that are acquired (only enabled) - self._channels = channels = {} - - # select only suitable e.g. enabled, timerable controllers & channels - for ctrl, pool_ctrl_data in pool_ctrls_dict.items(): - # skip not timerable controllers e.g. 0D - if not ctrl.is_timerable(): - continue - ctrl_enabled = False - elements = pool_ctrl_data['channels'] - for element, element_info in elements.items(): - # skip disabled elements - if not element_info['enabled']: - continue - # Add only the enabled channels - channel = Channel(element, info=element_info) - channels[element] = channel - ctrl_enabled = True - # check if the ctrl has enabled channels - if ctrl_enabled: - # enabled controller can no be offline - if not ctrl.is_online(): - self.main_element.set_state(State.Fault, propagate=2) - msg = "controller {0} is offline".format(ctrl.name) - raise RuntimeError(msg) - pool_ctrls.append(ctrl) - # only CT will be read in the loop, 1D and 2D not - if ElementType.CTExpChannel in ctrl.get_ctrl_types(): - _pool_ctrl_dict_loop[ctrl] = pool_ctrl_data + self._channels = [] + + # # select only suitable e.g. enabled, timerable controllers & channels + # for ctrl, pool_ctrl_data in pool_ctrls_dict.items(): + # # skip not timerable controllers e.g. 0D + # if not ctrl.is_timerable(): + # continue + # ctrl_enabled = False + # elements = pool_ctrl_data['channels'] + # for element, element_info in elements.items(): + # # skip disabled elements + # if not element_info['enabled']: + # continue + # # Add only the enabled channels + # channel = Channel(element, info=element_info) + # channels[element] = channel + # ctrl_enabled = True + # # check if the ctrl has enabled channels + # if ctrl_enabled: + # # enabled controller can no be offline + # if not ctrl.is_online(): + # self.main_element.set_state(State.Fault, propagate=2) + # msg = "controller {0} is offline".format(ctrl.name) + # raise RuntimeError(msg) + # pool_ctrls.append(ctrl) + # # only CT will be read in the loop, 1D and 2D not + # if ElementType.CTExpChannel in ctrl.get_ctrl_types(): + # _pool_ctrl_dict_loop[ctrl] = pool_ctrl_data # timer/monitor channels can not be disabled - for pool_ctrl in pool_ctrls: - ctrl = pool_ctrl.ctrl - pool_ctrl_data = pool_ctrls_dict[pool_ctrl] - timer_monitor = pool_ctrl_data[master_key] - if timer_monitor not in channels: - self.main_element.set_state(State.Fault, propagate=2) - msg = "timer/monitor ({0}) of {1} controller is "\ - "disabled)".format(timer_monitor.name, pool_ctrl.name) - raise RuntimeError(msg) + # for pool_ctrl in pool_ctrls: + # ctrl = pool_ctrl.ctrl + # pool_ctrl_data = pool_ctrls_dict[pool_ctrl] + # timer_monitor = pool_ctrl_data[master_key] + # if timer_monitor not in channels: + # self.main_element.set_state(State.Fault, propagate=2) + # msg = "timer/monitor ({0}) of {1} controller is "\ + # "disabled)".format(timer_monitor.name, pool_ctrl.name) + # raise RuntimeError(msg) - # make sure the controller which has the master channel is the last to - # be called - pool_ctrls.remove(master_ctrl) - pool_ctrls.append(master_ctrl) - def load(ctrl, master_axis, value, repetitions, latency=0): + + def load(channel, value, repetitions, latency=0): + axis = channel.axis + pool_ctrl = channel.controller + ctrl = pool_ctrl.ctrl ctrl.PreLoadAll() try: - res = ctrl.PreLoadOne(master_axis, value, repetitions, + res = ctrl.PreLoadOne(axis, value, repetitions, latency) except TypeError: try: - res = ctrl.PreLoadOne(master_axis, value, repetitions) + res = ctrl.PreLoadOne(axis, value, repetitions) msg = ("PreLoadOne(axis, value, repetitions) is " "deprecated since version Jan19. Use PreLoadOne(" "axis, value, repetitions, latency_time) instead.") self.warning(msg) except TypeError: - res = ctrl.PreLoadOne(master_axis, value) + res = ctrl.PreLoadOne(axis, value) msg = ("PreLoadOne(axis, value) is deprecated since " "version 2.3.0. Use PreLoadOne(axis, value, " "repetitions, latency_time) instead.") self.warning(msg) if not res: msg = ("%s.PreLoadOne(%d) returned False" % - (pool_ctrl.name, master_axis)) + (pool_ctrl.name, axis)) raise Exception(msg) try: - ctrl.LoadOne(master_axis, value, repetitions, latency) + ctrl.LoadOne(axis, value, repetitions, latency) except TypeError: try: - ctrl.LoadOne(master_axis, value, repetitions) + ctrl.LoadOne(axis, value, repetitions) msg = ("LoadOne(axis, value, repetitions) is deprecated " "since version Jan18. Use LoadOne(axis, value, " "repetitions, latency_time) instead.") self.warning(msg) except TypeError: - ctrl.LoadOne(master_axis, value) + ctrl.LoadOne(axis, value) msg = ("LoadOne(axis, value) is deprecated since " "version 2.3.0. Use LoadOne(axis, value, " "repetitions) instead.") @@ -512,64 +531,61 @@ def load(ctrl, master_axis, value, repetitions, latency=0): with ActionContext(self): # PreLoadAll, PreLoadOne, LoadOne and LoadAll - for pool_ctrl in pool_ctrls: - try: - ctrl = pool_ctrl.ctrl - pool_ctrl_data = pool_ctrls_dict[pool_ctrl] - master = pool_ctrl_data[master_key] - load(ctrl, master.axis, master_value, repetitions) - except Exception, e: - self.debug(e, exc_info=True) - master.set_state(State.Fault, propagate=2) - msg = ("Load sequence of %s failed" % pool_ctrl.name) - raise Exception(msg) + loadables = ctrls_loadables.values() + for channel in loadables: + load(channel, value, repetitions, latency) + + # TODO: remove when the action allows to use tango attributes + try: + pool_ctrls.pop('__tango__') + except Exception: + pass # PreStartAll on all enabled controllers for pool_ctrl in pool_ctrls: pool_ctrl.ctrl.PreStartAll() + channels_started = [] # PreStartOne & StartOne on all enabled elements for pool_ctrl in pool_ctrls: + channels = ctrls_channels[pool_ctrl] ctrl = pool_ctrl.ctrl - pool_ctrl_data = pool_ctrls_dict[pool_ctrl] - elements = pool_ctrl_data['channels'].keys() - timer_monitor = pool_ctrl_data[master_key] + # make sure that the timer/monitor is started as the last one - elements.remove(timer_monitor) - elements.append(timer_monitor) - for element in elements: - try: - channel = channels[element] - except KeyError: - continue - axis = element.axis - ret = ctrl.PreStartOne(axis, master_value) + loadable = ctrls_loadables[pool_ctrl] + channels.remove(loadable) + channels.append(loadable) + for channel in channels: + axis = channel.axis + ret = ctrl.PreStartOne(axis, value) if not ret: msg = ("%s.PreStartOne(%d) returns False" % (pool_ctrl.name, axis)) raise Exception(msg) try: - ctrl.StartOne(axis, master_value) + ctrl.StartOne(axis, value) except Exception, e: self.debug(e, exc_info=True) - element.set_state(State.Fault, propagate=2) + channel.set_state(State.Fault, propagate=2) msg = ("%s.StartOne(%d) failed" % (pool_ctrl.name, axis)) raise Exception(msg) + self._channels.append(channel) + # set the state of all elements to and inform their listeners - for channel in channels: + for channel in self._channels: channel.set_state(State.Moving, propagate=2) # StartAll on all enabled controllers for pool_ctrl in pool_ctrls: + channels = ctrls_channels[pool_ctrl] try: pool_ctrl.ctrl.StartAll() except Exception, e: self.debug(e, exc_info=True) - elements = pool_ctrl_data['channels'].keys() - for element in elements: - element.set_state(State.Fault, propagate=2) + for channel in channels: + channel.set_state(State.Fault, propagate=2) msg = ("%s.StartAll() failed" % pool_ctrl.name) raise Exception(msg) From 7b093274e14ce02694379289b55499630627de60 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 11 Oct 2018 16:59:29 +0200 Subject: [PATCH 212/652] Adapt acquisition test case to new API --- src/sardana/pool/test/test_acquisition.py | 37 ++++++++--------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index dd18c2c51e..eab0329cba 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -281,8 +281,8 @@ def event_received(self, *args, **kwargs): return else: self.sw_acq_busy.set() - args = dict(self.sw_acq_args) - kwargs = dict(self.sw_acq_kwargs) + args = self.sw_acq_args + kwargs = self.sw_acq_kwargs kwargs['idx'] = value get_thread_pool().add(self.sw_acq.run, None, @@ -303,6 +303,11 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, ct_ctrl_2 = ct_2_1.get_controller() self.channel_names.append('_test_ct_1_1') self.channel_names.append('_test_ct_2_1') + + acq_hw_ctrl_channels = {ct_ctrl_1: [ct_1_1]} + acq_hw_ctrl_loadable = {ct_ctrl_1: ct_1_1} + acq_sw_ctrl_channels = {ct_ctrl_2: [ct_2_1]} + acq_sw_ctrl_loadable = {ct_ctrl_2: ct_2_1} # crating configuration for TGGeneration tg_cfg = createPoolSynchronizationConfiguration((tg_ctrl_2,), ((tg_2_1,),)) @@ -310,15 +315,7 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, self.createPoolSynchronization([tg_2_1], tg_config=tg_cfg) # add_listeners self.addListeners([ct_1_1, ct_2_1]) - # creating acquisition configurations - self.hw_acq_cfg = createCTAcquisitionConfiguration((ct_ctrl_1,), - ((ct_1_1,),)) - self.sw_acq_cfg = createCTAcquisitionConfiguration((ct_ctrl_2,), - ((ct_2_1,),)) # creating acquisition actions - # TODO: The CTExpChannel should have a configuration - ct_1_1.configuration = self.hw_acq_cfg - ct_2_1.configuration = self.sw_acq_cfg self.hw_acq = PoolAcquisitionHardware(ct_1_1) self.sw_acq = PoolAcquisitionSoftware(ct_2_1) # Since we deposit the software acquisition action on the PoolThread's @@ -338,21 +335,13 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, # get the current number of jobs jobs_before = get_thread_pool().qsize - self.sw_acq_args = () - self.sw_acq_kwargs = { - 'synch': True, - 'integ_time': integ_time, - 'repetitions': 1, - 'config': self.sw_acq_cfg - } + self.sw_acq_args = (acq_sw_ctrl_channels, acq_sw_ctrl_loadable, + integ_time) + self.sw_acq_kwargs = {"master": ct_2_1} ct_ctrl_1.set_ctrl_par('synchronization', AcqSynch.HardwareTrigger) - hw_acq_args = () - hw_acq_kwargs = { - 'integ_time': integ_time, - 'repetitions': repetitions, - 'config': self.hw_acq_cfg, - } - self.hw_acq.run(*hw_acq_args, **hw_acq_kwargs) + hw_acq_args = (acq_hw_ctrl_channels, acq_hw_ctrl_loadable, + integ_time, repetitions) + self.hw_acq.run(*hw_acq_args) tg_args = () total_interval = active_interval + passive_interval synchronization = [{SynchParam.Delay: {SynchDomain.Time: offset}, From 00cdf04b1b2adec1211759ee1724c7b57a3d0108 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 11 Oct 2018 17:00:08 +0200 Subject: [PATCH 213/652] Add TODO for measurement configuration --- src/sardana/pool/poolmeasurementgroup.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 49f764605c..176fb02047 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -125,6 +125,10 @@ def _to_fqdn(name, logger=None): class MeasurementConfiguration(object): + """ + .. todo: Reject configuration with errors: + * Controllers with timer and monitor disable + """ DFT_DESC = 'General purpose measurement group' From e1484daaf9b40b77e1c146f98c4b9685e8b00460 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 15 Oct 2018 10:10:52 +0200 Subject: [PATCH 214/652] Remove unused code --- src/sardana/pool/poolacquisition.py | 74 ----------------------------- 1 file changed, 74 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 431f9c8e92..844eaa47a2 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -398,37 +398,6 @@ def start_action(self, ctrls_channels, ctrls_loadables, value, self._nb_states_per_value = kwargs.pop("nb_states_per_value", pool.acq_loop_states_per_value) - # self._integ_time = integ_time = kwargs.get("integ_time") - # self._mon_count = mon_count = kwargs.get("monitor_count") - # self._repetitions = repetitions = kwargs.get("repetitions") - # # if integ_time is None and mon_count is None: - # raise Exception("must give integration time or monitor counts") - # if integ_time is not None and mon_count is not None: - # msg = ("must give either integration time or monitor counts " - # "(not both)") - # raise Exception(msg) - # - # _ = kwargs.get("items", self.get_elements()) - # # determine which is the controller which holds the master channel - # master = None - # - # if integ_time is not None and mon_count is not None: - # raise RuntimeError('The acquisition must have only one role: ' - # 'timer or monitor') - # if integ_time is not None: - # master_key = 'timer' - # master_value = integ_time - # master = self._get_timer() - # if mon_count is not None: - # master_key = 'monitor' - # master_value = -mon_count - # master = self._get_monitor() - # if master is None: - # self.main_element.set_state(State.Fault, propagate=2) - # msg = "master {0} ({1})is unknown (probably disabled)".format( - # master_key, master) - # raise RuntimeError(msg) - # controllers to be started (only enabled) in the right order pool_ctrls = ctrls_channels.keys() @@ -439,54 +408,11 @@ def start_action(self, ctrls_channels, ctrls_loadables, value, pool_ctrls.remove(master_ctrl) pool_ctrls.append(master_ctrl) - # pool_ctrls_dict = dict(self._get_ctrls()) - # pool_ctrls_dict.pop('__tango__', None) - # controllers that will be read at the end of the action self._pool_ctrl_dict_loop = ctrls_channels # channels that are acquired (only enabled) self._channels = [] - # # select only suitable e.g. enabled, timerable controllers & channels - # for ctrl, pool_ctrl_data in pool_ctrls_dict.items(): - # # skip not timerable controllers e.g. 0D - # if not ctrl.is_timerable(): - # continue - # ctrl_enabled = False - # elements = pool_ctrl_data['channels'] - # for element, element_info in elements.items(): - # # skip disabled elements - # if not element_info['enabled']: - # continue - # # Add only the enabled channels - # channel = Channel(element, info=element_info) - # channels[element] = channel - # ctrl_enabled = True - # # check if the ctrl has enabled channels - # if ctrl_enabled: - # # enabled controller can no be offline - # if not ctrl.is_online(): - # self.main_element.set_state(State.Fault, propagate=2) - # msg = "controller {0} is offline".format(ctrl.name) - # raise RuntimeError(msg) - # pool_ctrls.append(ctrl) - # # only CT will be read in the loop, 1D and 2D not - # if ElementType.CTExpChannel in ctrl.get_ctrl_types(): - # _pool_ctrl_dict_loop[ctrl] = pool_ctrl_data - - # timer/monitor channels can not be disabled - # for pool_ctrl in pool_ctrls: - # ctrl = pool_ctrl.ctrl - # pool_ctrl_data = pool_ctrls_dict[pool_ctrl] - # timer_monitor = pool_ctrl_data[master_key] - # if timer_monitor not in channels: - # self.main_element.set_state(State.Fault, propagate=2) - # msg = "timer/monitor ({0}) of {1} controller is "\ - # "disabled)".format(timer_monitor.name, pool_ctrl.name) - # raise RuntimeError(msg) - - - def load(channel, value, repetitions, latency=0): axis = channel.axis pool_ctrl = channel.controller From 4f4f639e57f2952943bd0eed552eb759be8970b4 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 15 Oct 2018 15:55:23 +0200 Subject: [PATCH 215/652] Remove get configuration method Remove internal method to get the configuration for each action type. --- src/sardana/pool/poolacquisition.py | 42 ----------------------------- 1 file changed, 42 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 844eaa47a2..66839a925b 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -336,30 +336,6 @@ def __init__(self, main_element, name): # acquisition actions, uncomment this line # self.add_finish_hook(self.clear_value_buffers, True) - def _get_ctrls(self): - """ - Method to get the controller dict for the acquisition type - :return: - :rtype dict - """ - raise NotImplementedError() - - def _get_timer(self): - """ - Method to get the master timer for the acquisition type - :return: - :rtype dict - """ - raise NotImplementedError() - - def _get_monitor(self): - """ - Method to get the master monitor for the acquisition type - :return: - :rtype dict - """ - raise NotImplementedError() - def in_acquisition(self, states): """Determines if we are in acquisition or if the acquisition has ended based on the current unit trigger modes and states returned by the @@ -533,15 +509,6 @@ class PoolAcquisitionHardware(PoolAcquisitionBase): def __init__(self, main_element, name="AcquisitionHardware"): PoolAcquisitionBase.__init__(self, main_element, name) - def _get_ctrls(self): - return self.main_element.configuration.ctrl_hw_sync - - def _get_timer(self): - return self.main_element.configuration.hw_sync_timer - - def _get_monitor(self): - return self.main_element.configuration.hw_sync_monitor - @DebugIt() def action_loop(self): i = 0 @@ -612,15 +579,6 @@ def __init__(self, main_element, name="AcquisitionSoftware", slaves=None): slaves = () self._slaves = slaves - def _get_ctrls(self): - return self.main_element.configuration.ctrl_sw_sync - - def _get_timer(self): - return self.main_element.configuration.sw_sync_timer - - def _get_monitor(self): - return self.main_element.configuration.sw_sync_monitor - @DebugIt() def start_action(self, *args, **kwargs): """Prepares everything for acquisition and starts it. From d415179fe46e3599807b6cf2eb9ff470cb3ecbcf Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Mon, 15 Oct 2018 16:20:20 +0200 Subject: [PATCH 216/652] add limits checking before scan --- src/sardana/macroserver/scan/gscan.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index 83862aea0a..06087d68a2 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -271,6 +271,8 @@ def __init__(self, macro, generator=None, moveables=[], env={}, moveable_names.append(moveable.moveable.getName()) self._moveables.append(moveable) + self._check_moveables_limits() + name = self.__class__.__name__ self.call__init__(Logger, name) @@ -369,6 +371,30 @@ def __init__(self, macro, generator=None, moveables=[], env={}, # --------------------------------------------------------------------- self._setupEnvironment(env) + def _check_moveables_limits(self): + for m in self._moveables: + config = PyTango.AttributeProxy( + m.moveable.getName() + '/position').get_config() + try: + high = float(config.max_value) + except ValueError: + high = None + try: + low = float(config.min_value) + except ValueError: + low = None + for pos in (m.min_value, m.max_value): + if high is not None: + if float(pos) > high: + raise RuntimeError( + "requested movement of %s is above its upper limit" + % m.moveable.getName()) + if low is not None: + if float(pos) < low: + raise RuntimeError( + "requested movement of %s is below its lower limit" + % m.moveable.getName()) + def _getExtraColumns(self): ret = [] try: From 71bcea73076cb8b8540a91e3b847d40da0ce0f99 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 15 Oct 2018 16:27:34 +0200 Subject: [PATCH 217/652] Add explicit parameters on start_action method --- src/sardana/pool/poolacquisition.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 66839a925b..82055e1c16 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -326,6 +326,11 @@ class PoolAcquisitionBase(PoolAction): def __init__(self, main_element, name): PoolAction.__init__(self, main_element, name) self._channels = [] + self._index = None + self._nb_states_per_value = None + self._acq_sleep_time = None + self._pool_ctrl_dict_loop = None + # TODO: for the moment we can not clear value buffers at the end of # the acquisition. This is because of the pseudo counters that are # based on channels synchronized by hardware and software. @@ -353,7 +358,9 @@ def in_acquisition(self, states): @DebugIt() def start_action(self, ctrls_channels, ctrls_loadables, value, - repetitions=1, latency=0, master=None, *args, + repetitions=1, latency=0, master=None, + index=None, acq_sleep_time=None, + nb_states_per_value=None, *args, **kwargs): """Prepares everything for acquisition and starts it. :param acq_sleep_time: sleep time between state queries @@ -369,10 +376,16 @@ def start_action(self, ctrls_channels, ctrls_loadables, value, self._aborted = False self._stopped = False - self._acq_sleep_time = kwargs.pop("acq_sleep_time", - pool.acq_loop_sleep_time) - self._nb_states_per_value = kwargs.pop("nb_states_per_value", - pool.acq_loop_states_per_value) + self._index = index + + self._acq_sleep_time = acq_sleep_time + if self._acq_sleep_time is None: + self._acq_sleep_time = pool.acq_loop_sleep_time + + self._nb_states_per_value = nb_states_per_value + if self._nb_states_per_value is None: + self._nb_states_per_value = pool.acq_loop_states_per_value + # controllers to be started (only enabled) in the right order pool_ctrls = ctrls_channels.keys() From 25ddec1bb1da26a04b81ab7b0497c89a4954cb0d Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 15 Oct 2018 16:32:42 +0200 Subject: [PATCH 218/652] Add python 3 compatibility --- src/sardana/pool/poolacquisition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 82055e1c16..71b6e96332 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -479,7 +479,7 @@ def load(channel, value, repetitions, latency=0): raise Exception(msg) try: ctrl.StartOne(axis, value) - except Exception, e: + except Exception as e: self.debug(e, exc_info=True) channel.set_state(State.Fault, propagate=2) msg = ("%s.StartOne(%d) failed" % @@ -497,7 +497,7 @@ def load(channel, value, repetitions, latency=0): channels = ctrls_channels[pool_ctrl] try: pool_ctrl.ctrl.StartAll() - except Exception, e: + except Exception as e: self.debug(e, exc_info=True) for channel in channels: channel.set_state(State.Fault, propagate=2) From 02429c9c7bb59b7a1391f9154776263b642349ee Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 15 Oct 2018 16:35:33 +0200 Subject: [PATCH 219/652] Adapt to use PoolAcquisitionBase class --- src/sardana/pool/poolacquisition.py | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 71b6e96332..68fb425c14 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -592,24 +592,6 @@ def __init__(self, main_element, name="AcquisitionSoftware", slaves=None): slaves = () self._slaves = slaves - @DebugIt() - def start_action(self, *args, **kwargs): - """Prepares everything for acquisition and starts it. - :param acq_sleep_time: sleep time between state queries - :param nb_states_per_value: how many state queries between readouts - :param integ_time: integration time(s) - :type integ_time: float or seq - :param repetitions: repetitions - :type repetitions: int - :param config: configuration dictionary (with information about - involved controllers and channels) - :param index: trigger index that will be assigned to the acquired value - :type index: int - """ - - PoolAcquisitionBase.start_action(self, *args, **kwargs) - self.index = kwargs.get("idx") - @DebugIt() def action_loop(self): states, values = {}, {} @@ -656,7 +638,7 @@ def action_loop(self): if is_value_error(value): self.error("Loop final read value error for: %s" % acquirable.name) - acquirable.append_value_buffer(value, self.index) + acquirable.append_value_buffer(value, self._index) with acquirable: acquirable.clear_operation() state_info = acquirable._from_ctrl_state_info(state_info) From 322ec9f23ffd6a42db8076016488a0b64dd5ff99 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 15 Oct 2018 17:20:06 +0200 Subject: [PATCH 220/652] Rename start_action parameters --- src/sardana/pool/poolacquisition.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 68fb425c14..a0c8ac1151 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -357,7 +357,7 @@ def in_acquisition(self, states): return True @DebugIt() - def start_action(self, ctrls_channels, ctrls_loadables, value, + def start_action(self, ctrl_channels, ctrl_loadable, value, repetitions=1, latency=0, master=None, index=None, acq_sleep_time=None, nb_states_per_value=None, *args, @@ -388,7 +388,7 @@ def start_action(self, ctrls_channels, ctrls_loadables, value, # controllers to be started (only enabled) in the right order - pool_ctrls = ctrls_channels.keys() + pool_ctrls = ctrl_channels.keys() # make sure the controller which has the master channel is the last to # be called @@ -398,7 +398,7 @@ def start_action(self, ctrls_channels, ctrls_loadables, value, pool_ctrls.append(master_ctrl) # controllers that will be read at the end of the action - self._pool_ctrl_dict_loop = ctrls_channels + self._pool_ctrl_dict_loop = ctrl_channels # channels that are acquired (only enabled) self._channels = [] @@ -446,7 +446,7 @@ def load(channel, value, repetitions, latency=0): with ActionContext(self): # PreLoadAll, PreLoadOne, LoadOne and LoadAll - loadables = ctrls_loadables.values() + loadables = ctrl_loadable.values() for channel in loadables: load(channel, value, repetitions, latency) @@ -463,11 +463,11 @@ def load(channel, value, repetitions, latency=0): channels_started = [] # PreStartOne & StartOne on all enabled elements for pool_ctrl in pool_ctrls: - channels = ctrls_channels[pool_ctrl] + channels = ctrl_channels[pool_ctrl] ctrl = pool_ctrl.ctrl # make sure that the timer/monitor is started as the last one - loadable = ctrls_loadables[pool_ctrl] + loadable = ctrl_loadable[pool_ctrl] channels.remove(loadable) channels.append(loadable) for channel in channels: @@ -494,7 +494,7 @@ def load(channel, value, repetitions, latency=0): # StartAll on all enabled controllers for pool_ctrl in pool_ctrls: - channels = ctrls_channels[pool_ctrl] + channels = ctrl_channels[pool_ctrl] try: pool_ctrl.ctrl.StartAll() except Exception as e: From 33ff25044bbc4a1058795574c04b40f3dabc6427 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 15 Oct 2018 17:22:02 +0200 Subject: [PATCH 221/652] Update start_action docstring --- src/sardana/pool/poolacquisition.py | 31 ++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index a0c8ac1151..c3af02673f 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -362,16 +362,33 @@ def start_action(self, ctrl_channels, ctrl_loadable, value, index=None, acq_sleep_time=None, nb_states_per_value=None, *args, **kwargs): - """Prepares everything for acquisition and starts it. - :param acq_sleep_time: sleep time between state queries - :param nb_states_per_value: how many state queries between readouts - :param integ_time: integration time(s) - :type integ_time: float or seq + """ + Prepares everything for acquisition and starts it + :param ctrl_channels: Dictionary with controllers as key and its + enabled channels + :type ctrl_channels: dict + :param ctrl_loadable: Dictionary with controllers as key and its + timerable channel + :type ctrl_loadable: dict + :param value: integration time/monitor counts + :type value: float/int or seq :param repetitions: repetitions :type repetitions: int - :param config: configuration dictionary (with information about - involved controllers and channels) + :param latency: + :type latency: float + :param master: master channel is the last one to start + :type master: Channel + :param index: + :type index: int + :param acq_sleep_time: sleep time between state queries + :type acq_sleep_time: float + :param nb_states_per_value: how many state queries between readouts + :type nb_states_per_value: int + :param args: + :param kwargs: + :return: """ + pool = self.pool self._aborted = False self._stopped = False From e78fd6b89524335304b6cc78566893e2b4b9b567 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 15 Oct 2018 17:43:47 +0200 Subject: [PATCH 222/652] Do use_fqdn to private attribute --- src/sardana/pool/poolmeasurementgroup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 176fb02047..185bba5d39 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -137,7 +137,7 @@ def __init__(self, parent=None): if parent is not None: self._parent = weakref.ref(parent)() self._config = None - self.use_fqdn = True + self._use_fqdn = True self._clean_variables() def _clean_variables(self): @@ -281,7 +281,7 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): config['label'] = cfg.get('label', self._parent.name) config['description'] = cfg.get('description', self.DFT_DESC) - self.use_fqdn = to_fqdn + self._use_fqdn = to_fqdn self._build_configuration(config) def get_configuration_for_user(self): @@ -466,7 +466,7 @@ def _build_configuration(self, config=None): channel_data['source'] = _id else: full_name = channel_data['full_name'] - if self.use_fqdn: + if self._use_fqdn: full_name = _to_fqdn(full_name, logger=self._parent) element = pool.get_element_by_full_name(full_name) @@ -721,7 +721,7 @@ def configuration(self): return self._config def set_configuration(self, config=None, propagate=1, to_fqdn=True): - self._config.use_fqdn = to_fqdn + self._config._use_fqdn = to_fqdn self._config.configuration = config self._config_dirty = True if not propagate: From b0d16caf69d9a81eddb6772a71d1c700c5abb558 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 16 Oct 2018 15:24:16 +0200 Subject: [PATCH 223/652] Fix weak reference Use a weak reference of the parent instead of the object itself. --- src/sardana/pool/poolmeasurementgroup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 185bba5d39..987d914295 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -135,7 +135,7 @@ class MeasurementConfiguration(object): def __init__(self, parent=None): self._parent = None if parent is not None: - self._parent = weakref.ref(parent)() + self._parent = weakref.proxy(parent) self._config = None self._use_fqdn = True self._clean_variables() From 3df878b7d7ffe09426f94509f04483594adc852e Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 17 Oct 2018 18:38:15 +0200 Subject: [PATCH 224/652] Refactor acquisition and its tests to use ControllerConfiguration objects ControllerConfiguration objects will have information about its channels and its master channel. Assume it in start_action and tests. --- src/sardana/pool/poolacquisition.py | 37 +++++++++-------------- src/sardana/pool/test/test_acquisition.py | 14 ++++----- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index c3af02673f..a7ff6c17ab 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -357,19 +357,14 @@ def in_acquisition(self, states): return True @DebugIt() - def start_action(self, ctrl_channels, ctrl_loadable, value, - repetitions=1, latency=0, master=None, - index=None, acq_sleep_time=None, + def start_action(self, pool_ctrls, value, repetitions=1, latency=0, + master=None, index=None, acq_sleep_time=None, nb_states_per_value=None, *args, **kwargs): """ Prepares everything for acquisition and starts it - :param ctrl_channels: Dictionary with controllers as key and its - enabled channels - :type ctrl_channels: dict - :param ctrl_loadable: Dictionary with controllers as key and its - timerable channel - :type ctrl_loadable: dict + :param pool_ctrls: List of enabled controllers + :type pool_ctrls: list :param value: integration time/monitor counts :type value: float/int or seq :param repetitions: repetitions @@ -403,10 +398,6 @@ def start_action(self, ctrl_channels, ctrl_loadable, value, if self._nb_states_per_value is None: self._nb_states_per_value = pool.acq_loop_states_per_value - - # controllers to be started (only enabled) in the right order - pool_ctrls = ctrl_channels.keys() - # make sure the controller which has the master channel is the last to # be called if master is not None: @@ -415,7 +406,11 @@ def start_action(self, ctrl_channels, ctrl_loadable, value, pool_ctrls.append(master_ctrl) # controllers that will be read at the end of the action + ctrl_channels = {} + for pool_ctrl in pool_ctrls: + ctrl_channels[pool_ctrl] = pool_ctrl.channels self._pool_ctrl_dict_loop = ctrl_channels + # channels that are acquired (only enabled) self._channels = [] @@ -463,9 +458,8 @@ def load(channel, value, repetitions, latency=0): with ActionContext(self): # PreLoadAll, PreLoadOne, LoadOne and LoadAll - loadables = ctrl_loadable.values() - for channel in loadables: - load(channel, value, repetitions, latency) + for pool_ctrl in pool_ctrls: + load(pool_ctrl.master, value, repetitions, latency) # TODO: remove when the action allows to use tango attributes try: @@ -477,16 +471,15 @@ def load(channel, value, repetitions, latency=0): for pool_ctrl in pool_ctrls: pool_ctrl.ctrl.PreStartAll() - channels_started = [] # PreStartOne & StartOne on all enabled elements for pool_ctrl in pool_ctrls: - channels = ctrl_channels[pool_ctrl] + channels = pool_ctrl.channels ctrl = pool_ctrl.ctrl - # make sure that the timer/monitor is started as the last one - loadable = ctrl_loadable[pool_ctrl] - channels.remove(loadable) - channels.append(loadable) + # make sure that the master timer/monitor is started as the + # last one + channels.remove(pool_ctrl.master) + channels.append(pool_ctrl.master) for channel in channels: axis = channel.axis ret = ctrl.PreStartOne(axis, value) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index eab0329cba..6c49bc2541 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -304,10 +304,10 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, self.channel_names.append('_test_ct_1_1') self.channel_names.append('_test_ct_2_1') - acq_hw_ctrl_channels = {ct_ctrl_1: [ct_1_1]} - acq_hw_ctrl_loadable = {ct_ctrl_1: ct_1_1} - acq_sw_ctrl_channels = {ct_ctrl_2: [ct_2_1]} - acq_sw_ctrl_loadable = {ct_ctrl_2: ct_2_1} + ct_ctrl_1.channels = [ct_1_1] + ct_ctrl_1.master = ct_1_1 + ct_ctrl_2.channels = [ct_2_1] + ct_ctrl_2.master = ct_2_1 # crating configuration for TGGeneration tg_cfg = createPoolSynchronizationConfiguration((tg_ctrl_2,), ((tg_2_1,),)) @@ -335,12 +335,10 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, # get the current number of jobs jobs_before = get_thread_pool().qsize - self.sw_acq_args = (acq_sw_ctrl_channels, acq_sw_ctrl_loadable, - integ_time) + self.sw_acq_args = ([ct_ctrl_2], integ_time) self.sw_acq_kwargs = {"master": ct_2_1} ct_ctrl_1.set_ctrl_par('synchronization', AcqSynch.HardwareTrigger) - hw_acq_args = (acq_hw_ctrl_channels, acq_hw_ctrl_loadable, - integ_time, repetitions) + hw_acq_args = ([ct_ctrl_1], integ_time, repetitions) self.hw_acq.run(*hw_acq_args) tg_args = () total_interval = active_interval + passive_interval From 434fcf94a91ff261caee5a990f0f519839aec7bd Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 18 Oct 2018 11:48:00 +0200 Subject: [PATCH 225/652] Add configuration helpers classes Add classes to help the use of the static measurement configuration. --- src/sardana/pool/poolmeasurementgroup.py | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 987d914295..6dad6ee9e1 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -124,6 +124,35 @@ def _to_fqdn(name, logger=None): return full_name +class ConfigurationItem(object): + def __init__(self, element, conf=None): + self._element = weakref.ref(element) + if conf is not None: + self.__dict__.update(conf) + + def __getattr__(self, item): + return getattr(self.element, item) + + def get_element(self): + """Returns the element associated with this item""" + return self._element() + + def set_element(self, element): + """Sets the element for this item""" + self._element = weakref.ref(element) + + element = property(get_element) + + +class ControllerConfiguration(ConfigurationItem): + """Configuration: 'timer', 'monitor', 'synchronization', 'channels'""" + + +class ChannelConfiguration(ConfigurationItem): + """Configuration: 'id', 'enabled', 'output', 'plot_type', 'plot_axes', + 'label', 'scale', 'plot_color'""" + + class MeasurementConfiguration(object): """ .. todo: Reject configuration with errors: From 310312b6b2c40c9e37076f889be00b51126b95f0 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Thu, 18 Oct 2018 18:41:05 +0200 Subject: [PATCH 226/652] check if moveable has any defined position --- src/sardana/macroserver/scan/gscan.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index 06087d68a2..9f349bd063 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -384,6 +384,10 @@ def _check_moveables_limits(self): except ValueError: low = None for pos in (m.min_value, m.max_value): + if pos is None: + self._macro.warning("Macro did not define position for %s. " + "Limit check was not possible." % m.moveable.getName()) + continue if high is not None: if float(pos) > high: raise RuntimeError( From 21563facdd2320ff229d0f0b134b52b7d89115b1 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 22 Oct 2018 11:23:59 +0200 Subject: [PATCH 227/652] Add Unit Test for macros examples --- src/sardana/spock/test/test_parser.py | 292 +++++++++++++++++++++++++- 1 file changed, 291 insertions(+), 1 deletion(-) diff --git a/src/sardana/spock/test/test_parser.py b/src/sardana/spock/test/test_parser.py index cbe99b068c..29377ecb8f 100644 --- a/src/sardana/spock/test/test_parser.py +++ b/src/sardana/spock/test/test_parser.py @@ -76,6 +76,16 @@ def parse(self, params_str, params): } ] +pt2_params_def = [ + { + "default_value": None, + "description": "some bloody motor", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + } +] pt3_params_def = [ { "default_value": None, @@ -116,6 +126,26 @@ def parse(self, params_str, params): } ] +pt4_params_def = [ + { + "default_value": None, + "description": "List of motors", + "max": None, + "min": 1, + "name": "motor_list", + "type": [ + { + "default_value": None, + "description": "motor name", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + } + ] + } +] + pt5_params_def = [ { "default_value": None, @@ -137,7 +167,35 @@ def parse(self, params_str, params): "description": "value", "max": None, "min": 1, - "name": "position", + "name": "pos", + "type": "Float" + } + ] + } +] + +pt6_params_def = [ + { + "default_value": None, + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + }, + { + "default_value": None, + "description": "List of values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": None, + "description": "value", + "max": None, + "min": 1, + "name": "pos", "type": "Float" } ] @@ -172,6 +230,118 @@ def parse(self, params_str, params): } ] +pt7d1_params_def = [ + { + "default_value": None, + "description": "List of motor/position pairs", + "max": None, + "min": 1, + "name": "m_p_pair", + "type": [ + { + "default_value": None, + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + }, + { + "default_value": 2, + "description": "Position to move to", + "max": None, + "min": 1, + "name": "pos", + "type": "Float" + } + ] + } +] + +pt7d2_params_def = [ + { + "default_value": None, + "description": "List of motor/position pairs", + "max": None, + "min": 1, + "name": "m_p_pair", + "type": [ + { + "default_value": 'mot1', + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + }, + { + "default_value": 2, + "description": "Position to move to", + "max": None, + "min": 1, + "name": "pos", + "type": "Float" + } + ] + } +] + +pt8_params_def = [ + { + "default_value": None, + "description": "List of motor/position pairs", + "max": None, + "min": 1, + "name": "m_p_pair", + "type": [ + { + "default_value": None, + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + }, + { + "default_value": None, + "description": "Position to move to", + "max": 2, + "min": 1, + "name": "pos", + "type": "Float" + } + ] + } +] + +pt9_params_def = [ + { + "default_value": None, + "description": "List of motor/position pairs", + "max": None, + "min": 1, + "name": "m_p_pair", + "type": [ + { + "default_value": None, + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + }, + { + "default_value": None, + "description": "Position to move to", + "max": 2, + "min": 1, + "name": "pos", + "type": "Float" + } + ] + } +] + pt10_params_def = [ { "default_value": None, @@ -200,6 +370,81 @@ def parse(self, params_str, params): }, ] +pt11_params_def = [ + + { + "default_value": None, + "description": "Counter to count", + "max": None, + "min": 1, + "name": "counter", + "type": "ExpChannel" + }, + { + "default_value": None, + "description": "List of values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": None, + "description": "value", + "max": None, + "min": 1, + "name": "pos", + "type": "Float" + }, + ] + }, + { + "default_value": None, + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + }, +] + +pt12_params_def = [ + + { + "default_value": None, + "description": "List of values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": None, + "description": "value", + "max": None, + "min": 1, + "name": "pos", + "type": "Float" + }, + ] + }, + { + "default_value": None, + "description": "List of Motors", + "max": None, + "min": 1, + "name": "motor_list", + "type": [ + { + "default_value": 'mot1', + "description": "Motor to move", + "max": None, + "min": 1, + "name": "motor", + "type": "Motor" + }, + ] + }, +] + pt13_params_def = [ { "default_value": None, @@ -273,6 +518,8 @@ def parse(self, params_str, params): params_str="1", params=["1"]) @insertTest(helper_name="parse", params_def=pt1d_params_def, params_str="", params=[]) +@insertTest(helper_name="parse", params_def=pt2_params_def, + params_str="mot1", params=["mot1"]) @insertTest(helper_name="parse", params_def=pt3_params_def, params_str="1 34 15", params=[["1", "34", "15"]]) @insertTest(helper_name="parse", params_def=pt3_params_def, @@ -283,20 +530,63 @@ def parse(self, params_str, params): params_str="[1 34 15]", params=[["1", "34", "15"]]) @insertTest(helper_name="parse", params_def=pt3d_params_def, params_str="[1 [] 15]", params=[["1", [], "15"]]) +@insertTest(helper_name="parse", params_def=pt4_params_def, + params_str="[mot1 mot2 mot3]", params=[["mot1", "mot2", "mot3"]]) +@insertTest(helper_name="parse", params_def=pt4_params_def, + params_str="mot1 mot2 mot3", params=[["mot1", "mot2", "mot3"]]) @insertTest(helper_name="parse", params_def=pt5_params_def, params_str="mot1 1 3", params=["mot1", ["1", "3"]]) @insertTest(helper_name="parse", params_def=pt5_params_def, params_str="mot1 [1 3]", params=["mot1", ["1", "3"]]) +@insertTest(helper_name="parse", params_def=pt6_params_def, + params_str="mot1 [1 34 1]", params=["mot1", ["1", "34", "1"]]) +@insertTest(helper_name="parse", params_def=pt6_params_def, + params_str="mot1 1 34 1", params=["mot1", ["1", "34", "1"]]) @insertTest(helper_name="parse", params_def=pt7_params_def, params_str="mot1 1 mot2 3", params=[[["mot1", "1"], ["mot2", "3"]]]) @insertTest(helper_name="parse", params_def=pt7_params_def, params_str="[[mot1 1] [mot2 3]]", params=[[["mot1", "1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt7d1_params_def, + params_str="[[mot1 1] [mot2 3]]", + params=[[["mot1", "1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt7d1_params_def, + params_str="mot1 1 mot2 3", + params=[[["mot1", "1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt7d1_params_def, + params_str="[[mot1] [mot2 3]]", + params=[[["mot1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt7d2_params_def, + params_str="[[mot1 1] [mot2 3]]", + params=[[["mot1", "1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt7d2_params_def, + params_str="mot1 1 mot2 3", + params=[[["mot1", "1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt7d2_params_def, + params_str="[[] [mot2 3] []]", + params=[[[], ["mot2", "3"], []]]) +@insertTest(helper_name="parse", params_def=pt8_params_def, + params_str="[[mot1 1] [mot2 3]]", + params=[[["mot1", "1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt8_params_def, + params_str="mot1 1 mot2 3", + params=[[["mot1", "1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt9_params_def, + params_str="[[mot1 1] [mot2 3]]", + params=[[["mot1", "1"], ["mot2", "3"]]]) +@insertTest(helper_name="parse", params_def=pt9_params_def, + params_str="mot1 1 mot2 3", + params=[[["mot1", "1"], ["mot2", "3"]]]) @insertTest(helper_name="parse", params_def=pt10_params_def, params_str="[1 3] mot1", params=[["1", "3"], "mot1"]) @insertTest(helper_name="parse", params_def=pt10_params_def, params_str="1 mot1", params=[["1"], "mot1"]) +@insertTest(helper_name="parse", params_def=pt11_params_def, + params_str="ct1 [1 3] mot1", params=["ct1", ["1", "3"], "mot1"]) +@insertTest(helper_name="parse", params_def=pt12_params_def, + params_str="[1 3 4] [mot1 mot2]", + params=[["1", "3", "4"], ["mot1", "mot2"]]) @insertTest(helper_name="parse", params_def=pt13_params_def, params_str="[[mot1 mot2] [mot3 mot4]]", params=[[["mot1", "mot2"], ["mot3", "mot4"]]]) From 7a7ad30970b6916b5a7dbd93ef8bed619de879b4 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 22 Oct 2018 11:24:46 +0200 Subject: [PATCH 228/652] Add Unit Test for custom test --- src/sardana/spock/test/test_parser.py | 297 ++++++++++++++++++++++++-- 1 file changed, 278 insertions(+), 19 deletions(-) diff --git a/src/sardana/spock/test/test_parser.py b/src/sardana/spock/test/test_parser.py index 29377ecb8f..403ff2c94f 100644 --- a/src/sardana/spock/test/test_parser.py +++ b/src/sardana/spock/test/test_parser.py @@ -30,25 +30,6 @@ from sardana.spock.parser import ParamParser -# @insertTest(helper_name="parse", -# params_str='ScanFile "[\\"file.nxs\\", \\"file.dat\\"]"', -# params=["ScanFile", '["file.nxs", "file.dat"]']) -# @insertTest(helper_name="parse", params_str="[1 [] 3]", -# params=[["1", [], "3"]]) -# @insertTest(helper_name="parse", -# params_str="2 3 ['Hello world!' 'How are you?']", -# params=["2", "3", ["Hello world!", "How are you?"]]) -# @insertTest(helper_name="parse", params_str="ScanFile file.dat", -# params=["ScanFile", "file.dat"]) -# @insertTest(helper_name="parse", params_str="'2 3'", params=["2 3"]) -# @insertTest(helper_name="parse", params_str='"2 3"', params=["2 3"]) -# @insertTest(helper_name="parse", params_str="[[mot01 3][mot02 5]] ct01 999", -# params=[[["mot01", "3"], ["mot02", "5"]], "ct01", "999"]) -# @insertTest(helper_name="parse", params_str="[[2 3][4 5]]", -# params=[[["2", "3"], ["4", "5"]]]) -# @insertTest(helper_name="parse", params_str="1 [2 3]", -# params=["1", ["2", "3"]]) -# @insertTest(helper_name="parse", params_str="2 3", params=["2", "3"]) class ParamParserTestCase(unittest.TestCase): """Unit tests for ParamParser class.""" @@ -511,6 +492,260 @@ def parse(self, params_str, params): } ] +pt15_params_def = [ + { + "default_value": None, + "description": "Parameter", + "max": None, + "min": 1, + "name": "param", + "type": "String" + }, + { + "default_value": None, + "description": "List of Scan files", + "max": None, + "min": 1, + "name": "ScanFiles List", + "type": [ + { + "default_value": None, + "description": "ScanFile", + "max": None, + "min": 1, + "name": "ScanFile", + "type": "String", + } + ] + } +] + +pt16_params_def = [ + { + "default_value": None, + "description": "List of values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": 2, + "description": "value", + "max": None, + "min": 1, + "name": "position", + "type": "Float" + } + ] + } +] + +pt17_params_def = [ + + { + "default_value": None, + "description": "Value 1", + "max": None, + "min": 1, + "name": "value1", + "type": "Float" + }, + { + "default_value": None, + "description": "Value 2", + "max": None, + "min": 1, + "name": "value2", + "type": "float" + }, + { + "default_value": None, + "description": "List of Strings", + "max": None, + "min": 1, + "name": "string_list", + "type": [ + { + "default_value": None, + "description": "string", + "max": None, + "min": 1, + "name": "string", + "type": "String" + }, + ] + }, +] +pt18_params_def = [ + + { + "default_value": None, + "description": "param", + "max": None, + "min": 1, + "name": "param", + "type": "String" + }, + { + "default_value": None, + "description": "Value", + "max": None, + "min": 1, + "name": "value", + "type": "String" + }, +] + +pt19_params_def = [ + + { + "default_value": None, + "description": "value 1", + "max": None, + "min": 1, + "name": "value1", + "type": "Float" + }, + { + "default_value": None, + "description": "Value 2", + "max": None, + "min": 1, + "name": "value2", + "type": "Float" + }, +] + + +pt20_params_def = [ + + { + "default_value": None, + "description": "List of Motor and Values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": None, + "description": "Motor", + "max": None, + "min": 1, + "name": "pos", + "type": "Motor" + }, + { + "default_value": None, + "description": "Position to move to", + "max": 2, + "min": 1, + "name": "pos", + "type": "Float" + } + ] + }, + { + "default_value": None, + "description": "Counter to use", + "max": None, + "min": 1, + "name": "counter", + "type": "ExpChan" + }, + { + "default_value": None, + "description": "Value", + "max": None, + "min": 1, + "name": "Value", + "type": "Float" + } +] +pt21_params_def = [ + + { + "default_value": None, + "description": "List of Values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": None, + "description": "Value 1", + "max": None, + "min": 1, + "name": "value1", + "type": "Float" + }, + { + "default_value": None, + "description": "Value 2", + "max": None, + "min": 1, + "name": "value2", + "type": "Float" + } + ] + } +] + +pt22_params_def = [ + + { + "default_value": None, + "description": "value 1", + "max": None, + "min": 1, + "name": "value1", + "type": "Float" + }, + { + "default_value": None, + "description": "List of Values", + "max": None, + "min": 1, + "name": "numb_list", + "type": [ + { + "default_value": None, + "description": "Value 2.1", + "max": None, + "min": 1, + "name": "value21", + "type": "Float" + }, + { + "default_value": None, + "description": "Value 2.2", + "max": None, + "min": 1, + "name": "value22", + "type": "Float" + } + ] + } +] +pt23_params_def = [ + + { + "default_value": None, + "description": "value 1", + "max": None, + "min": 1, + "name": "value1", + "type": "Float" + }, + { + "default_value": None, + "description": "Value 2", + "max": None, + "min": 1, + "name": "value2", + "type": "Float" + }, +] + @insertTest(helper_name="parse", params_def=pt0_params_def, params_str="", params=[]) @@ -593,6 +828,30 @@ def parse(self, params_str, params): @insertTest(helper_name="parse", params_def=pt14_params_def, params_str="[[[mot1 mot2] 3] [[mot3] 5]]", params=[[[["mot1", "mot2"], "3"], [["mot3"], "5"]]]) +@insertTest(helper_name="parse", params_def=pt15_params_def, + params_str="ScanFile ['file.nxs' 'file.dat']", + params=["ScanFile", ["file.nxs", "file.dat"]]) +@insertTest(helper_name="parse", params_def=pt16_params_def, + params_str="[1 [] 3]", params=[["1", [], "3"]]) +@insertTest(helper_name="parse", params_def=pt17_params_def, + params_str="2 3 ['Hello world!' 'How are you?']", + params=["2", "3", ["Hello world!", "How are you?"]]) +@insertTest(helper_name="parse", params_def=pt18_params_def, + params_str="ScanFile file.dat", + params=["ScanFile", "file.dat"]) +@insertTest(helper_name="parse", params_def=pt19_params_def, + params_str="'2 3'", params=["2 3"]) +@insertTest(helper_name="parse", params_def=pt20_params_def, + params_str="[[mot01 3][mot02 5]] ct01 999", + params=[[["mot01", "3"], ["mot02", "5"]], "ct01", "999"]) +@insertTest(helper_name="parse", params_def=pt21_params_def, + params_str="[[2 3][4 5]]", + params=[[["2", "3"], ["4", "5"]]]) +@insertTest(helper_name="parse", params_def=pt22_params_def, + params_str="1 [2 3]", + params=["1", ["2", "3"]]) +@insertTest(helper_name="parse", params_def=pt23_params_def, + params_str="2 3", params=["2", "3"]) class ParamParserWithDefTestCase(unittest.TestCase): """Unit tests for ParamParser class initialized with parameters definition. From f79d501d70af6903eb68dd5c818b39e17d39aedb Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 19 Oct 2018 16:07:55 +0200 Subject: [PATCH 229/652] Fix parsing of non-complete repeats --- src/sardana/spock/parser.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sardana/spock/parser.py b/src/sardana/spock/parser.py index b01e57c6aa..65ca7b9df2 100644 --- a/src/sardana/spock/parser.py +++ b/src/sardana/spock/parser.py @@ -118,7 +118,7 @@ def _expect(self, toktype): # Grammar rules follow - def _params(self, params_def=None): + def _params(self, params_def=None, is_repeat=False): """Interpret parameter values by iterating over generated tokens according to parameters definition. @@ -151,7 +151,14 @@ def _params(self, params_def=None): param_value = self._repeat_param(repeat_param_def, last_param) else: - param_value = self._param() + try: + param_value = self._param() + except UnrecognizedParamValue: + # this exception may occur if repeat is not complete - + # uses default values + if is_repeat: + return params + raise params.append(param_value) return params @@ -238,7 +245,7 @@ def _repeat(self, repeat_param_def): if self._accept("RPAREN"): repeat = [] else: - repeat = self._params(repeat_param_def) + repeat = self._params(repeat_param_def, is_repeat=True) # repetitions of single repeat parameters are not enclosed # in parenthesis so remove it if is_repeat_param_single(repeat_param_def): From 0c870e460242f3f9495e1354f509a7b9182e2423 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 19 Oct 2018 16:17:44 +0200 Subject: [PATCH 230/652] (minor) rename variable --- src/sardana/spock/parser.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sardana/spock/parser.py b/src/sardana/spock/parser.py index 65ca7b9df2..880ea77f60 100644 --- a/src/sardana/spock/parser.py +++ b/src/sardana/spock/parser.py @@ -144,12 +144,12 @@ def _params(self, params_def=None, is_repeat=False): if self.nexttok is None: break if is_repeat_param(param_def): - last_param = False + is_last_param = False if param_idx == len_params_def - 1: - last_param = True + is_last_param = True repeat_param_def = param_def["type"] param_value = self._repeat_param(repeat_param_def, - last_param) + is_last_param) else: try: param_value = self._param() @@ -184,7 +184,7 @@ def _param(self): raise UnrecognizedParamValue(msg) return param - def _repeat_param(self, repeat_param_def, last_param): + def _repeat_param(self, repeat_param_def, is_last_param): """Interpret repeat parameter. Accepts repeat parameters using the following rules: @@ -196,9 +196,9 @@ def _repeat_param(self, repeat_param_def, last_param): :param repeat_param_def: repeat parameter definition :type repeat_param_def: list - :param last_param: whether this repeat parameter is the last in the + :param is_last_param: whether this repeat parameter is the last in the definition - :type last_param: bool + :type is_last_param: bool :return: repeat parameter value :rtype: list """ @@ -213,7 +213,7 @@ def _repeat_param(self, repeat_param_def, last_param): self._expect("RPAREN") else: single = is_repeat_param_single(repeat_param_def) - if last_param: + if is_last_param: while True: repeat = [] for _ in repeat_param_def: From b63b10768470e021796ed04935da1047f54d1754 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 22 Oct 2018 12:48:56 +0200 Subject: [PATCH 231/652] Rename param_def variables Rename param_def variables to not collide with eventual new parameter examples. --- src/sardana/spock/test/test_parser.py | 56 +++++++++------------------ 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/src/sardana/spock/test/test_parser.py b/src/sardana/spock/test/test_parser.py index 403ff2c94f..80edc3ecfe 100644 --- a/src/sardana/spock/test/test_parser.py +++ b/src/sardana/spock/test/test_parser.py @@ -492,7 +492,7 @@ def parse(self, params_str, params): } ] -pt15_params_def = [ +extra1_params_def = [ { "default_value": None, "description": "Parameter", @@ -520,27 +520,7 @@ def parse(self, params_str, params): } ] -pt16_params_def = [ - { - "default_value": None, - "description": "List of values", - "max": None, - "min": 1, - "name": "numb_list", - "type": [ - { - "default_value": 2, - "description": "value", - "max": None, - "min": 1, - "name": "position", - "type": "Float" - } - ] - } -] - -pt17_params_def = [ +extra2_params_def = [ { "default_value": None, @@ -576,7 +556,7 @@ def parse(self, params_str, params): ] }, ] -pt18_params_def = [ +extra3_params_def = [ { "default_value": None, @@ -596,7 +576,7 @@ def parse(self, params_str, params): }, ] -pt19_params_def = [ +extra4_params_def = [ { "default_value": None, @@ -617,7 +597,7 @@ def parse(self, params_str, params): ] -pt20_params_def = [ +extra5_params_def = [ { "default_value": None, @@ -661,7 +641,7 @@ def parse(self, params_str, params): "type": "Float" } ] -pt21_params_def = [ +extra6_params_def = [ { "default_value": None, @@ -690,7 +670,7 @@ def parse(self, params_str, params): } ] -pt22_params_def = [ +extra7_params_def = [ { "default_value": None, @@ -726,7 +706,7 @@ def parse(self, params_str, params): ] } ] -pt23_params_def = [ +extra8_params_def = [ { "default_value": None, @@ -747,6 +727,7 @@ def parse(self, params_str, params): ] +# parameters examples tests @insertTest(helper_name="parse", params_def=pt0_params_def, params_str="", params=[]) @insertTest(helper_name="parse", params_def=pt1d_params_def, @@ -828,29 +809,28 @@ def parse(self, params_str, params): @insertTest(helper_name="parse", params_def=pt14_params_def, params_str="[[[mot1 mot2] 3] [[mot3] 5]]", params=[[[["mot1", "mot2"], "3"], [["mot3"], "5"]]]) -@insertTest(helper_name="parse", params_def=pt15_params_def, +# extra tests for complex parameter values +@insertTest(helper_name="parse", params_def=extra1_params_def, params_str="ScanFile ['file.nxs' 'file.dat']", params=["ScanFile", ["file.nxs", "file.dat"]]) -@insertTest(helper_name="parse", params_def=pt16_params_def, - params_str="[1 [] 3]", params=[["1", [], "3"]]) -@insertTest(helper_name="parse", params_def=pt17_params_def, +@insertTest(helper_name="parse", params_def=extra2_params_def, params_str="2 3 ['Hello world!' 'How are you?']", params=["2", "3", ["Hello world!", "How are you?"]]) -@insertTest(helper_name="parse", params_def=pt18_params_def, +@insertTest(helper_name="parse", params_def=extra3_params_def, params_str="ScanFile file.dat", params=["ScanFile", "file.dat"]) -@insertTest(helper_name="parse", params_def=pt19_params_def, +@insertTest(helper_name="parse", params_def=extra4_params_def, params_str="'2 3'", params=["2 3"]) -@insertTest(helper_name="parse", params_def=pt20_params_def, +@insertTest(helper_name="parse", params_def=extra5_params_def, params_str="[[mot01 3][mot02 5]] ct01 999", params=[[["mot01", "3"], ["mot02", "5"]], "ct01", "999"]) -@insertTest(helper_name="parse", params_def=pt21_params_def, +@insertTest(helper_name="parse", params_def=extra6_params_def, params_str="[[2 3][4 5]]", params=[[["2", "3"], ["4", "5"]]]) -@insertTest(helper_name="parse", params_def=pt22_params_def, +@insertTest(helper_name="parse", params_def=extra7_params_def, params_str="1 [2 3]", params=["1", ["2", "3"]]) -@insertTest(helper_name="parse", params_def=pt23_params_def, +@insertTest(helper_name="parse", params_def=extra8_params_def, params_str="2 3", params=["2", "3"]) class ParamParserWithDefTestCase(unittest.TestCase): """Unit tests for ParamParser class initialized with parameters From 256fc31bf16a83da448a46085a0f410a6d42f11c Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 22 Oct 2018 12:51:17 +0200 Subject: [PATCH 232/652] Final rename of test class --- src/sardana/spock/test/test_parser.py | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/sardana/spock/test/test_parser.py b/src/sardana/spock/test/test_parser.py index 80edc3ecfe..ad78f78b4c 100644 --- a/src/sardana/spock/test/test_parser.py +++ b/src/sardana/spock/test/test_parser.py @@ -30,20 +30,6 @@ from sardana.spock.parser import ParamParser -class ParamParserTestCase(unittest.TestCase): - """Unit tests for ParamParser class.""" - - def parse(self, params_str, params): - """Helper method to test parameters parsing. To be used with insertTest - decorator. - """ - p = ParamParser() - result = p.parse(params_str) - msg = "Parsing failed (result: %r; expected: %r)" %\ - (result, params) - self.assertListEqual(result, params, msg) - - pt0_params_def = [] pt1d_params_def = [ @@ -832,11 +818,14 @@ def parse(self, params_str, params): params=["1", ["2", "3"]]) @insertTest(helper_name="parse", params_def=extra8_params_def, params_str="2 3", params=["2", "3"]) -class ParamParserWithDefTestCase(unittest.TestCase): - """Unit tests for ParamParser class initialized with parameters - definition. +class ParamParserTestCase(unittest.TestCase): + """Unit tests for ParamParser class. Mainly based on macro examples for + parameters definition. """ def parse(self, params_def, params_str, params): + """Helper method to test parameters parsing. To be used with + insertTest decorator. + """ p = ParamParser(params_def) result = p.parse(params_str) msg = "Parsing failed (result: %r; expected: %r)" % \ From 237fbe2b2ba8698688d1b30acdbfadfb9278c223 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 23 Oct 2018 09:37:38 +0200 Subject: [PATCH 233/652] (docs) Add link to plugins register in how-to-ctrls --- doc/source/devel/howto_controllers/index.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/source/devel/howto_controllers/index.rst b/doc/source/devel/howto_controllers/index.rst index 034f023086..34e093ebfb 100644 --- a/doc/source/devel/howto_controllers/index.rst +++ b/doc/source/devel/howto_controllers/index.rst @@ -6,7 +6,12 @@ Writing controllers =================== -This chapter provides the necessary information to write controllers in sardana. +This chapter provides the necessary information to write controllers in +sardana. + +Before writing a new controller you should check the `controller plugin +register `_. +There's a high chance that somebody already wrote the plugin for your hardware. An overview of the pool controller concept can be found :ref:`here `. From df2f61564f48bda046a3399a493cef7872151730 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 23 Oct 2018 14:37:50 +0200 Subject: [PATCH 234/652] Move parser from spock to util --- src/sardana/{spock => util}/parser.py | 0 src/sardana/{spock => util}/test/test_parser.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/sardana/{spock => util}/parser.py (100%) rename src/sardana/{spock => util}/test/test_parser.py (99%) diff --git a/src/sardana/spock/parser.py b/src/sardana/util/parser.py similarity index 100% rename from src/sardana/spock/parser.py rename to src/sardana/util/parser.py diff --git a/src/sardana/spock/test/test_parser.py b/src/sardana/util/test/test_parser.py similarity index 99% rename from src/sardana/spock/test/test_parser.py rename to src/sardana/util/test/test_parser.py index ad78f78b4c..c8a4c77eac 100644 --- a/src/sardana/spock/test/test_parser.py +++ b/src/sardana/util/test/test_parser.py @@ -27,7 +27,7 @@ from taurus.external import unittest from taurus.test import insertTest -from sardana.spock.parser import ParamParser +from sardana.util.parser import ParamParser pt0_params_def = [] From ef7bfcca6ac85ea6576f44d103f2bfbedc37134e Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 23 Oct 2018 14:38:17 +0200 Subject: [PATCH 235/652] Fix parser imports --- src/sardana/macroserver/msmacromanager.py | 2 +- src/sardana/spock/spockms.py | 2 +- src/sardana/taurus/core/tango/sardana/test/test_macro.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/macroserver/msmacromanager.py b/src/sardana/macroserver/msmacromanager.py index 992d0a03f8..38143f3055 100644 --- a/src/sardana/macroserver/msmacromanager.py +++ b/src/sardana/macroserver/msmacromanager.py @@ -70,7 +70,7 @@ from sardana.macroserver.msexception import UnknownMacroLibrary, \ LibraryError, UnknownMacro, MissingEnv, AbortException, StopException, \ MacroServerException, UnknownEnv -from sardana.spock.parser import ParamParser +from sardana.util.parser import ParamParser # These classes are imported from the "client" part of sardana, if finally # both the client and the server side needs them, place them in some diff --git a/src/sardana/spock/spockms.py b/src/sardana/spock/spockms.py index cca3035748..2a661f45b4 100755 --- a/src/sardana/spock/spockms.py +++ b/src/sardana/spock/spockms.py @@ -37,7 +37,7 @@ from sardana.sardanautils import is_pure_str, is_non_str_seq from sardana.spock import genutils -from sardana.spock.parser import ParamParser +from sardana.util.parser import ParamParser from sardana.spock.inputhandler import SpockInputHandler, InputHandler from sardana import sardanacustomsettings diff --git a/src/sardana/taurus/core/tango/sardana/test/test_macro.py b/src/sardana/taurus/core/tango/sardana/test/test_macro.py index 8ed8d271f5..0f6090537f 100755 --- a/src/sardana/taurus/core/tango/sardana/test/test_macro.py +++ b/src/sardana/taurus/core/tango/sardana/test/test_macro.py @@ -41,7 +41,7 @@ pt14d_param_def) # TODO: Use unittest.mock instead of this fake class. from sardana.macroserver.mstypemanager import TypeManager -from sardana.spock.parser import ParamParser +from sardana.util.parser import ParamParser class FakeMacroServer(object): From e1ce69ffcf6e40d8f5d5a3830142f186eb0e78cc Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 23 Oct 2018 16:22:04 +0200 Subject: [PATCH 236/652] Add method to ConfigurationItems classes --- src/sardana/pool/poolmeasurementgroup.py | 78 +++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 6dad6ee9e1..6126237633 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -127,12 +127,22 @@ def _to_fqdn(name, logger=None): class ConfigurationItem(object): def __init__(self, element, conf=None): self._element = weakref.ref(element) + + if conf is None: + conf = {'acq_synch': None} + else: + conf['acq_synch'] = None + if conf is not None: self.__dict__.update(conf) def __getattr__(self, item): return getattr(self.element, item) + def get_config(self): + """ Returns the configuration dictionary""" + raise NotImplementedError() + def get_element(self): """Returns the element associated with this item""" return self._element() @@ -147,11 +157,77 @@ def set_element(self, element): class ControllerConfiguration(ConfigurationItem): """Configuration: 'timer', 'monitor', 'synchronization', 'channels'""" + def __init__(self, element, conf=None): + self._channels = [] + self._channels_enabled = [] + self._channels_disabled = [] + self.enabled = False + + ConfigurationItem.__init__(self, element, conf) + + def get_config(self): + config = {} + # the external controllers: Tango attributes does not have timer and + # monitor + config['timer'] = self.timer.full_name + config['monitor'] = self.monitor.full_name + + if isinstance(self.synchronizer, (str, unicode)): + synchronizer = self.synchronizer + else: + synchronizer = self.synchronizer.full_name + config['synchronizer'] = synchronizer + config['synchronization'] = self.synchronization + config['channels'] = {} + for ch_item in self._channels: + config['channels'][ch_item.full_name] = ch_item.get_config() + return config + + def add_channel(self, channel_item): + self._channels.append(channel_item) + if channel_item.enabled: + self.enabled = True + if self._channels_enabled is None: + self._channels_enabled = [] + self._channels_enabled.append(channel_item) + else: + if self._channels_disabled is None: + self._channels_disabled = [] + self._channels_disabled.append(channel_item) + + def get_channels(self, enabled=None): + if enabled is None: + return list(self.channels) + elif enabled: + return list(self._channels_enabled) + else: + return list(self._channels_disabled) + class ChannelConfiguration(ConfigurationItem): - """Configuration: 'id', 'enabled', 'output', 'plot_type', 'plot_axes', + """Configuration: 'index', 'enabled', 'output', 'plot_type', 'plot_axes', 'label', 'scale', 'plot_color'""" + def get_config(self): + config = {} + config['index'] = self.index + config['name'] = self.name + config['full_name'] = self.full_name + config['source'] = self.source + config['enabled'] = self.enabled + config['label'] = self.label + config['ndim'] = self.ndim + config['output'] = self.output + config['plot_type'] = self.plot_type + config['plot_axes'] = self.plot_axes + config['conditioning'] = self.conditioning + config['normalization'] = self.normalization + config['data_type'] = self.data_type + config['data_units'] = self.data_units + config['nexus_path'] = self.nexus_path + config['shape'] = self.shape + return config + class MeasurementConfiguration(object): """ From 2bac2d67432e483cd574c216d5757c5caa9a4ccb Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 24 Oct 2018 10:52:51 +0200 Subject: [PATCH 237/652] Update doc strings --- .../taurus/core/tango/sardana/macro.py | 20 +++++++------------ .../taurus/core/tango/sardana/macroserver.py | 12 ++++------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py index 4b73b24d68..8c6b45935a 100755 --- a/src/sardana/taurus/core/tango/sardana/macro.py +++ b/src/sardana/taurus/core/tango/sardana/macro.py @@ -1274,8 +1274,9 @@ def fromPlainText(self, plainText): def ParamFactory(paramInfo): - """Factory method returning param element, depends of the paramInfo argument.""" - + """Factory method returning param element, depends of the paramInfo + argument. + """ if isinstance(paramInfo.get('type'), list): param = RepeatParamNode(param=paramInfo) if param.min() > 0: @@ -1286,21 +1287,14 @@ def ParamFactory(paramInfo): def createMacroNode(macro_name, params_def, macro_params): - """The best effort creation of the macro XML object. It tries to - convert flat list of string parameter values to the correct macro XML - object. - - Default values allow in ParamRepeat parameters or the last single ones + """Create of the macro node object. :param macro_name: (str) macro name :param params_def: (list) list of param definitions - :param macro_params: (sequence[str]) list of parameter values - - :return (lxml.etree._Element) macro XML element + :param macro_params: (sequence[str]) list of parameter values, if repeat + parameters are used parameter values may be sequences itself. - .. todo:: This method implements exactly the same logic as :meth: - `sardana.taurus.core.tango.sardana.macroserver.BaseDoor._createMacroXmlFromStr` - unify them and place in some common location. + :return (MacroNode) macro node object """ macro_node = MacroNode(name=macro_name, params_def=params_def) macro_node.fromList(macro_params) diff --git a/src/sardana/taurus/core/tango/sardana/macroserver.py b/src/sardana/taurus/core/tango/sardana/macroserver.py index ea381f2c9f..a21eeb02dd 100755 --- a/src/sardana/taurus/core/tango/sardana/macroserver.py +++ b/src/sardana/taurus/core/tango/sardana/macroserver.py @@ -490,16 +490,12 @@ def _clearRunMacro(self): self._block_lines = 0 def _createMacroXml(self, macro_name, macro_params): - """The best effort creation of the macro XML object. It tries to - convert flat list of string parameter values to the correct macro XML - object. The cases that can not be converted are: - * repeat parameter containing repeat parameters - * two repeat parameters - * repeat parameter that is not the last parameter + """Creation of the macro XML object. :param macro_name: (str) macro name - :param macro_params: (sequence[str]) list of parameter values - + :param macro_params: (sequence[str]) list of parameter values, + if repeat parameters are used parameter values may be sequences + itself. :return (lxml.etree._Element) macro XML element """ macro_info = self.macro_server.getMacroInfoObj(macro_name) From 26feef05246441cd1903bcd6ccffa1065ddf5132 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 24 Oct 2018 12:42:30 +0200 Subject: [PATCH 238/652] Document spock syntax --- doc/source/users/spock.rst | 139 ++++++++++++++++++++++++++++++++----- 1 file changed, 121 insertions(+), 18 deletions(-) diff --git a/doc/source/users/spock.rst b/doc/source/users/spock.rst index 43c43303a8..f974ce48f0 100755 --- a/doc/source/users/spock.rst +++ b/doc/source/users/spock.rst @@ -492,24 +492,127 @@ case a macro fails when being executed. Valid values are ``output``, ``critical``, ``error``, ``warning``, ``info``, ``debug`` and ``result``. -*Spock syntax* and *Advanced spock syntax* ------------------------------------------- - -*Spock syntax* is based on space separated list of parameter values. Not all macros -are allowed to be used with the spock syntax. Restrictions appear for those macros -using :ref:`repeat parameters ` as argument. The -*Spock syntax* would not allow: - -1. macros defining more than one repeat parameter -2. macros defining repeat parameter which is not at the end of the parameters definition -3. macros defining nested repeat parameters - -To overcome these restrictions an *Advanced spock syntax* was developed, this syntax introduces the -use of square brackets to group the repeat parameters and its repetitions. -The *Spock Syntax* was extended for the cases 1 and 2 in case only one repetion of the repeat -parameter is needed, this extension assumes that the parameter values passed by the user are a single -repetition of the repeat parameter. -A set of macro examples using both syntaxes can be found in :ref:`sardana-devel-macro-parameter-examples`. +Spock syntax +------------ + +*Spock syntax* is used to execute macros. It is based on space +separated list of parameter values. If the string parameter values contain +spaces itself these **must** be enclosed in quotes, either single quotes +``''`` or double quotes ``""``. + +The spock syntax was extended with the use of square brackets ``[]`` for +macros which define +:ref:`repeat parameters ` as arguments. +Repeat parameter values must be enclosed in square brackets. If the repeat +parameter is composed from more than one internal parameter its every +repetition must be enclosed in another square brackets as well. + +For example, the ``move_with_timeout`` macro:: + + class move_with_timeout(Macro): + """Execute move with a timeout""" + + param_def = [ + ['m_p_pair', + [['motor', Type.Motor, None, 'Motor to move'], + ['pos', Type.Float, None, 'Position to move to']], + None, 'List of motor/position pairs'], + ['timeout', Type.Float, None, 'Timeout value'] + ] + + def run(self, *args, **kwargs): + pass + +Must use the square brackets for the ``m_p_pair`` parameter and its +repeats: + +.. sourcecode:: spock + + Door_1 [1]: move_with_timeout [[th 8.4] [tth 16.8]] 50 + +However for the commodity reasons the square brackets may be skipped. The +following examples explain in which cases. + +Repeat parameter is the last one +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When the repeat parameter is the last one in the parameters definition +both square brackets (for the repeat parameter and for the repetition) may +be skipped. + +For example, the ``move`` macro:: + + class move(Macro): + """Execute move""" + + param_def = [ + ['m_p_pair', + [['motor', Type.Motor, None, 'Motor to move'], + ['pos', Type.Float, None, 'Position to move to']], + None, 'List of motor/position pairs'] + ] + + def run(self, *args, **kwargs): + pass + +May skip the square brackets for the ``m_p_pair`` parameter and its +repeats: + +.. sourcecode:: spock + + Door_1 [1]: move th 8.4 tth 16.8 + +This is equivalent to: + +.. sourcecode:: spock + + Door_1 [1]: move [[th 8.4] [tth 16.8]] + +Repeat parameter has only one internal parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When the repeat parameter contains only one internal parameter the square +brackets for the repetition **must** be skipped. + +For example, the ``power_motor`` macro:: + + class power_motor(Macro): + """Power on/off motor(s)""" + + param_def = [ + ['motor_list', [['motor', Type.Motor, None, 'motor name']], + None, 'List of motors'], + ['power_on', Type.Boolean, None, 'motor power state'] + ] + + def run(self, *args, **kwargs): + pass + +Must use the square brackets for the ``motor_list`` parameter but not for +its repeats: + +.. sourcecode:: spock + + Door_1 [1]: power_motor [th tth] True + +Repeat parameter has only one internal parameter and only one repetition value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When the repeat parameter contains only one internal parameter and you +would like to pass only one repetition value then the square brackets for +the repeat parameter may be skipped as well resulting in no square brackets +being used. + +This assumes the ``power_motor`` macro from the previous example. +The following two macro executions are equivalent: + +.. sourcecode:: spock + + Door_1 [1]: power_motor th True + Door_1 [2]: power_motor [th] True + +A set of macro examples defining complex repeat parameters can be found in +:ref:`sardana-devel-macro-parameter-examples`. You can see the invocation example for each of these macros in its docstring. From 9a6f0e03a2f4812f4419c43e5cf6e1f6f89a9eca Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 24 Oct 2018 15:25:03 +0200 Subject: [PATCH 239/652] Refactor configuration classes Refactor classes to use them with the synchronizer controllers and channels --- src/sardana/pool/poolmeasurementgroup.py | 53 +++++------------------- 1 file changed, 11 insertions(+), 42 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 6126237633..725ae36337 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -128,11 +128,6 @@ class ConfigurationItem(object): def __init__(self, element, conf=None): self._element = weakref.ref(element) - if conf is None: - conf = {'acq_synch': None} - else: - conf['acq_synch'] = None - if conf is not None: self.__dict__.update(conf) @@ -165,24 +160,6 @@ def __init__(self, element, conf=None): ConfigurationItem.__init__(self, element, conf) - def get_config(self): - config = {} - # the external controllers: Tango attributes does not have timer and - # monitor - config['timer'] = self.timer.full_name - config['monitor'] = self.monitor.full_name - - if isinstance(self.synchronizer, (str, unicode)): - synchronizer = self.synchronizer - else: - synchronizer = self.synchronizer.full_name - config['synchronizer'] = synchronizer - config['synchronization'] = self.synchronization - config['channels'] = {} - for ch_item in self._channels: - config['channels'][ch_item.full_name] = ch_item.get_config() - return config - def add_channel(self, channel_item): self._channels.append(channel_item) if channel_item.enabled: @@ -195,6 +172,17 @@ def add_channel(self, channel_item): self._channels_disabled = [] self._channels_disabled.append(channel_item) + def update_state(self): + self.enabled = False + self._channels_enabled = [] + self._channels_disabled = [] + for channel_item in self._channels: + if channel_item.enabled: + self.enabled = True + self._channels_enabled.append(channel_item) + else: + self._channels_disabled.append(channel_item) + def get_channels(self, enabled=None): if enabled is None: return list(self.channels) @@ -208,25 +196,6 @@ class ChannelConfiguration(ConfigurationItem): """Configuration: 'index', 'enabled', 'output', 'plot_type', 'plot_axes', 'label', 'scale', 'plot_color'""" - def get_config(self): - config = {} - config['index'] = self.index - config['name'] = self.name - config['full_name'] = self.full_name - config['source'] = self.source - config['enabled'] = self.enabled - config['label'] = self.label - config['ndim'] = self.ndim - config['output'] = self.output - config['plot_type'] = self.plot_type - config['plot_axes'] = self.plot_axes - config['conditioning'] = self.conditioning - config['normalization'] = self.normalization - config['data_type'] = self.data_type - config['data_units'] = self.data_units - config['nexus_path'] = self.nexus_path - config['shape'] = self.shape - return config class MeasurementConfiguration(object): From 2a19c6165c6ea3310e424f1cdc2758731659b86d Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 24 Oct 2018 15:25:26 +0200 Subject: [PATCH 240/652] Add SyncrhonizerConfiguration class --- src/sardana/pool/poolmeasurementgroup.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 725ae36337..5957778254 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -197,6 +197,13 @@ class ChannelConfiguration(ConfigurationItem): 'label', 'scale', 'plot_color'""" +class SynchronizerConfiguration(ConfigurationItem): + + def __init__(self, element, conf=None): + self.enabled = False + + ConfigurationItem.__init__(self, element, conf) + class MeasurementConfiguration(object): """ From e64ad8870193146f110b8378f659ae7d576cc024 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 24 Oct 2018 16:59:56 +0200 Subject: [PATCH 241/652] Add enabled attribute to ConfigurationItem Add enabled attribute to the ConfigurationItem class with True as default value. --- src/sardana/pool/poolmeasurementgroup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 5957778254..f334499773 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -127,6 +127,7 @@ def _to_fqdn(name, logger=None): class ConfigurationItem(object): def __init__(self, element, conf=None): self._element = weakref.ref(element) + self.enabled = True if conf is not None: self.__dict__.update(conf) @@ -153,12 +154,11 @@ class ControllerConfiguration(ConfigurationItem): """Configuration: 'timer', 'monitor', 'synchronization', 'channels'""" def __init__(self, element, conf=None): + ConfigurationItem.__init__(self, element, conf) + self.enabled = False self._channels = [] self._channels_enabled = [] self._channels_disabled = [] - self.enabled = False - - ConfigurationItem.__init__(self, element, conf) def add_channel(self, channel_item): self._channels.append(channel_item) @@ -200,9 +200,9 @@ class ChannelConfiguration(ConfigurationItem): class SynchronizerConfiguration(ConfigurationItem): def __init__(self, element, conf=None): + ConfigurationItem.__init__(self, element, conf) self.enabled = False - ConfigurationItem.__init__(self, element, conf) class MeasurementConfiguration(object): From cabf4c3ff5c90d128f549a6787d8128d85d2cb34 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 24 Oct 2018 17:02:29 +0200 Subject: [PATCH 242/652] Refactor MeasurementConfiguration class Refactor class to update the internals attribute at set the configuration. Add protections to validate the configuration set by the user. --- src/sardana/pool/poolmeasurementgroup.py | 713 +++++++++-------------- 1 file changed, 281 insertions(+), 432 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index f334499773..13e9075685 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -217,224 +217,329 @@ def __init__(self, parent=None): self._parent = None if parent is not None: self._parent = weakref.proxy(parent) + self._config = None self._use_fqdn = True - self._clean_variables() - - def _clean_variables(self): - # list of controller with channels enabled. - self.enabled_ctrls = [] - # list of timers and monitors by synchronization type. - self.sw_sync_timers_enabled = [] - self.sw_sync_monitors_enabled = [] - self.sw_start_timers_enabled = [] - self.sw_start_monitors_enabled = [] - self.hw_sync_timers_enabled = [] - self.hw_sync_monitors_enabled = [] - # dict with channel and its acquisition synchronization - # key: PoolBaseChannel; value: AcqSynch - self.channel_to_acq_synch = {} - # dict with controller and its acquisition synchronization - # key: PoolController; value: AcqSynch - self.ctrl_to_acq_synch = {} - # TODO: Do the documentation - self.ctrl_sw_sync = {} - self.ctrl_hw_sync = {} - self.ctrl_sw_start = {} - self.ctrl_0d_sync = {} - self.ctrl_tg_sync = {} - # TODO: Do the documentation - self.sw_sync_timer = None - self.sw_sync_monitor = None - self.sw_start_timer = None - self.sw_start_monitor = None - self.hw_sync_timer = None - self.hw_sync_monitor = None - - def __check_config(func): - def wrapper(self, *args, **kwargs): - if self._config is None: - raise RuntimeError('The configuration is empty.') - return func(self, *args, **kwargs) - return wrapper - - def __getitem__(self, item): - return self._config.__getitem__(item) - @property - @__check_config - def configuration(self): - return self._config + # Structure to store the controllers and their channels + self._timerable_ctrls = {} + self._zerod_ctrls = [] + self._synch_ctrls = {} + self._other_ctrls = [] + self._master_timer_sw = None + self._master_monitor_sw = None + self._master_timer_sw_start = None + self._master_monitor_sw_start = None + self._label = None + self._description = None + self._master_timer = None + self._master_monitor = None + self._user_confg = {} + self._element_acq_synch = {} + + def get_acq_synch_by_element(self, element): + return self._element_acq_synch[element.id] + + def _filter_ctrls(self, ctrls, enabled): + if enabled is None: + return ctrls + + filtered_ctrls = [] + for ctrl in ctrls: + if ctrl.enabled == enabled: + filtered_ctrls.append(ctrl) + return filtered_ctrls + + def get_timerable_ctrls(self, acq_synch=None, enabled=None): + timerable_ctrls = [] + if acq_synch is None: + for ctrls in self._timerable_ctrls.values(): + timerable_ctrls += ctrls + elif isinstance(acq_synch, list): + acq_synch_list = acq_synch + for acq_synch in acq_synch_list: + timerable_ctrls += self._timerable_ctrls[acq_synch] + else: + timerable_ctrls = list(self._timerable_ctrls[acq_synch]) + + return self._filter_ctrls(timerable_ctrls, enabled) + + def get_zerod_ctrls(self, enabled=None): + return self._filter_ctrls(self._zerod_ctrls, enabled) - @configuration.setter - def configuration(self, config=None): - self._build_configuration(config) + def get_synch_ctrls(self, enabled=None): + return self._filter_ctrls(self._synch_ctrls, enabled) + + def get_master_timer_software(self): + return self._master_timer_sw + + def get_master_monitor_software(self): + return self._master_monitor_sw + + def get_master_timer_software_start(self): + return self._master_monitor_sw_start + + def get_master_monitor_software_start(self): + return self._master_timer_sw_start + + def get_configuration_for_user(self): + return self._user_confg def set_configuration_from_user(self, cfg, to_fqdn=True): - config = {} user_elements = self._parent.get_user_elements() - pool = self._parent.pool if len(user_elements) == 0: - # All timers were disabled - default_timer = None - else: - default_timer = user_elements[0].full_name - - timer_name = cfg.get('timer', default_timer) - monitor_name = cfg.get('monitor', default_timer) - if to_fqdn: - timer_name = _to_fqdn(timer_name, logger=self._parent) - config['timer'] = pool.get_element_by_full_name(timer_name) - if to_fqdn: - monitor_name = _to_fqdn(monitor_name, logger=self._parent) - config['monitor'] = pool.get_element_by_full_name(monitor_name) - config['controllers'] = controllers = {} - - for c_name, c_data in cfg['controllers'].items(): + # All channels were disabled + raise ValueError('The configuration has all the channels disabled') + + pool = self._parent.pool + + label = cfg.get('label', self._parent.name) + description = cfg.get('description', self.DFT_DESC) + + timerable_ctrls = {AcqSynch.HardwareGate: [], + AcqSynch.HardwareStart: [], + AcqSynch.HardwareTrigger: [], + AcqSynch.SoftwareStart: [], + AcqSynch.SoftwareTrigger: [], + AcqSynch.SoftwareGate: []} + zerod_ctrls = [] + synch_ctrls = [] + other_ctrls = [] + master_timer_sw = None + master_monitor_sw = None + master_timer_sw_start = None + master_monitor_sw_start = None + master_timer = None + master_monitor = None + element_acq_synch = {} + master_timer_idx_sw = float("+inf") + master_monitor_idx_sw = float("+inf") + user_elem_ids = {} + user_config = {} + + # Update the configuration for user + user_config['controllers'] = {} + user_config = {} + if 'timer' in cfg: + user_config['timer'] = cfg['timer'] + if 'monitor' in cfg: + user_config['monitor'] = cfg['monitor'] + user_config['controllers'] = {} + user_config['label'] = label + user_config['description'] = description + + for ctrl_name, ctrl_data in cfg['controllers'].items(): # backwards compatibility for measurement groups created before # implementing feature-372: # https://sourceforge.net/p/sardana/tickets/372/ # WARNING: this is one direction backwards compatibility - it just # reads channels from the units, but does not write channels to the # units back - if 'units' in c_data: - c_data = c_data['units']['0'] + if 'units' in ctrl_data: + ctrl_data = ctrl_data['units']['0'] # discard controllers which don't have items (garbage) - ch_count = len(c_data['channels']) + ch_count = len(ctrl_data['channels']) if ch_count == 0: continue - external = c_name.startswith('__') + external = ctrl_name.startswith('__') if external: - ctrl = c_name + ctrl = ctrl_name else: if to_fqdn: - c_name = _to_fqdn(c_name, logger=self._parent) - ctrl = pool.get_element_by_full_name(c_name) + ctrl_name = _to_fqdn(ctrl_name, logger=self._parent) + ctrl = pool.get_element_by_full_name(ctrl_name) assert ctrl.get_type() == ElementType.Controller - controllers[ctrl] = ctrl_data = {} - # exclude external and not timerable elements - if not external and ctrl.is_timerable(): - timer_name = c_data['timer'] - if to_fqdn: - timer_name = _to_fqdn(timer_name, logger=self._parent) - timer = pool.get_element_by_full_name(timer_name) - ctrl_data['timer'] = timer - monitor_name = c_data['monitor'] + user_config['controllers'][ctrl_name] = user_config_ctrl = {} + ctrl_conf = {} + + synchronizer = ctrl_data.get('synchronizer', None) + conf_synch = None + if synchronizer is None or synchronizer == 'software': + ctrl_conf['synchronizer'] = 'software' + user_config_ctrl['synchronizer'] = 'software' + else: if to_fqdn: - monitor_name = _to_fqdn(monitor_name, logger=self._parent) - monitor = pool.get_element_by_full_name(monitor_name) - ctrl_data['monitor'] = monitor - synchronizer = c_data.get('synchronizer') - # for backwards compatibility purposes - # protect measurement groups without synchronizer defined - if synchronizer is None: - synchronizer = 'software' - elif synchronizer != 'software': - if to_fqdn: - synchronizer = _to_fqdn(synchronizer, - logger=self._parent) - synchronizer = pool.get_element_by_full_name(synchronizer) - ctrl_data['synchronizer'] = synchronizer + synchronizer = _to_fqdn(synchronizer, + logger=self._parent) + + user_config_ctrl['synchronizer'] = synchronizer + pool_synch = pool.get_element_by_full_name(synchronizer) + pool_synch_ctrl = pool_synch.controller + conf_synch = SynchronizerConfiguration(pool_synch) + conf_synch_ctrl = None + if len(synch_ctrls) > 0: + conf_synch_ctrl = None + for conf_ctrl in synch_ctrls: + if pool_synch_ctrl == conf_ctrl.element: + conf_synch_ctrl = conf_ctrl + if conf_synch_ctrl is None: + conf_synch_ctrl = ControllerConfiguration(pool_synch_ctrl) + conf_synch_ctrl.add_channel(conf_synch) + synch_ctrls.append(conf_synch_ctrl) + ctrl_conf['synchronizer'] = conf_synch + + try: + synchronization = ctrl_data['synchronization'] + except KeyError: + # backwards compatibility for configurations before SEP6 try: - synchronization = c_data['synchronization'] - except KeyError: - # backwards compatibility for configurations before SEP6 - synchronization = c_data['trigger_type'] + synchronization = ctrl_data['trigger_type'] msg = ("trigger_type configuration parameter is deprecated" " in favor of synchronization. Re-apply " "configuration in order to upgrade.") self._parent.warning(msg) - ctrl_data['synchronization'] = synchronization - ctrl_data['channels'] = channels = {} - for ch_name, ch_data in c_data['channels'].items(): + except KeyError: + synchronization = None + + ctrl_conf['synchronization'] = synchronization + user_config_ctrl['synchronization'] = synchronization + ctrl_conf['timer'] = None + ctrl_conf['monitor'] = None + ctrl_item = ControllerConfiguration(ctrl, ctrl_conf) + + acq_synch = None + if not external and ctrl.is_timerable(): + is_software = synchronizer == 'software' + acq_synch = AcqSynch.from_synch_type(is_software, + synchronization) + element_acq_synch[ctrl.id] = acq_synch + + ctrl_enabled = False + if 'channels' in ctrl_data: + user_config_ctrl['channels'] = user_config_channel = {} + for ch_name, ch_data in ctrl_data['channels'].items(): + if external: validator = TangoAttributeNameValidator() params = validator.getParams(ch_data['full_name']) - params['pool'] = self._parent.pool + params['pool'] = pool channel = PoolExternalObject(**params) else: if to_fqdn: ch_name = _to_fqdn(ch_name, logger=self._parent) channel = pool.get_element_by_full_name(ch_name) - channels[channel] = dict(ch_data) - config['label'] = cfg.get('label', self._parent.name) - config['description'] = cfg.get('description', self.DFT_DESC) - self._use_fqdn = to_fqdn - self._build_configuration(config) + ch_data = self._fill_channel_data(channel, ch_data) + user_config_channel[ch_name] = ch_data + ch_item = ChannelConfiguration(channel, ch_data) + ch_item.controller = ctrl_item + ctrl_item.add_channel(ch_item) + if ch_item.enabled: + user_elem_ids[ch_item.index] = channel.id - def get_configuration_for_user(self): - cfg = self._config - config = {} + # Update controller timer + if ch_name == ctrl_data['timer']: + ctrl_item.timer = ch_item - config['timer'] = cfg['timer'].full_name - config['monitor'] = cfg['monitor'].full_name - config['controllers'] = controllers = {} + # Update controller monitor + if ch_name == ctrl_data['monitor']: + ctrl_item.monitor = ch_item - for c, c_data in cfg['controllers'].items(): - ctrl_name = c - if not isinstance(c, (str, unicode)): - ctrl_name = c.full_name - external = ctrl_name.startswith('__') - controllers[ctrl_name] = ctrl_data = {} - if not external and c.is_timerable(): - if 'timer' in c_data: - ctrl_data['timer'] = c_data['timer'].full_name - if 'monitor' in c_data: - ctrl_data['monitor'] = c_data['monitor'].full_name - if 'synchronizer' in c_data: - synchronizer = c_data['synchronizer'] - if synchronizer != 'software': - synchronizer = synchronizer.full_name - ctrl_data['synchronizer'] = synchronizer - if 'synchronization' in c_data: - ctrl_data['synchronization'] = c_data['synchronization'] - ctrl_data['channels'] = channels = {} - for ch, ch_data in c_data['channels'].items(): - channels[ch.full_name] = dict(ch_data) - - config['label'] = cfg['label'] - config['description'] = cfg['description'] - return config - - def _build_channel_defaults(self, channel_data, channel): + # Update measurement configuration master timer + if ch_name == cfg.get('timer', None): + master_timer = ch_item + + # Update measurement configuration master timer + if ch_name == cfg.get('monitor', None): + master_monitor = ch_item + + if ch_item.enabled: + ctrl_enabled = True + + if acq_synch is not None: + element_acq_synch[channel.id] = acq_synch + + # Update syncrhonizer state + if conf_synch is not None: + conf_synch.enabled = ctrl_enabled + + # validate if the timer and monitor are disabled if the + # controller is enabled + if ctrl_enabled and not ctrl_item.timer.enabled and \ + not ctrl_item.monitor.enabled: + timer_label = ctrl_item.timer.label + monitor_label = ctrl_item.monitor.label + + err_msg = 'The channel {0} used as timer and the channel ' \ + '{1} used as monitor are disabled. One of them ' \ + 'must be enabled'.format(timer_label, monitor_label) + raise ValueError(err_msg) + + if not external and ctrl.is_timerable(): + timerable_ctrls[acq_synch].append(ctrl_item) + # Find master timer/monitor the system take the channel with + # less index + if ctrl_item.synchronizer == 'software': + if ctrl_item.timer.index < master_timer_idx_sw: + master_timer_sw = ctrl_item.timer + master_timer_idx_sw = ctrl_item.timer.index + if ctrl_item.monitor.index < master_monitor_idx_sw: + master_monitor_sw = ctrl_item.monitor + master_monitor_idx_sw = ctrl_item.monitor.index + elif ctrl.get_ctrl_types()[0] == ElementType.ZeroDExpChannel: + zerod_ctrls.append(ctrl_item) + else: + other_ctrls.append(ctrl_item) + + # Update synchronizer controller states + for conf_synch_ctrl in synch_ctrls: + conf_synch_ctrl.update_state() + + + # Update internals values + self._master_monitor = master_monitor + self._master_timer = master_timer + self._label = label + self._description = description + self._timerable_ctrls = timerable_ctrls + self._zerod_ctrls = zerod_ctrls + self._synch_ctrls = synch_ctrls + self._other_ctrls = other_ctrls + self._master_timer_sw = master_timer_sw + self._master_monitor_sw = master_monitor_sw + self._element_acq_synch = element_acq_synch + self._user_confg = user_config + + # sorted ids may not be consecutive (if a channel is disabled) + indexes = sorted(user_elem_ids.keys()) + user_elem_ids_list = [user_elem_ids[idx] for idx in indexes] + for conf_synch_ctrl in synch_ctrls: + for conf_synch in conf_synch_ctrl.get_channels(enabled=True): + user_elem_ids_list.append(conf_synch.id) + self._parent.set_user_element_ids(user_elem_ids_list) + + def _fill_channel_data(self, channel, channel_data): """ Fills the channel default values for the given channel dictionary """ - external_from_name = isinstance(channel, (str, unicode)) + name = channel.name + full_name = channel.full_name + source = channel.get_source() ndim = None - if external_from_name: - name = full_name = source = channel - ndim = 0 # TODO: this should somehow verify the dimension - else: - name = channel.name - full_name = channel.full_name - source = channel.get_source() - ndim = None - ctype = channel.get_type() - if ctype == ElementType.CTExpChannel: - ndim = 0 - elif ctype == ElementType.PseudoCounter: - ndim = 0 - elif ctype == ElementType.ZeroDExpChannel: - ndim = 0 - elif ctype == ElementType.OneDExpChannel: - ndim = 1 - elif ctype == ElementType.TwoDExpChannel: - ndim = 2 - elif ctype == ElementType.External: - config = channel.get_config() - if config is not None: - ndim = int(config.data_format) - elif ctype == ElementType.IORegister: - ndim = 0 + ctype = channel.get_type() + if ctype == ElementType.CTExpChannel: + ndim = 0 + elif ctype == ElementType.PseudoCounter: + ndim = 0 + elif ctype == ElementType.ZeroDExpChannel: + ndim = 0 + elif ctype == ElementType.OneDExpChannel: + ndim = 1 + elif ctype == ElementType.TwoDExpChannel: + ndim = 2 + elif ctype == ElementType.External: + config = channel.get_config() + if config is not None: + ndim = int(config.data_format) + elif ctype == ElementType.IORegister: + ndim = 0 # Definitively should be initialized by measurement group # index MUST be here already (asserting this in the following line) - channel_data['index'] = channel_data['index'] + channel_data['index'] = channel_data.get('index', None) channel_data['name'] = channel_data.get('name', name) channel_data['full_name'] = channel_data.get('full_name', full_name) channel_data['source'] = channel_data.get('source', source) @@ -448,272 +553,16 @@ def _build_channel_defaults(self, channel_data, channel): channel_data['plot_type'] = channel_data.get('plot_type', PlotType.No) channel_data['plot_axes'] = channel_data.get('plot_axes', []) channel_data['conditioning'] = channel_data.get('conditioning', '') - channel_data['normalization'] = channel_data.get( - 'normalization', Normalization.No) + channel_data['normalization'] = channel_data.get('normalization', + Normalization.No) + # TODO use real values + channel_data['data_type'] = channel_data.get('data_type', None) + channel_data['data_units'] = channel_data.get('data_units', None) + channel_data['nexus_path'] = channel_data.get('nexus_path', '') + channel_data['shape'] = channel_data.get('shape', []) return channel_data - def _build_configuration(self, config=None): - """Builds a configuration object from the list of elements""" - self._clean_variables() - - if config is None: - config = {} - user_elements = self._parent.get_user_elements() - ctrls = self._parent.get_pool_controllers() - - # find the first CT - first_timerable = None - for elem in user_elements: - if elem.get_type() in TYPE_TIMERABLE_ELEMENTS: - first_timerable = elem - break - if first_timerable is None: - raise Exception("It is not possible to construct a " - "measurement group without at least one " - "timer able channel (Counter/timer, 1D or 2D)") - g_timer = g_monitor = first_timerable - config['timer'] = g_timer - config['monitor'] = g_monitor - config['controllers'] = controllers = {} - - external_user_elements = [] - for index, element in enumerate(user_elements): - elem_type = element.get_type() - if elem_type == ElementType.External: - external_user_elements.append((index, element)) - continue - - ctrl = element.controller - ctrl_data = controllers.get(ctrl) - # include all controller in the enabled list - self.enabled_ctrls.append(ctrl) - if ctrl_data is None: - controllers[ctrl] = ctrl_data = {} - ctrl_data['channels'] = channels = {} - if elem_type in TYPE_TIMERABLE_ELEMENTS: - elements = ctrls[ctrl] - if g_timer in elements: - ctrl_data['timer'] = g_timer - else: - ctrl_data['timer'] = elements[0] - if g_monitor in elements: - ctrl_data['monitor'] = g_monitor - else: - ctrl_data['monitor'] = elements[0] - ctrl_data['synchronization'] = AcqSynchType.Trigger - ctrl_data['synchronizer'] = 'software' - self.ctrl_to_acq_synch[ctrl] = AcqSynch.SoftwareTrigger - self.channel_to_acq_synch[ - element] = AcqSynch.SoftwareTrigger - else: - channels = ctrl_data['channels'] - channels[element] = channel_data = {} - channel_data['index'] = user_elements.index(element) - channel_data = self._build_channel_defaults(channel_data, - element) - - config['label'] = self._parent.name - config['description'] = self.DFT_DESC - - if len(external_user_elements) > 0: - controllers['__tango__'] = ctrl_data = {} - ctrl_data['channels'] = channels = {} - for index, element in external_user_elements: - channels[element] = channel_data = {} - channel_data['index'] = index - channel_data = self._build_channel_defaults(channel_data, - element) - else: - # create a configuration based on a new configuration - user_elem_ids = {} - tg_elem_ids = [] - pool = self._parent.pool - for c, c_data in config['controllers'].items(): - synchronizer = c_data.get('synchronizer') - acq_synch_type = c_data.get('synchronization') - software = synchronizer == 'software' - external = isinstance(c, (str, unicode)) - # only timerable elements are configured with acq_synch - acq_synch = None - ctrl_enabled = False - ctrl_to_acq_synch = False - if not external and c.is_timerable(): - acq_synch = AcqSynch.from_synch_type( - software, acq_synch_type) - for channel_data in c_data['channels'].values(): - if external: - element = _id = channel_data['full_name'] - channel_data['source'] = _id - else: - full_name = channel_data['full_name'] - if self._use_fqdn: - full_name = _to_fqdn(full_name, - logger=self._parent) - element = pool.get_element_by_full_name(full_name) - _id = element.id - channel_data = self._build_channel_defaults( - channel_data, element) - if channel_data["enabled"]: - ctrl_enabled = True - if acq_synch is not None: - ctrl_to_acq_synch = True - self.channel_to_acq_synch[element] = acq_synch - if not software: - tg_elem_ids.append(synchronizer.id) - user_elem_ids[channel_data['index']] = _id - - if ctrl_to_acq_synch: - self.ctrl_to_acq_synch[c] = acq_synch - if ctrl_enabled: - self.enabled_ctrls.append(c) - - # sorted ids may not be consecutive (if a channel is disabled) - indexes = sorted(user_elem_ids.keys()) - user_elem_ids_list = [user_elem_ids[idx] for idx in indexes] - user_elem_ids_list.extend(tg_elem_ids) - self._parent.set_user_element_ids(user_elem_ids_list) - - g_timer, g_monitor = config['timer'], config['monitor'] - - timer_ctrl_data = config['controllers'][g_timer.controller] - if timer_ctrl_data['timer'] != g_timer: - self._parent.warning('controller timer and global timer ' - 'mismatch. Using global timer') - self._parent.debug('For controller %s, timer is defined as ' - 'channel %s. The global timer is set to ' - 'channel %s which belongs to the same ' - 'controller', g_timer.controller.name, - timer_ctrl_data['timer'].name, g_timer.name) - timer_ctrl_data['timer'] = g_timer - - monitor_ctrl_data = config['controllers'][g_monitor.controller] - if monitor_ctrl_data['monitor'] != g_monitor: - self._parent.warning('controller monitor and global ' - 'monitor mismatch. Using global monitor') - self._parent.debug('For controller %s, monitor is defined as ' - 'channel %s. The global timer is set to ' - 'channel %s which belongs to the same ' - 'controller', g_monitor.controller.name, - monitor_ctrl_data['monitor'].name, - g_monitor.name) - - self._config = config - self._split_sync() - self._split_tg() - - def _split_sync(self): - """ - Split MeasurementGroup configuration with channels - triggered by SW Trigger and channels triggered by HW trigger - - """ - - ctrls_in = self._config['controllers'] - for ctrl, ctrl_info in ctrls_in.items(): - external = isinstance(ctrl, str) and ctrl.startswith('__') - # skipping external controllers e.g. Tango attributes - if external: - continue - # splitting ZeroD based on the type - if ctrl.get_ctrl_types()[0] == ElementType.ZeroDExpChannel: - self.ctrl_0d_sync[ctrl] = ctrl_info - # ignoring PseudoCounter - elif ctrl.get_ctrl_types()[0] == ElementType.PseudoCounter: - pass - # splitting rest of the channels based on the assigned trigger - else: - synchronizer = ctrl_info.get('synchronizer') - if synchronizer is None or synchronizer == 'software': - synchronization = ctrl_info.get('synchronization') - if synchronization in [AcqSynch.SoftwareTrigger, - AcqSynch.SoftwareGate]: - self.ctrl_sw_sync[ctrl] = ctrl_info - else: - self.ctrl_sw_start[ctrl] = ctrl_info - else: - self.ctrl_hw_sync[ctrl] = ctrl_info - - def get_master_enables(ctrls, role): - master_idx = float("+inf") - master = None - elements = [] - for ctrl_info in ctrls.values(): - element = ctrl_info[role] - if element in ctrl_info["channels"]: - element_idx = ctrl_info["channels"][element]["index"] - element_enabled = ctrl_info["channels"][element]["enabled"] - # Find master only if is enabled - if element_enabled: - elements.append(element) - if element_idx < master_idx: - master = element - master_idx = element_idx - return master, elements - - if len(self.ctrl_sw_sync): - timer, timers = get_master_enables(self.ctrl_sw_sync, "timer") - self.sw_sync_timer = timer - self.sw_sync_timers_enabled = timers - - monitor, monitors = get_master_enables(self.ctrl_sw_sync, - "monitor") - self.sw_sync_monitor = monitor - self.sw_sync_monitors_enabled = monitors - - if len(self.ctrl_sw_start): - timer, timers = get_master_enables(self.ctrl_sw_start, "timer") - self.sw_start_timer = timer - self.sw_start_timers_enabled = timers - - monitor, monitors = get_master_enables(self.ctrl_sw_start, - "monitor") - self.sw_start_monitor = monitor - self.sw_start_monitors_enabled = monitors - - if len(self.ctrl_hw_sync): - timer, timers = get_master_enables(self.ctrl_hw_sync, "timer") - self.hw_sync_timer = timer - self.hw_sync_timers_enabled = timers - - monitor, monitors = get_master_enables(self.ctrl_hw_sync, - "monitor") - self.hw_sync_monitor = monitor - self.hw_sync_monitors_enabled = monitors - - def _split_tg(self): - """ - Build TG configuration from complete configuration. - """ - - # Create list with not repeated elements - _tg_element_list = [] - - for ctrl in self._config["controllers"]: - tg_element = self._config["controllers"][ctrl].get('synchronizer', - None) - if (tg_element is not None and - tg_element != "software" and - tg_element not in _tg_element_list): - _tg_element_list.append(tg_element) - - # Intermediate dictionary to organize each ctrl with its elements. - ctrl_tgelem_dict = {} - for tgelem in _tg_element_list: - tg_ctrl = tgelem.get_controller() - if tg_ctrl not in ctrl_tgelem_dict.keys(): - ctrl_tgelem_dict[tg_ctrl] = [tgelem] - else: - ctrl_tgelem_dict[tg_ctrl].append(tgelem) - - # Build TG configuration dictionary. - for ctrl in ctrl_tgelem_dict: - self.ctrl_tg_sync[ctrl] = ctrls = {} - ctrls['channels'] = {} - for tg_elem in ctrl_tgelem_dict[ctrl]: - ch = ctrls['channels'][tg_elem] = {} - ch['full_name'] = tg_elem.full_name - class PoolMeasurementGroup(PoolGroupElement): From f398116d445e64c114e883294a57302d8dd36518 Mon Sep 17 00:00:00 2001 From: flyingbot91 Date: Wed, 24 Oct 2018 21:43:06 +0200 Subject: [PATCH 243/652] Bugfix: If len(sys.argv) > 1 second conditional is never executed --- sardanaConfig/src/wizards/pool_page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sardanaConfig/src/wizards/pool_page.py b/sardanaConfig/src/wizards/pool_page.py index d77ebd3936..4bffa6ede2 100644 --- a/sardanaConfig/src/wizards/pool_page.py +++ b/sardanaConfig/src/wizards/pool_page.py @@ -149,7 +149,7 @@ def nextId(self): def main(): tg_host, sardana = None, None - if len(sys.argv) > 1: + if len(sys.argv) == 2: tg_host = sys.argv[1] if len(sys.argv) > 2: sardana = sys.argv[2] From 8b616b8eb2767d2181b7b8d8b1872d94b2155ea6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 25 Oct 2018 00:27:18 +0200 Subject: [PATCH 244/652] (minor) Return None when device not found in get_device_from_user --- src/sardana/spock/ipython_01_00/genutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/spock/ipython_01_00/genutils.py b/src/sardana/spock/ipython_01_00/genutils.py index 181d725da5..93a7d8e348 100644 --- a/src/sardana/spock/ipython_01_00/genutils.py +++ b/src/sardana/spock/ipython_01_00/genutils.py @@ -319,7 +319,7 @@ def get_device_from_user(expected_class, dft=None): prompt += "? " from_user = raw_input(prompt).strip() or dft - name = '' + name = None try: full_name, name, _ = from_name_to_tango(from_user) except: From 2de6189721988a0da7c21452fb4e3c20ebcef896 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 25 Oct 2018 00:30:09 +0200 Subject: [PATCH 245/652] Do cleanup when spock profile was not correctly created Spock profile may not be correctly created, for example when no valid door was selected. In this case remove the profile directory previously prepare for the profile file. --- src/sardana/spock/ipython_01_00/genutils.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sardana/spock/ipython_01_00/genutils.py b/src/sardana/spock/ipython_01_00/genutils.py index 93a7d8e348..c486168148 100644 --- a/src/sardana/spock/ipython_01_00/genutils.py +++ b/src/sardana/spock/ipython_01_00/genutils.py @@ -753,6 +753,8 @@ def _create_config_file(location, door_name=None): else: full_door_name, door_name, _ = from_name_to_tango(door_name) door_name = full_door_name + if door_name is None: + raise RuntimeError('unknown door name') # # Discover macro server name @@ -786,7 +788,17 @@ def create_spock_profile(userdir, profile, door_name=None): ipy_profile_dir = p_dir.location - _create_config_file(ipy_profile_dir) + try: + _create_config_file(ipy_profile_dir) + except Exception: + import shutil + try: + shutil.rmtree(ipy_profile_dir) + except OSError: + msg = ('Could not remove spock profile directory {0}. ' + 'Remove it by hand e.g. rmdir {0}').format(ipy_profile_dir) + print(msg) + sys.exit(-1) def upgrade_spock_profile(ipy_profile_dir, door_name): From 464fd8efdce43bfc9c0d76067393e03f4f54702d Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 25 Oct 2018 09:37:14 +0200 Subject: [PATCH 246/652] Change acq_synch lookup table Use two lookup table one for channel and another for controller. Use as key the element instead of the id. --- src/sardana/pool/poolmeasurementgroup.py | 25 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 13e9075685..a2b41b63f0 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -204,7 +204,6 @@ def __init__(self, element, conf=None): self.enabled = False - class MeasurementConfiguration(object): """ .. todo: Reject configuration with errors: @@ -235,10 +234,18 @@ def __init__(self, parent=None): self._master_timer = None self._master_monitor = None self._user_confg = {} - self._element_acq_synch = {} + self._channel_acq_synch = {} + self._ctrl_acq_synch = {} + + def get_acq_synch_by_channel(self, element): + if isinstance(element, ConfigurationItem): + element = element.element + return self._channel_acq_synch[element] - def get_acq_synch_by_element(self, element): - return self._element_acq_synch[element.id] + def get_acq_synch_by_controller(self, element): + if isinstance(element, ConfigurationItem): + element = element.element + return self._ctrl_acq_synch[element] def _filter_ctrls(self, ctrls, enabled): if enabled is None: @@ -315,6 +322,8 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): master_timer_idx_sw = float("+inf") master_monitor_idx_sw = float("+inf") user_elem_ids = {} + channel_acq_synch = {} + ctrl_acq_synch = {} user_config = {} # Update the configuration for user @@ -404,7 +413,7 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): is_software = synchronizer == 'software' acq_synch = AcqSynch.from_synch_type(is_software, synchronization) - element_acq_synch[ctrl.id] = acq_synch + ctrl_acq_synch[ctrl] = acq_synch ctrl_enabled = False if 'channels' in ctrl_data: @@ -449,7 +458,7 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): ctrl_enabled = True if acq_synch is not None: - element_acq_synch[channel.id] = acq_synch + channel_acq_synch[channel] = acq_synch # Update syncrhonizer state if conf_synch is not None: @@ -487,7 +496,6 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): for conf_synch_ctrl in synch_ctrls: conf_synch_ctrl.update_state() - # Update internals values self._master_monitor = master_monitor self._master_timer = master_timer @@ -499,8 +507,9 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): self._other_ctrls = other_ctrls self._master_timer_sw = master_timer_sw self._master_monitor_sw = master_monitor_sw - self._element_acq_synch = element_acq_synch self._user_confg = user_config + self._channel_acq_synch = channel_acq_synch + self._ctrl_acq_synch = ctrl_acq_synch # sorted ids may not be consecutive (if a channel is disabled) indexes = sorted(user_elem_ids.keys()) From b94ff8c1e5d9f352a8c3801719bd0cdd8f0b711f Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 25 Oct 2018 09:42:20 +0200 Subject: [PATCH 247/652] Adapt classes to use new MeasurementConfiguration API --- src/sardana/pool/poolacquisition.py | 173 +++++++++++++---------- src/sardana/pool/poolmeasurementgroup.py | 107 ++++++++------ src/sardana/pool/poolsynchronization.py | 72 +++++----- 3 files changed, 202 insertions(+), 150 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index a7ff6c17ab..3668ee3711 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -147,17 +147,15 @@ def event_received(self, *args, **kwargs): self.debug('Stopping ZeroD acquisition.') self._0d_acq.stop_action() - def prepare(self, config, nr_of_starts): + def prepare(self, ctrl_lodeable, nr_of_starts): """Prepare measurement.""" - timers = config.sw_sync_timers_enabled + \ - config.sw_start_timers_enabled + \ - config.hw_sync_timers_enabled - for timer in timers: - axis = timer.axis - timer_ctrl = timer.controller - ctrl = timer_ctrl.ctrl - ctrl.PrepareOne(axis, nr_of_starts) + for ctrl, lodeable in ctrl_lodeable.items(): + axis = lodeable.axis + try: + ctrl.PrepareOne(axis, nr_of_starts) + except Exception: + pass def is_running(self): return self._0d_acq.is_running() or\ @@ -181,38 +179,61 @@ def run(self, *args, **kwargs): for pseudo_elem in elem.get_pseudo_elements(): pseudo_elem.clear_value_buffer() - config = self.main_element.configuration - synchronization = kwargs["synchronization"] - integ_time = synchronization.integration_time + if acq_mode is AcqMode.Timer: + value = synchronization.integration_time repetitions = synchronization.repetitions latency_time = 0 - ctrls_channels_acq_hw = config.get_ctrls_channels() + # starting continuous acquisition only if there are any controllers - if len(config.ctrl_hw_sync): - cont_acq_kwargs = dict(kwargs) - cont_acq_kwargs['integ_time'] = integ_time - cont_acq_kwargs['repetitions'] = repetitions - self._hw_acq.run(*args, **cont_acq_kwargs) - if len(config.ctrl_sw_sync) or len(config.ctrl_0d_sync): + acq_sync_hw = [AcqSynch.HardwareTrigger, AcqSynch.HardwareStart, + AcqSynch.HardwareGate] + ctrls_acq_hw = config.get_timerable_ctrls(acq_synch=acq_sync_hw, + enabled=True) + + + if len(ctrls_acq_hw): + self._hw_acq.run(conf_ctrls=ctrls_acq_hw, + value=value, + repetitions=repetitions, + latency_time=latency_time) + + # starting software acquisition only if there are any controller + acq_sync_sw = [AcqSynch.SoftwareGate, AcqSynch.SoftwareTrigger] + ctrls_acq_sw = config.get_timerable_ctrls(acq_synch=acq_sync_sw, + enabled=True) + ctrls_acq_0d = config.get_zerod_ctrls(enabled=True) + + if len(ctrls_acq_sw) or len(ctrls_acq_0d): self._synch.add_listener(self) - if len(config.ctrl_sw_sync): - sw_acq_kwargs = dict(kwargs) - sw_acq_kwargs['integ_time'] = integ_time - sw_acq_kwargs['repetitions'] = 1 + if len(ctrls_acq_sw): + master = None + if acq_mode is AcqMode.Timer: + master = config.get_master_timer_software() + elif acq_mode is AcqMode.Monitor: + master = config.get_master_monitor_software() + + sw_acq_kwargs = dict(conf_ctrls=ctrls_acq_sw, + value=value, + repetitions=1, + latency_time=latency_time, + master=master) self.set_sw_config(sw_acq_kwargs) - if len(config.ctrl_0d_sync): - zerod_acq_kwargs = dict(kwargs) + if len(ctrls_acq_0d): + zerod_acq_kwargs = dict(conf_ctrls=ctrls_acq_0d, value=value) self.set_0d_config(zerod_acq_kwargs) - synch_kwargs = dict(kwargs) - self._synch.run(*args, **synch_kwargs) + + #start the synchonization action + ctrls_synch = config.get_synch_ctrls(enabled=True) + self._synch.run(conf_ctrls=ctrls_synch, + synchronization=synchronization, + moveable=moveable, + sw_synch_initial_domain=sw_synch_initial_domain) def _get_action_for_element(self, element): elem_type = element.get_type() if elem_type in TYPE_TIMERABLE_ELEMENTS: - main_element = self.main_element - channel_to_acq_synch = \ - main_element.configuration.channel_to_acq_synch - acq_synch = channel_to_acq_synch.get(element) + config = self.main_element.configuration + acq_synch = config.get_acq_synch_by_channel(element) if acq_synch in (AcqSynch.SoftwareTrigger, AcqSynch.SoftwareGate): return self._sw_acq @@ -401,22 +422,18 @@ def start_action(self, pool_ctrls, value, repetitions=1, latency=0, # make sure the controller which has the master channel is the last to # be called if master is not None: - master_ctrl = master.controller - pool_ctrls.remove(master_ctrl) - pool_ctrls.append(master_ctrl) + conf_ctrls.remove(master.controller) + conf_ctrls.append(master.controller) - # controllers that will be read at the end of the action - ctrl_channels = {} - for pool_ctrl in pool_ctrls: - ctrl_channels[pool_ctrl] = pool_ctrl.channels - self._pool_ctrl_dict_loop = ctrl_channels + # controllers that will be read at during the action + self._set_pool_ctrl_dict_loop(conf_ctrls) # channels that are acquired (only enabled) self._channels = [] - def load(channel, value, repetitions, latency=0): - axis = channel.axis - pool_ctrl = channel.controller + def load(conf_channel, value, repetitions, latency=0): + axis = conf_channel.axis + pool_ctrl = conf_channel.controller ctrl = pool_ctrl.ctrl ctrl.PreLoadAll() try: @@ -458,62 +475,73 @@ def load(channel, value, repetitions, latency=0): with ActionContext(self): # PreLoadAll, PreLoadOne, LoadOne and LoadAll - for pool_ctrl in pool_ctrls: - load(pool_ctrl.master, value, repetitions, latency) + for conf_ctrl in conf_ctrls: + # TODO find solution for master now sardana only use timer + load(conf_ctrl.timer, value, repetitions, latency) # TODO: remove when the action allows to use tango attributes try: - pool_ctrls.pop('__tango__') + conf_ctrls.pop('__tango__') except Exception: pass # PreStartAll on all enabled controllers - for pool_ctrl in pool_ctrls: - pool_ctrl.ctrl.PreStartAll() + for conf_ctrl in conf_ctrls: + conf_ctrl.ctrl.PreStartAll() # PreStartOne & StartOne on all enabled elements - for pool_ctrl in pool_ctrls: - channels = pool_ctrl.channels - ctrl = pool_ctrl.ctrl + for conf_ctrl in conf_ctrls: + conf_channels = conf_ctrl.get_channels(enabled=True) # make sure that the master timer/monitor is started as the # last one - channels.remove(pool_ctrl.master) - channels.append(pool_ctrl.master) - for channel in channels: - axis = channel.axis - ret = ctrl.PreStartOne(axis, value) + conf_channels.remove(conf_ctrl.timer) + conf_channels.append(conf_ctrl.timer) + for conf_channel in conf_channels: + axis = conf_channel.axis + ret = conf_ctrl.ctrl.PreStartOne(axis, value) if not ret: msg = ("%s.PreStartOne(%d) returns False" % - (pool_ctrl.name, axis)) + (conf_ctrl.name, axis)) raise Exception(msg) try: - ctrl.StartOne(axis, value) + conf_ctrl.ctrl.StartOne(axis, value) except Exception as e: self.debug(e, exc_info=True) - channel.set_state(State.Fault, propagate=2) + conf_channel.set_state(State.Fault, propagate=2) msg = ("%s.StartOne(%d) failed" % - (pool_ctrl.name, axis)) + (conf_ctrl.name, axis)) raise Exception(msg) - self._channels.append(channel) + self._channels.append(conf_channel) # set the state of all elements to and inform their listeners - for channel in self._channels: - channel.set_state(State.Moving, propagate=2) + for conf_channel in self._channels: + conf_channel.set_state(State.Moving, propagate=2) # StartAll on all enabled controllers - for pool_ctrl in pool_ctrls: - channels = ctrl_channels[pool_ctrl] + for conf_ctrl in conf_ctrls: try: - pool_ctrl.ctrl.StartAll() + conf_ctrl.ctrl.StartAll() except Exception as e: + conf_channels = conf_ctrl.get_channels(enabled=True) self.debug(e, exc_info=True) - for channel in channels: - channel.set_state(State.Fault, propagate=2) - msg = ("%s.StartAll() failed" % pool_ctrl.name) + for conf_channel in conf_channels: + conf_channel.set_state(State.Fault, propagate=2) + msg = ("%s.StartAll() failed" % conf_ctrl.name) raise Exception(msg) + def _set_pool_ctrl_dict_loop(self, conf_ctrls): + ctrl_channels = {} + for conf_ctrl in conf_ctrls: + pool_channels = [] + pool_ctrl = conf_ctrl.element + # TODO: filter 1D and 2D for software synchronize acquisition + for conf_channel in conf_ctrl.get_channels(enabled=True): + pool_channels.append(conf_channel.element) + ctrl_channels[pool_ctrl] = pool_channels + self._pool_ctrl_dict_loop = ctrl_channels + def clear_value_buffers(self): for channel in self._channels: channel.clear_value_buffer() @@ -537,7 +565,8 @@ def action_loop(self): i = 0 states, values = {}, {} - for element in self._channels: + for channel in self._channels: + element = channel.element states[element] = None values[element] = None @@ -605,7 +634,8 @@ def __init__(self, main_element, name="AcquisitionSoftware", slaves=None): @DebugIt() def action_loop(self): states, values = {}, {} - for element in self._channels: + for channel in self._channels: + element = channel.element states[element] = None values[element] = None @@ -774,8 +804,7 @@ def start_action(self, *args, **kwargs): items = self.get_elements() cfg = self.main_element.configuration - pool_ctrls_dict = dict(cfg.ctrl_0d_sync) - pool_ctrls_dict.pop('__tango__', None) + pool_ctrls_dict = cfg.get_zerod_ctrls(enabled=True) pool_ctrls = [] for ctrl in pool_ctrls_dict: if ElementType.ZeroDExpChannel in ctrl.get_ctrl_types(): diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index a2b41b63f0..33480a4dc7 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -592,15 +592,16 @@ def __init__(self, **kwargs): kwargs['elem_type'] = ElementType.MeasurementGroup PoolGroupElement.__init__(self, **kwargs) - configuration = kwargs.get("configuration") - self.set_configuration(configuration) - # if the configuration was never "really" written e.g. newly created MG - # just sets it now so the _channe_to_acq_synch and ctrl_to_acq_synch - # are properly populated - # TODO: make it more elegant - if configuration is None: - configuration = self.configuration.configuration - self.set_configuration(configuration, propagate=0, to_fqdn=False) + # TODO: Check if it needed + # configuration = kwargs.get("configuration") + # self.set_configuration(configuration) + # # if the configuration was never "really" written e.g. newly created MG + # # just sets it now so the _channe_to_acq_synch and ctrl_to_acq_synch + # # are properly populated + # # TODO: make it more elegant + # if configuration is None: + # configuration = self.configuration.configuration + # self.set_configuration(configuration, propagate=0, to_fqdn=False) def _create_action_cache(self): acq_name = "%s.Acquisition" % self._name @@ -659,6 +660,7 @@ def _is_managed_element(self, element): def configuration(self): return self._config + # TODO: Check if it needed def set_configuration(self, config=None, propagate=1, to_fqdn=True): self._config._use_fqdn = to_fqdn self._config.configuration = config @@ -673,7 +675,7 @@ def set_configuration_from_user(self, cfg, propagate=1, to_fqdn=True): if not propagate: return self.fire_event(EventType("configuration", priority=propagate), - self._config.configuration) + self._config.get_configuration_for_user()) def get_user_configuration(self): return self._config.get_configuration_for_user() @@ -682,9 +684,9 @@ def load_configuration(self, force=False): """Loads the current configuration to all involved controllers""" # g_timer, g_monitor = cfg['timer'], cfg['monitor'] - for ctrl in self._config.enabled_ctrls: - if isinstance(ctrl, str): # skip external channels - continue + + for ctrl_item in self._config.get_timerable_ctrls(enabled=True): + ctrl = ctrl_item.element if not ctrl.is_online(): continue @@ -693,25 +695,23 @@ def load_configuration(self, force=False): if ctrl.operator == self and not force and not self._config_dirty: continue ctrl.operator = self - if ctrl.is_timerable(): - # TODO: Implement API to extract controller data - ctrl_data = self._config.configuration['controllers'][ctrl] - # if ctrl == g_timer.controller: - # ctrl.set_ctrl_par('timer', g_timer.axis) - # if ctrl == g_monitor.controller: - # ctrl.set_ctrl_par('monitor', g_monitor.axis) - ctrl.set_ctrl_par('timer', ctrl_data['timer'].axis) - ctrl.set_ctrl_par('monitor', ctrl_data['monitor'].axis) - synchronization = self._config.ctrl_to_acq_synch.get(ctrl) - self.debug('load_configuration: setting trigger_type: %s ' - 'to ctrl: %s' % (synchronization, ctrl)) - ctrl.set_ctrl_par('synchronization', synchronization) + # ctrl_data = self._config.configuration['controllers'][ctrl] + # # if ctrl == g_timer.controller: + # # ctrl.set_ctrl_par('timer', g_timer.axis) + # # if ctrl == g_monitor.controller: + # # ctrl.set_ctrl_par('monitor', g_monitor.axis) + ctrl.set_ctrl_par('timer', ctrl_item.timer.axis) + ctrl.set_ctrl_par('monitor', ctrl_item.monitor.axis) + synchronization = self._config.get_acq_synch_by_controller(ctrl) + self.debug('load_configuration: setting trigger_type: %s ' + 'to ctrl: %s' % (synchronization, ctrl)) + ctrl.set_ctrl_par('synchronization', synchronization) self._config_dirty = False def get_timer(self): # TODO: Adapt to the new future MeasurementConfiguration API - return self._config.configuration['timer'] + return self._config._master_timer timer = property(get_timer) @@ -877,10 +877,21 @@ def set_nr_of_starts(self, nr_of_starts, propagate=1): def prepare(self): # load configuration into controller(s) if necessary self.load_configuration() - config = self.configuration + ctrls = self.configuration.get_timerable_ctrls(enabled=True) + ctrl_lodeable = {} + for ctrl in ctrls: + if self.acquisition_mode == AcqMode.Timer: + lodeable = ctrl.timer + elif self.acquisition_mode == AcqMode.Monitor: + lodeable = ctrl.monitor + else: + continue + ctrl_lodeable[ctrl] = lodeable + nr_of_starts = self.nr_of_starts self._pending_starts = nr_of_starts - self.acquisition.prepare(config, nr_of_starts) + + self.acquisition.prepare(ctrl_lodeable, nr_of_starts) def start_acquisition(self, value=None, multiple=1): if self._pending_starts == 0: @@ -898,17 +909,33 @@ def start_acquisition(self, value=None, multiple=1): self._pending_starts -= 1 if not self._simulation_mode: # determining the acquisition parameters - kwargs = dict(head=self, config=self._config, multiple=multiple) - acquisition_mode = self.acquisition_mode - if acquisition_mode is AcqMode.Timer: - kwargs['integ_time'] = self.get_integration_time() - elif acquisition_mode is AcqMode.Monitor: - kwargs['monitor'] = self._monitor - kwargs['synchronization'] = self._synchronization - kwargs['moveable'] = self._moveable_obj - kwargs['sw_synch_initial_domain'] = self._sw_synch_initial_domain - # start acquisition - self.acquisition.run(**kwargs) + if self._acquisition_mode is AcqMode.Timer: + value = self.get_integration_time() + elif self.acquisition_mode is AcqMode.Monitor: + value = self._monitor_count + + self.acquisition.run( + head=self, + config=self._config, + multiple=multiple, + acq_mode=self.acquisition_mode, + value=value, + synchronization=self._synchronization, + moveable=self._moveable_obj, + sw_synch_initial_domain=self.sw_synch_initial_domain) + + # + # kwargs = dict(head=self, config=self._config, multiple=multiple) + # acquisition_mode = self.acquisition_mode + # if acquisition_mode is AcqMode.Timer: + # kwargs['integ_time'] = self.get_integration_time() + # elif acquisition_mode is AcqMode.Monitor: + # kwargs['monitor'] = self._monitor + # kwargs['synchronization'] = self._synchronization + # kwargs['moveable'] = self._moveable_obj + # kwargs['sw_synch_initial_domain'] = self._sw_synch_initial_domain + # # start acquisition + # self.acquisition.run(**kwargs) def set_acquisition(self, acq_cache): self.set_action_cache(acq_cache) diff --git a/src/sardana/pool/poolsynchronization.py b/src/sardana/pool/poolsynchronization.py index 1cfca7ba09..a424e861b0 100644 --- a/src/sardana/pool/poolsynchronization.py +++ b/src/sardana/pool/poolsynchronization.py @@ -141,37 +141,32 @@ def start_action(self, *args, **kwargs): synchronizer, can be either SynchDomain.Time or SynchDomain.Position ''' - cfg = self.main_element.configuration - synchronization = kwargs.get('synchronization') - moveable = kwargs.get('moveable') - sw_synch_initial_domain = kwargs.get('sw_synch_initial_domain', None) - ctrls_config = cfg.ctrl_tg_sync - pool_ctrls = ctrls_config.keys() - - # Prepare a dictionary with the involved channels - self._channels = channels = {} - for pool_ctrl in pool_ctrls: - pool_ctrl_data = ctrls_config[pool_ctrl] - elements = pool_ctrl_data['channels'] - - for element, element_info in elements.items(): - channel = TGChannel(element, info=element_info) - channels[element] = channel + # cfg = self.main_element.configuration + # ctrls_config = cfg.ctrl_tg_sync + # pool_ctrls = ctrls_config.keys() + # + # # Prepare a dictionary with the involved channels + # self._channels = channels = {} + # for pool_ctrl in pool_ctrls: + # pool_ctrl_data = ctrls_config[pool_ctrl] + # elements = pool_ctrl_data['channels'] + # + # for element, element_info in elements.items(): + # channel = TGChannel(element, info=element_info) + # channels[element] = channel with ActionContext(self): # loads synchronization description - for pool_ctrl in pool_ctrls: - ctrl = pool_ctrl.ctrl - pool_ctrl_data = ctrls_config[pool_ctrl] + for conf_ctrl in conf_ctrls: + ctrl = conf_ctrl.ctrl ctrl.PreSynchAll() - elements = pool_ctrl_data['channels'] - for element in elements: - axis = element.axis + for conf_channel in conf_ctrl.get_channels(enabled=True): + axis = conf_channel.axis ret = ctrl.PreSynchOne(axis, synchronization) if not ret: msg = ("%s.PreSynchOne(%d) returns False" % - (pool_ctrl.name, axis)) + (conf_ctrl.name, axis)) raise Exception(msg) ctrl.SynchOne(axis, synchronization) ctrl.SynchAll() @@ -206,30 +201,30 @@ def start_action(self, *args, **kwargs): get_thread_pool().add(self._synch_soft.run) # PreStartAll on all controllers - for pool_ctrl in pool_ctrls: - pool_ctrl.ctrl.PreStartAll() + for conf_ctrl in conf_ctrls: + conf_ctrl.ctrl.PreStartAll() # PreStartOne & StartOne on all elements - for pool_ctrl in pool_ctrls: - ctrl = pool_ctrl.ctrl - pool_ctrl_data = ctrls_config[pool_ctrl] - elements = pool_ctrl_data['channels'] - for element in elements: - axis = element.axis - channel = channels[element] + for conf_ctrl in conf_ctrls: + ctrl = conf_ctrl.ctrl + for conf_channel in conf_ctrl.get_channels(enabled=True): + axis = conf_channel.axis ret = ctrl.PreStartOne(axis) if not ret: raise Exception("%s.PreStartOne(%d) returns False" - % (pool_ctrl.name, axis)) + % (ctrl.name, axis)) ctrl.StartOne(axis) # set the state of all elements to inform their listeners - for channel in channels: - channel.set_state(State.Moving, propagate=2) + self._channels = [] + for conf_ctrl in conf_ctrls: + for conf_channel in conf_ctrl.get_channels(enabled=True): + conf_channel.set_state(State.Moving, propagate=2) + self._channels.append(conf_channel) # StartAll on all controllers - for pool_ctrl in pool_ctrls: - pool_ctrl.ctrl.StartAll() + for conf_ctrl in conf_ctrls: + conf_ctrl.ctrl.StartAll() def is_triggering(self, states): """Determines if we are triggering or if the triggering has ended @@ -254,7 +249,8 @@ def action_loop(self): '''action_loop method ''' states = {} - for element in self._channels: + for conf_channel in self._channels: + element = conf_channel.element states[element] = None # Triggering loop From cee606bac9cda03b146b6c30cd864f1ac2120008 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 25 Oct 2018 09:43:55 +0200 Subject: [PATCH 248/652] Change start_action API Do explicit the parameters needed by the action --- src/sardana/pool/poolacquisition.py | 18 +++++++++++------- src/sardana/pool/poolsynchronization.py | 3 ++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 3668ee3711..9adc1b5806 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -39,7 +39,7 @@ from sardana import SardanaValue, State, ElementType, TYPE_TIMERABLE_ELEMENTS from sardana.sardanathreadpool import get_thread_pool -from sardana.pool import SynchParam, SynchDomain, AcqSynch +from sardana.pool import SynchParam, SynchDomain, AcqSynch, AcqMode from sardana.pool.poolaction import ActionContext, PoolActionItem, PoolAction from sardana.pool.poolsynchronization import PoolSynchronization @@ -121,8 +121,9 @@ def event_received(self, *args, **kwargs): self.debug('Executing software acquisition.') args = () kwargs = self._sw_acq_config + # TODO: key synch is not used on the code, remove it kwargs['synch'] = True - kwargs['idx'] = value + kwargs['index'] = value self._sw_acq._started = True get_thread_pool().add(self._sw_acq.run, *args, **kwargs) if self._0d_config: @@ -135,8 +136,9 @@ def event_received(self, *args, **kwargs): self.debug('Executing ZeroD acquisition.') args = () kwargs = self._0d_config + # TODO: key synch is not used on the code, remove it kwargs['synch'] = True - kwargs['idx'] = value + kwargs['index'] = value self._0d_acq._started = True self._0d_acq._stopped = False self._0d_acq._aborted = False @@ -163,7 +165,9 @@ def is_running(self): self._hw_acq.is_running() or\ self._synch.is_running() - def run(self, *args, **kwargs): + def run(self, head, config, multiple, acq_mode, value, synchronization, + moveable, sw_synch_initial_domain=None, *args, **kwargs): + for elem in self.get_elements(): elem.put_state(None) # TODO: temporarily clear value buffers at the beginning of the @@ -378,14 +382,14 @@ def in_acquisition(self, states): return True @DebugIt() - def start_action(self, pool_ctrls, value, repetitions=1, latency=0, + def start_action(self, conf_ctrls, value, repetitions=1, latency=0, master=None, index=None, acq_sleep_time=None, nb_states_per_value=None, *args, **kwargs): """ Prepares everything for acquisition and starts it - :param pool_ctrls: List of enabled controllers - :type pool_ctrls: list + :param conf_ctrls: List of enabled controllers + :type conf_ctrls: list :param value: integration time/monitor counts :type value: float/int or seq :param repetitions: repetitions diff --git a/src/sardana/pool/poolsynchronization.py b/src/sardana/pool/poolsynchronization.py index a424e861b0..c7c8ae0bc5 100644 --- a/src/sardana/pool/poolsynchronization.py +++ b/src/sardana/pool/poolsynchronization.py @@ -127,7 +127,8 @@ def __init__(self, main_element, name="Synchronization"): def add_listener(self, listener): self._listener = listener - def start_action(self, *args, **kwargs): + def start_action(self, conf_ctrls, synchronization=None, moveable=None, + sw_synch_initial_domain=None, *args, **kwargs): '''Start action method. Expects the following kwargs: - config - dictionary containing measurement group configuration From 5cce652c92299ee716355404c7cf421de56f7402 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 25 Oct 2018 09:44:52 +0200 Subject: [PATCH 249/652] Adapt test to use new start_action API --- src/sardana/pool/test/helper.py | 21 +++++++++- src/sardana/pool/test/test_acquisition.py | 41 ++++++++++--------- .../pool/test/test_measurementgroup.py | 4 +- .../pool/test/test_poolsynchronization.py | 4 +- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index 6cd87dfe33..a2889630ed 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -27,6 +27,8 @@ 'createPoolZeroDExpChannel', 'createPoolTriggerGate', 'createPoolMotor', 'createPoolPseudoCounter', 'createPoolPseudoMotor', 'createPoolMeasurementGroup', + 'createControllerConfiguration', + 'createTimerableControllerConfiguration', 'createPoolSynchronizationConfiguration', 'createCTAcquisitionConfiguration', 'createMGConfiguration', 'createElemConf', 'createCtrlConf', 'createConfbyCtrlKlass', @@ -42,7 +44,7 @@ from sardana.pool.poolpseudocounter import PoolPseudoCounter from sardana.pool.poolpseudomotor import PoolPseudoMotor from sardana.pool.poolmeasurementgroup import PoolMeasurementGroup, \ - MeasurementConfiguration + MeasurementConfiguration, ControllerConfiguration, ChannelConfiguration def createPoolController(pool, conf): @@ -151,6 +153,23 @@ def createPoolMeasurementGroup(pool, conf): return PoolMeasurementGroup(**kwargs) +def createControllerConfiguration(pool_ctrl, pool_channels): + conf_ctrl = ControllerConfiguration(pool_ctrl) + for pool_channel in pool_channels: + channel = ChannelConfiguration(pool_channel) + channel.controller = conf_ctrl + conf_ctrl.add_channel(channel) + return conf_ctrl + + +def createTimerableControllerConfiguration(pool_ctrl, pool_channels): + conf_ctrl = createControllerConfiguration(pool_ctrl, pool_channels) + channel = conf_ctrl.get_channels(enabled=True)[0] + conf_ctrl.timer = channel + conf_ctrl.monitor = channel + return conf_ctrl + + def createPoolSynchronizationConfiguration(ctrls, ctrl_channels): '''Method to create PoolSynchronization configuration. Order of the sequences is important. For all sequences, the element of a given position diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index 6c49bc2541..a08648d9e6 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -36,9 +36,12 @@ from sardana.pool.poolacquisition import (PoolAcquisitionHardware, PoolAcquisitionSoftware, PoolCTAcquisition) +from sardana.pool.poolmeasurementgroup import ControllerConfiguration from sardana.sardanautils import is_non_str_seq from sardana.sardanathreadpool import get_thread_pool -from sardana.pool.test import (createPoolSynchronizationConfiguration, +from sardana.pool.test import (createControllerConfiguration, + createTimerableControllerConfiguration, + createPoolSynchronizationConfiguration, createCTAcquisitionConfiguration, BasePoolTestCase, FakeElement) @@ -295,8 +298,8 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, according the test parameters. Checks the lengths of the acquired data. """ # obtaining elements created in the BasePoolTestCase.setUp - tg_2_1 = self.tgs['_test_tg_1_1'] - tg_ctrl_2 = tg_2_1.get_controller() + tg_1_1 = self.tgs['_test_tg_1_1'] + tg_ctrl_1 = tg_1_1.get_controller() ct_1_1 = self.cts['_test_ct_1_1'] # hw synchronized ct_2_1 = self.cts['_test_ct_2_1'] # sw synchronized ct_ctrl_1 = ct_1_1.get_controller() @@ -304,15 +307,18 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, self.channel_names.append('_test_ct_1_1') self.channel_names.append('_test_ct_2_1') - ct_ctrl_1.channels = [ct_1_1] - ct_ctrl_1.master = ct_1_1 - ct_ctrl_2.channels = [ct_2_1] - ct_ctrl_2.master = ct_2_1 + conf_ct_ctrl_1 = createTimerableControllerConfiguration(ct_ctrl_1, + [ct_1_1]) + conf_ct_ctrl_2 = createTimerableControllerConfiguration(ct_ctrl_2, + [ct_2_1]) + conf_ct_2_1 = conf_ct_ctrl_2.timer + conf_tg_ctrl_1 = createControllerConfiguration(tg_ctrl_1, [tg_1_1]) + # crating configuration for TGGeneration - tg_cfg = createPoolSynchronizationConfiguration((tg_ctrl_2,), - ((tg_2_1,),)) + tg_cfg = createPoolSynchronizationConfiguration((tg_ctrl_1,), + ((tg_1_1,),)) # creating TGGeneration action - self.createPoolSynchronization([tg_2_1], tg_config=tg_cfg) + self.createPoolSynchronization([tg_1_1], tg_config=tg_cfg) # add_listeners self.addListeners([ct_1_1, ct_2_1]) # creating acquisition actions @@ -335,22 +341,19 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, # get the current number of jobs jobs_before = get_thread_pool().qsize - self.sw_acq_args = ([ct_ctrl_2], integ_time) - self.sw_acq_kwargs = {"master": ct_2_1} + self.sw_acq_args = ([conf_ct_ctrl_2], integ_time) + self.sw_acq_kwargs = {"master": conf_ct_2_1} ct_ctrl_1.set_ctrl_par('synchronization', AcqSynch.HardwareTrigger) - hw_acq_args = ([ct_ctrl_1], integ_time, repetitions) + hw_acq_args = ([conf_ct_ctrl_1], integ_time, repetitions) self.hw_acq.run(*hw_acq_args) - tg_args = () + total_interval = active_interval + passive_interval synchronization = [{SynchParam.Delay: {SynchDomain.Time: offset}, SynchParam.Active: {SynchDomain.Time: active_interval}, SynchParam.Total: {SynchDomain.Time: total_interval}, SynchParam.Repeats: repetitions}] - tg_kwargs = { - 'config': tg_cfg, - 'synchronization': synchronization - } - self.tggeneration.run(*tg_args, **tg_kwargs) + tg_args = ([conf_tg_ctrl_1], synchronization) + self.tggeneration.run(*tg_args) # waiting for acquisition and tggeneration to finish while (self.hw_acq.is_running() or self.sw_acq.is_running() or diff --git a/src/sardana/pool/test/test_measurementgroup.py b/src/sardana/pool/test/test_measurementgroup.py index c10bd51403..a309c91b8c 100644 --- a/src/sardana/pool/test/test_measurementgroup.py +++ b/src/sardana/pool/test/test_measurementgroup.py @@ -340,8 +340,8 @@ def tearDown(self): doc_13 = 'Test acquisition of zerod using software gate.' config_13 = [[('_test_ct_1_1', '_test_tg_1_1', AcqSynchType.Trigger), ], - [('_test_ct_2_1', 'software', AcqSynchType.Trigger), ], - [('_test_0d_1_1', 'software', AcqSynchType.Gate), ]] + [('_test_ct_2_1', 'software', AcqSynchType.Trigger), ],] + # [('_test_0d_1_1', 'software', AcqSynchType.Gate), ]] @insertTest(helper_name='meas_contpos_acquisition', test_method_doc=doc_12, diff --git a/src/sardana/pool/test/test_poolsynchronization.py b/src/sardana/pool/test/test_poolsynchronization.py index 22c2c706ff..043ebe3315 100644 --- a/src/sardana/pool/test/test_poolsynchronization.py +++ b/src/sardana/pool/test/test_poolsynchronization.py @@ -75,10 +75,8 @@ def stopGeneration(self): def test_tggeneration(self): """Verify trigger element states before and after action_loop.""" from mock import call - args = () - kwargs = {'config': self.cfg} # starting action - self.tgaction.start_action(*args, **kwargs) + self.tgaction.start_action(conf_ctrls) # verifying that the action correctly started the involved controller self.mock_tg_ctrl.assert_has_calls([call.PreStartAll(), (call.PreStartOne(1,)), From d0c3c3f85579ae75c937d6d73f58ef52b1b95d2f Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 25 Oct 2018 10:49:42 +0200 Subject: [PATCH 250/652] Fix flake8 --- src/sardana/util/parser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/util/parser.py b/src/sardana/util/parser.py index 880ea77f60..79c8e6f708 100644 --- a/src/sardana/util/parser.py +++ b/src/sardana/util/parser.py @@ -50,9 +50,9 @@ def generate_tokens(text): for m in iter(scanner.match, None): # quoted parameters must be returned without the quotes that's why we # extract a given group, otherwise we would extract the whole match - group = (m.group("QUOTEDPARAM") or - m.group("SINGQUOTEDPARAM") or - m.group()) + group = (m.group("QUOTEDPARAM") + or m.group("SINGQUOTEDPARAM") + or m.group()) tok = Token(m.lastgroup, group) if tok.type != "WS": yield tok From 15df24aacc08ab51f99cca956041503f9841e8e2 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 25 Oct 2018 14:35:41 +0200 Subject: [PATCH 251/652] Include the 0D channel on the test --- src/sardana/pool/test/test_measurementgroup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/test/test_measurementgroup.py b/src/sardana/pool/test/test_measurementgroup.py index a309c91b8c..c10bd51403 100644 --- a/src/sardana/pool/test/test_measurementgroup.py +++ b/src/sardana/pool/test/test_measurementgroup.py @@ -340,8 +340,8 @@ def tearDown(self): doc_13 = 'Test acquisition of zerod using software gate.' config_13 = [[('_test_ct_1_1', '_test_tg_1_1', AcqSynchType.Trigger), ], - [('_test_ct_2_1', 'software', AcqSynchType.Trigger), ],] - # [('_test_0d_1_1', 'software', AcqSynchType.Gate), ]] + [('_test_ct_2_1', 'software', AcqSynchType.Trigger), ], + [('_test_0d_1_1', 'software', AcqSynchType.Gate), ]] @insertTest(helper_name='meas_contpos_acquisition', test_method_doc=doc_12, From f7731fb5e9e315ff303a93129cd535f6891faea6 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 25 Oct 2018 14:46:20 +0200 Subject: [PATCH 252/652] Adapt test to new start_action API --- .../pool/test/test_poolsynchronization.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sardana/pool/test/test_poolsynchronization.py b/src/sardana/pool/test/test_poolsynchronization.py index 043ebe3315..ecd643fc38 100644 --- a/src/sardana/pool/test/test_poolsynchronization.py +++ b/src/sardana/pool/test/test_poolsynchronization.py @@ -28,10 +28,9 @@ from sardana.pool.poolsynchronization import PoolSynchronization from sardana.sardanadefs import State -from sardana.pool.test import (FakePool, createPoolController, - createPoolTriggerGate, dummyPoolTGCtrlConf01, - dummyTriggerGateConf01, - createPoolSynchronizationConfiguration) +from sardana.pool.test import FakePool, createPoolController, \ + createPoolTriggerGate, dummyPoolTGCtrlConf01, dummyTriggerGateConf01, \ + createControllerConfiguration class PoolTriggerGateTestCase(unittest.TestCase): @@ -53,8 +52,11 @@ def setUp(self): dummy_tg_ctrl.add_element(self.dummy_tg) pool.add_element(dummy_tg_ctrl) pool.add_element(self.dummy_tg) - self.cfg = createPoolSynchronizationConfiguration((dummy_tg_ctrl,), - ((self.dummy_tg,),),) + conf_ctrl = createControllerConfiguration(dummy_tg_ctrl, + [self.dummy_tg]) + self.conf_ctrls = [conf_ctrl] + # self.cfg = createPoolSynchronizationConfiguration((dummy_tg_ctrl,), + # ((self.dummy_tg,),),) # Create mock and define its functions ctrl_methods = ['PreStartAll', 'StartAll', 'PreStartOne', 'StartOne', 'PreStateAll', 'StateAll', 'PreStateOne', 'StateOne', @@ -63,8 +65,6 @@ def setUp(self): self.mock_tg_ctrl.StateOne.return_value = (State.Moving, 'triggering') dummy_tg_ctrl.ctrl = self.mock_tg_ctrl - # TODO: The TriggerGate should have a configuration - self.dummy_tg.configuration = self.cfg self.tgaction = PoolSynchronization(self.dummy_tg) self.tgaction.add_element(self.dummy_tg) @@ -76,7 +76,7 @@ def test_tggeneration(self): """Verify trigger element states before and after action_loop.""" from mock import call # starting action - self.tgaction.start_action(conf_ctrls) + self.tgaction.start_action(self.conf_ctrls) # verifying that the action correctly started the involved controller self.mock_tg_ctrl.assert_has_calls([call.PreStartAll(), (call.PreStartOne(1,)), From aaa51c4bec1d59a4e423b919c96cb9a802b46e49 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Thu, 25 Oct 2018 14:51:42 +0200 Subject: [PATCH 253/652] Allow to BaseMacroServerTestCase set propoerties on start the MacroServer --- src/sardana/tango/macroserver/test/base.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sardana/tango/macroserver/test/base.py b/src/sardana/tango/macroserver/test/base.py index 9580b0b85a..e017ee3dc6 100755 --- a/src/sardana/tango/macroserver/test/base.py +++ b/src/sardana/tango/macroserver/test/base.py @@ -44,7 +44,7 @@ class BaseMacroServerTestCase(object): door_name = getattr(sardanacustomsettings, 'UNITTEST_DOOR_NAME', "door/demo1/1") - def setUp(self, pool_name): + def setUp(self, pool_name=None, properties=None): """Start MacroServer DS. """ try: @@ -68,7 +68,13 @@ def setUp(self, pool_name): start_from = int(dev_name_parts[2]) self.door_name = get_free_device(db, prefix, start_from) self._msstarter.addNewDevice(self.door_name, klass='Door') - db.put_device_property(self.ms_name, {'PoolNames': pool_name}) + if pool_name is not None: + db.put_device_property(self.ms_name, {'PoolNames': pool_name}) + # Add properties + if properties: + for key, values in properties.items(): + db.put_device_property(self.ms_name, + {key: values}) # start MS server self._msstarter.startDs() self.door = PyTango.DeviceProxy(self.door_name) From 325174cf1ca647829b62c32ca5d1d089ed9e40c0 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Thu, 25 Oct 2018 14:54:04 +0200 Subject: [PATCH 254/652] unittest to runMacro, createMacro and execMaco --- .../macroserver/macros/test/test_macro.py | 25 +++++++++++ .../macroserver/test/res/macros/testmacros.py | 43 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/sardana/macroserver/macros/test/test_macro.py create mode 100644 src/sardana/macroserver/test/res/macros/testmacros.py diff --git a/src/sardana/macroserver/macros/test/test_macro.py b/src/sardana/macroserver/macros/test/test_macro.py new file mode 100644 index 0000000000..5edb193aa0 --- /dev/null +++ b/src/sardana/macroserver/macros/test/test_macro.py @@ -0,0 +1,25 @@ +from sardana.tango.macroserver.test import BaseMacroServerTestCase +from sardana.macroserver.macros.test import RunMacroTestCase, testRun +from taurus.external import unittest +import os + +@testRun(macro_name="runMacro") +@testRun(macro_name="createMacro") +@testRun(macro_name="execMacro") +class MacroTest(BaseMacroServerTestCase, RunMacroTestCase, unittest.TestCase): + + def setUp(self): + macros_test_path = '../../test/res/macros' + path = os.path.abspath(os.path.join(os.path.dirname( __file__ ), + macros_test_path)) + environment = {'MacroPath': [path]} + unittest.TestCase.setUp(self) + BaseMacroServerTestCase.setUp(self, properties=environment) + RunMacroTestCase.setUp(self) + + + def tearDown(self): + BaseMacroServerTestCase.tearDown(self) + RunMacroTestCase.tearDown(self) + unittest.TestCase.tearDown(self) + diff --git a/src/sardana/macroserver/test/res/macros/testmacros.py b/src/sardana/macroserver/test/res/macros/testmacros.py new file mode 100644 index 0000000000..5f23ceaf87 --- /dev/null +++ b/src/sardana/macroserver/test/res/macros/testmacros.py @@ -0,0 +1,43 @@ +from sardana.macroserver.macro import Type, Macro + + +class runMacro(Macro): + + def run(self, *args): + macro, _ = self.prepareMacro("testParamMacros1", 99, [1, 2]) + self.runMacro(macro) + macro, _ = self.prepareMacro("testParamMacros1", 99, 1, 2) + self.runMacro(macro) + + +class createMacro(Macro): + + def run(self, *args): + macro, pars = self.createMacro('testParamMacros1', 99, 1, 3) + self.runMacro(macro) + macro, pars = self.createMacro('testParamMacros1', 99, [1, 3]) + self.runMacro(macro) + + +class execMacro(Macro): + + def run(self, *args): + self.execMacro('testParamMacros1 99 [1 3]') + self.execMacro('testParamMacros1', '99', '1', '3') + + +class testParamMacros1(Macro): + """Macro with a motor parameter followed by a list of numbers. + Usages from Spock, ex.: + pt5 99 [1 3] + pt5 99 1 3 + """ + + param_def = [ + ['val1', Type.Float, None, 'value 1'], + ['numb_list', [['pos', Type.Float, None, 'value']], None, 'List of ' + 'values'], + ] + + def run(self, *args, **kwargs): + print args From 272666585adb4e154af3654be1c048c8a18e08d4 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Thu, 25 Oct 2018 14:56:06 +0200 Subject: [PATCH 255/652] flake8 Fix --- src/sardana/macroserver/macros/test/test_macro.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sardana/macroserver/macros/test/test_macro.py b/src/sardana/macroserver/macros/test/test_macro.py index 5edb193aa0..cc230f2834 100644 --- a/src/sardana/macroserver/macros/test/test_macro.py +++ b/src/sardana/macroserver/macros/test/test_macro.py @@ -1,8 +1,11 @@ -from sardana.tango.macroserver.test import BaseMacroServerTestCase -from sardana.macroserver.macros.test import RunMacroTestCase, testRun -from taurus.external import unittest import os +from taurus.external import unittest + +from sardana.macroserver.macros.test import RunMacroTestCase, testRun +from sardana.tango.macroserver.test import BaseMacroServerTestCase + + @testRun(macro_name="runMacro") @testRun(macro_name="createMacro") @testRun(macro_name="execMacro") @@ -10,16 +13,14 @@ class MacroTest(BaseMacroServerTestCase, RunMacroTestCase, unittest.TestCase): def setUp(self): macros_test_path = '../../test/res/macros' - path = os.path.abspath(os.path.join(os.path.dirname( __file__ ), - macros_test_path)) + source = os.path.join(os.path.dirname(__file__), macros_test_path) + path = os.path.abspath(source) environment = {'MacroPath': [path]} unittest.TestCase.setUp(self) BaseMacroServerTestCase.setUp(self, properties=environment) RunMacroTestCase.setUp(self) - def tearDown(self): BaseMacroServerTestCase.tearDown(self) RunMacroTestCase.tearDown(self) unittest.TestCase.tearDown(self) - From 84036620241415c23734b2e131d1db2f3bf920b9 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 25 Oct 2018 15:52:20 +0200 Subject: [PATCH 256/652] Handle Ctrl+C during spock profile creation Catch BaseException to also handle KeyboardInterrupt. --- src/sardana/spock/ipython_01_00/genutils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/spock/ipython_01_00/genutils.py b/src/sardana/spock/ipython_01_00/genutils.py index c486168148..080425497d 100644 --- a/src/sardana/spock/ipython_01_00/genutils.py +++ b/src/sardana/spock/ipython_01_00/genutils.py @@ -790,7 +790,8 @@ def create_spock_profile(userdir, profile, door_name=None): try: _create_config_file(ipy_profile_dir) - except Exception: + # catch BaseException in order to catch also KeyboardInterrupt + except BaseException: import shutil try: shutil.rmtree(ipy_profile_dir) From ced533220e81e49cd59bcd355fdd414537ce2cfb Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 25 Oct 2018 16:05:05 +0200 Subject: [PATCH 257/652] Change 0D start_action API --- src/sardana/pool/poolacquisition.py | 65 ++++++++++++----------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 9adc1b5806..70968a18a9 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -223,7 +223,7 @@ def run(self, head, config, multiple, acq_mode, value, synchronization, master=master) self.set_sw_config(sw_acq_kwargs) if len(ctrls_acq_0d): - zerod_acq_kwargs = dict(conf_ctrls=ctrls_acq_0d, value=value) + zerod_acq_kwargs = dict(conf_ctrls=ctrls_acq_0d) self.set_0d_config(zerod_acq_kwargs) #start the synchonization action @@ -779,57 +779,43 @@ class Pool0DAcquisition(PoolAction): def __init__(self, main_element, name="0DAcquisition"): self._channels = None + self._index = None PoolAction.__init__(self, main_element, name) - def start_action(self, *args, **kwargs): + def start_action(self, conf_ctrls, index=None, acq_sleep_time=None, + nb_states_per_value=None, *args, **kwargs): """Prepares everything for acquisition and starts it. :param: config""" pool = self.pool - - self._index = kwargs.get("idx") - - # prepare data structures # TODO: rollback this change when a proper synchronization between # acquisition actions will be develop. # Now the meta acquisition action is resettung them to 0. -# self._aborted = False -# self._stopped = False - - self._acq_sleep_time = kwargs.pop("acq_sleep_time", - pool.acq_loop_sleep_time) - self._nb_states_per_value = \ - kwargs.pop("nb_states_per_value", - pool.acq_loop_states_per_value) - - items = kwargs.get("items") - if items is None: - items = self.get_elements() - cfg = self.main_element.configuration - - pool_ctrls_dict = cfg.get_zerod_ctrls(enabled=True) - pool_ctrls = [] - for ctrl in pool_ctrls_dict: - if ElementType.ZeroDExpChannel in ctrl.get_ctrl_types(): - pool_ctrls.append(ctrl) - - # Determine which channels are active - self._channels = channels = {} - for pool_ctrl in pool_ctrls: - ctrl = pool_ctrl.ctrl - pool_ctrl_data = pool_ctrls_dict[pool_ctrl] - elements = pool_ctrl_data['channels'] + # self._aborted = False + # self._stopped = False - for element, element_info in elements.items(): - channel = Channel(element, info=element_info) - channels[element] = channel + self._index = index + + self._acq_sleep_time = acq_sleep_time + if self._acq_sleep_time is None: + self._acq_sleep_time = pool.acq_loop_sleep_time + + self._nb_states_per_value = nb_states_per_value + if self._nb_states_per_value is None: + self._nb_states_per_value = pool.acq_loop_states_per_value + + # channels that are acquired (only enabled) + self._channels = [] with ActionContext(self): # set the state of all elements to and inform their listeners - for channel in channels: - channel.clear_buffer() - channel.set_state(State.Moving, propagate=2) + + for conf_ctrl in conf_ctrls: + for conf_channel in conf_ctrl.get_channels(enabled=True): + conf_channel.clear_buffer() + conf_channel.set_state(State.Moving, propagate=2) + self._channels.append(conf_channel) def in_acquisition(self, states): """Determines if we are in acquisition or if the acquisition has ended @@ -848,7 +834,8 @@ def in_acquisition(self, states): def action_loop(self): states, values = {}, {} - for element in self._channels: + for conf_channel in self._channels: + element = conf_channel.element states[element] = None values[element] = None From 9c1dbe4ef3a82d99e1b268b58a4fc7f98fd56b39 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 25 Oct 2018 17:33:38 +0200 Subject: [PATCH 258/652] Update SynchronizationDescription Change integration_time attribute name to active_time Add passive_time attribute --- src/sardana/pool/poolacquisition.py | 2 +- src/sardana/pool/poolmeasurementgroup.py | 2 +- src/sardana/pool/poolsynchronization.py | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 70968a18a9..86b69f80c9 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -184,7 +184,7 @@ def run(self, head, config, multiple, acq_mode, value, synchronization, pseudo_elem.clear_value_buffer() if acq_mode is AcqMode.Timer: - value = synchronization.integration_time + value = synchronization.active_time repetitions = synchronization.repetitions latency_time = 0 diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 33480a4dc7..9b14e178c6 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -720,7 +720,7 @@ def get_timer(self): # ------------------------------------------------------------------------- def get_integration_time(self): - integration_time = self._synchronization.integration_time + integration_time = self._synchronization.active_time if type(integration_time) == float: return integration_time elif len(integration_time) == 0: diff --git a/src/sardana/pool/poolsynchronization.py b/src/sardana/pool/poolsynchronization.py index c7c8ae0bc5..aa8ee028d0 100644 --- a/src/sardana/pool/poolsynchronization.py +++ b/src/sardana/pool/poolsynchronization.py @@ -76,13 +76,17 @@ def repetitions(self): return repetitions @property - def integration_time(self): + def active_time(self): return self._get_param(SynchParam.Active) @property def total_time(self): return self._get_param(SynchParam.Total) + @property + def passive_time(self): + return self.total_time - self.active_time + def _get_param(self, param, domain=SynchDomain.Time): """ Extract parameter from synchronization description and its groups. If From 0f7cfdb27c07e294bb92b8927d97a81bad59bd46 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Thu, 25 Oct 2018 17:34:04 +0200 Subject: [PATCH 259/652] Update prepare method --- src/sardana/pool/controller.py | 2 +- src/sardana/pool/poolacquisition.py | 8 +++--- src/sardana/pool/poolmeasurementgroup.py | 31 +++++++++++++++--------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index e441e44c29..cd9e6873af 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -662,7 +662,7 @@ class Preparable(object): .. note: Do not inherit directly from Preparable.""" - def PrepareOne(self, axis, repetitions): + def PrepareOne(self, axis, value, repetitions, latency, nr_of_starts): """**Controller API**. Override if necessary. Called to load the number of repetitions. Default implementation does nothing. diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 86b69f80c9..7d00cac42d 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -149,15 +149,13 @@ def event_received(self, *args, **kwargs): self.debug('Stopping ZeroD acquisition.') self._0d_acq.stop_action() - def prepare(self, ctrl_lodeable, nr_of_starts): + def prepare(self, ctrl_lodeable, value, repetitions, latency, + nr_of_starts): """Prepare measurement.""" for ctrl, lodeable in ctrl_lodeable.items(): axis = lodeable.axis - try: - ctrl.PrepareOne(axis, nr_of_starts) - except Exception: - pass + ctrl.PrepareOne(axis, value, repetitions, latency, nr_of_starts) def is_running(self): return self._0d_acq.is_running() or\ diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 9b14e178c6..c68da969cb 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -877,21 +877,24 @@ def set_nr_of_starts(self, nr_of_starts, propagate=1): def prepare(self): # load configuration into controller(s) if necessary self.load_configuration() - ctrls = self.configuration.get_timerable_ctrls(enabled=True) + conf_ctrls = self.configuration.get_timerable_ctrls(enabled=True) ctrl_lodeable = {} - for ctrl in ctrls: + for conf_ctrl in conf_ctrls: if self.acquisition_mode == AcqMode.Timer: - lodeable = ctrl.timer + lodeable = conf_ctrl.timer elif self.acquisition_mode == AcqMode.Monitor: - lodeable = ctrl.monitor + lodeable = conf_ctrl.monitor else: continue - ctrl_lodeable[ctrl] = lodeable + ctrl_lodeable[conf_ctrl] = lodeable - nr_of_starts = self.nr_of_starts - self._pending_starts = nr_of_starts + value = self._get_value() + repetitions = self.synchronization.repetitions + latency = self.synchronization.passive_time + self._pending_starts = self.nr_of_starts - self.acquisition.prepare(ctrl_lodeable, nr_of_starts) + self.acquisition.prepare(ctrl_lodeable, value, repetitions, + latency, self.nr_of_starts) def start_acquisition(self, value=None, multiple=1): if self._pending_starts == 0: @@ -909,10 +912,7 @@ def start_acquisition(self, value=None, multiple=1): self._pending_starts -= 1 if not self._simulation_mode: # determining the acquisition parameters - if self._acquisition_mode is AcqMode.Timer: - value = self.get_integration_time() - elif self.acquisition_mode is AcqMode.Monitor: - value = self._monitor_count + value = self._get_value() self.acquisition.run( head=self, @@ -937,6 +937,13 @@ def start_acquisition(self, value=None, multiple=1): # # start acquisition # self.acquisition.run(**kwargs) + def _get_value(self): + if self._acquisition_mode is AcqMode.Timer: + value = self.get_integration_time() + elif self.acquisition_mode is AcqMode.Monitor: + value = self._monitor_count + return value + def set_acquisition(self, acq_cache): self.set_action_cache(acq_cache) From 7d7be5f005eea06deb6077fc2b4399e04c8d1348 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 25 Oct 2018 21:41:57 +0200 Subject: [PATCH 260/652] (minor) Remove unused imports --- src/sardana/pool/test/test_acquisition.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index a08648d9e6..18143c65ce 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -23,7 +23,6 @@ ## ############################################################################## import time -import datetime import numpy import threading @@ -33,17 +32,13 @@ from sardana.pool import AcqSynch from sardana.pool.pooldefs import SynchDomain, SynchParam from sardana.pool.poolsynchronization import PoolSynchronization -from sardana.pool.poolacquisition import (PoolAcquisitionHardware, - PoolAcquisitionSoftware, - PoolCTAcquisition) -from sardana.pool.poolmeasurementgroup import ControllerConfiguration -from sardana.sardanautils import is_non_str_seq +from sardana.pool.poolacquisition import PoolAcquisitionHardware, \ + PoolAcquisitionSoftware from sardana.sardanathreadpool import get_thread_pool -from sardana.pool.test import (createControllerConfiguration, - createTimerableControllerConfiguration, - createPoolSynchronizationConfiguration, - createCTAcquisitionConfiguration, - BasePoolTestCase, FakeElement) +from sardana.pool.test import createControllerConfiguration, \ + createTimerableControllerConfiguration, \ + createPoolSynchronizationConfiguration, \ + createCTAcquisitionConfiguration, BasePoolTestCase, FakeElement class AttributeListener(object): From 1f91c8000315c2ce682538541cf49867ea938ff6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 25 Oct 2018 22:23:35 +0200 Subject: [PATCH 261/652] Refactor acquisition test --- src/sardana/pool/test/test_acquisition.py | 182 +++++----------------- 1 file changed, 35 insertions(+), 147 deletions(-) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index 18143c65ce..d134e65512 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -36,9 +36,7 @@ PoolAcquisitionSoftware from sardana.sardanathreadpool import get_thread_pool from sardana.pool.test import createControllerConfiguration, \ - createTimerableControllerConfiguration, \ - createPoolSynchronizationConfiguration, \ - createCTAcquisitionConfiguration, BasePoolTestCase, FakeElement + createTimerableControllerConfiguration, BasePoolTestCase, FakeElement class AttributeListener(object): @@ -90,132 +88,25 @@ def get_table(self): class AcquisitionTestCase(BasePoolTestCase): def setUp(self): - """Create a Controller, TriggerGate and PoolSynchronization objects from - dummy configurations. - """ + """Create dummy controllers and elements.""" BasePoolTestCase.setUp(self) - self.l = AttributeListener() + self.data_listener = AttributeListener() self.channel_names = [] - - def createPoolSynchronization(self, tg_list, tg_config=None): self.main_element = FakeElement(self.pool) - # TODO: The TriggerGate should have a configuration - self.main_element.configuration = tg_config - self.tggeneration = PoolSynchronization(self.main_element) - for tg in tg_list: - self.tggeneration.add_element(tg) - self.tggeneration.add_listener(self) - - def hw_continuous_acquisition(self, offset, active_interval, - passive_interval, repetitions, integ_time): - """Executes measurement running the TGGeneration and Acquisition - actions according the test parameters. Checks the lengths of the - acquired data. - """ - # obtaining elements created in the BasePoolTestCase.setUp - tg = self.tgs[self.tg_elem_name] - tg_ctrl = tg.get_controller() - # crating configuration for TGGeneration - tg_cfg = createPoolSynchronizationConfiguration((tg_ctrl,), - ((tg,),)) - # creating PoolSynchronization action - self.createPoolSynchronization([tg], tg_config=tg_cfg) - - channels = [] - for name in self.channel_names: - channels.append(self.cts[name]) - - ct_ctrl = self.ctrls[self.chn_ctrl_name] - - # add_listeners - self.addListeners(channels) - # creating acquisition configurations - self.hw_acq_cfg = createCTAcquisitionConfiguration((ct_ctrl,), - (channels,)) - # creating acquisition actions - self.hw_acq = PoolAcquisitionHardware(channels[0]) - for channel in channels: - self.hw_acq.add_element(channel) - - # get the current number of jobs - jobs_before = get_thread_pool().qsize - - ct_ctrl.set_ctrl_par('synchronization', AcqSynch.HardwareTrigger) - - hw_acq_args = () - hw_acq_kwargs = { - 'integ_time': integ_time, - 'repetitions': repetitions, - 'config': self.hw_acq_cfg, - } - self.hw_acq.run(hw_acq_args, **hw_acq_kwargs) - tg_args = () - tg_kwargs = { - 'offset': offset, - 'active_interval': active_interval, - 'passive_interval': passive_interval, - 'repetitions': repetitions, - 'config': tg_cfg - } - self.tggeneration.run(*tg_args, **tg_kwargs) - # waiting for acquisition and tggeneration to finish - while self.hw_acq.is_running() or self.tggeneration.is_running(): - time.sleep(1) - self.do_asserts(self.channel_names, repetitions, jobs_before) - - def hw_step_acquisition(self, repetitions, integ_time): - """Executes measurement running the TGGeneration and Acquisition - actions according the test parameters. Checks the lengths of the - acquired data. - """ - - channels = [] - for name in self.channel_names: - channels.append(self.cts[name]) - - ct_ctrl = self.ctrls[self.chn_ctrl_name] + def create_action(self, class_, elements): + action = class_(self.main_element) + for element in elements: + action.add_element(element) + return action - # creating acquisition configurations - self.acq_cfg = createCTAcquisitionConfiguration((ct_ctrl,), - (channels,)) - # creating acquisition actions - main_element = FakeElement(self.pool) - # TODO: The main_element should have a configuration - main_element.configuration = self.acq_cfg - - self.ct_acq = PoolAcquisitionSoftware(main_element) - for channel in channels: - self.ct_acq.add_element(channel) - - ct_ctrl.set_ctrl_par('synchronization', AcqSynch.SoftwareTrigger) - - ct_acq_args = () - ct_acq_kwargs = { - 'integ_time': integ_time, - 'repetitions': repetitions, - 'config': self.acq_cfg, - } - self.ct_acq.run(ct_acq_args, **ct_acq_kwargs) - # waiting for acquisition - while self.ct_acq.is_running(): - time.sleep(0.02) - - for channel in channels: - name = channel.name - value = channel.value.value - print 'channel: %s = %s' % (name, value) - msg = ('Value for channel %s is of type %s, should be ' % - (name, type(value))) - self.assertIsInstance(value, float, msg) - - def addListeners(self, chn_list): + def add_listeners(self, chn_list): for chn in chn_list: - chn.add_listener(self.l) + chn.add_listener(self.data_listener) def do_asserts(self, channel_names, repetitions, jobs_before): # print acquisition records - table = self.l.get_table() + table = self.data_listener.get_table() header = table.dtype.names print header n_rows = table.shape[0] @@ -239,8 +130,9 @@ def do_asserts(self, channel_names, repetitions, jobs_before): def tearDown(self): BasePoolTestCase.tearDown(self) - self.l = None + self.data_listener = None self.channel_names = None + self.main_element = None @insertTest(helper_name='continuous_acquisition', offset=0, active_interval=0.1, @@ -298,6 +190,7 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, ct_1_1 = self.cts['_test_ct_1_1'] # hw synchronized ct_2_1 = self.cts['_test_ct_2_1'] # sw synchronized ct_ctrl_1 = ct_1_1.get_controller() + ct_ctrl_1.set_ctrl_par("synchronization", AcqSynch.HardwareTrigger) ct_ctrl_2 = ct_2_1.get_controller() self.channel_names.append('_test_ct_1_1') self.channel_names.append('_test_ct_2_1') @@ -308,17 +201,15 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, [ct_2_1]) conf_ct_2_1 = conf_ct_ctrl_2.timer conf_tg_ctrl_1 = createControllerConfiguration(tg_ctrl_1, [tg_1_1]) - - # crating configuration for TGGeneration - tg_cfg = createPoolSynchronizationConfiguration((tg_ctrl_1,), - ((tg_1_1,),)) - # creating TGGeneration action - self.createPoolSynchronization([tg_1_1], tg_config=tg_cfg) + # creating synchronization action + self.synchronization = self.create_action(PoolSynchronization, + [tg_1_1]) + self.synchronization.add_listener(self) # add_listeners - self.addListeners([ct_1_1, ct_2_1]) + self.add_listeners([ct_1_1, ct_2_1]) # creating acquisition actions - self.hw_acq = PoolAcquisitionHardware(ct_1_1) - self.sw_acq = PoolAcquisitionSoftware(ct_2_1) + self.hw_acq = self.create_action(PoolAcquisitionHardware, [ct_1_1]) + self.sw_acq = self.create_action(PoolAcquisitionSoftware, [ct_2_1]) # Since we deposit the software acquisition action on the PoolThread's # queue we can not rely on the action's state - one may still wait # in the queue (its state has not changed to running yet) and we would @@ -330,30 +221,27 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, self.sw_acq_busy = threading.Event() self.sw_acq.add_finish_hook(self.sw_acq_busy.clear) - self.hw_acq.add_element(ct_1_1) - self.sw_acq.add_element(ct_2_1) + self.sw_acq_args = ([conf_ct_ctrl_2], integ_time) + self.sw_acq_kwargs = {"master": conf_ct_2_1} # get the current number of jobs jobs_before = get_thread_pool().qsize - - self.sw_acq_args = ([conf_ct_ctrl_2], integ_time) - self.sw_acq_kwargs = {"master": conf_ct_2_1} - ct_ctrl_1.set_ctrl_par('synchronization', AcqSynch.HardwareTrigger) - hw_acq_args = ([conf_ct_ctrl_1], integ_time, repetitions) - self.hw_acq.run(*hw_acq_args) + self.hw_acq.run([conf_ct_ctrl_1], integ_time, repetitions) total_interval = active_interval + passive_interval - synchronization = [{SynchParam.Delay: {SynchDomain.Time: offset}, - SynchParam.Active: {SynchDomain.Time: active_interval}, - SynchParam.Total: {SynchDomain.Time: total_interval}, - SynchParam.Repeats: repetitions}] - tg_args = ([conf_tg_ctrl_1], synchronization) - self.tggeneration.run(*tg_args) - # waiting for acquisition and tggeneration to finish + group = { + SynchParam.Delay: {SynchDomain.Time: offset}, + SynchParam.Active: {SynchDomain.Time: active_interval}, + SynchParam.Total: {SynchDomain.Time: total_interval}, + SynchParam.Repeats: repetitions + } + synchronization = [group] + self.synchronization.run([conf_tg_ctrl_1], synchronization) + # waiting for acquisition and synchronization to finish while (self.hw_acq.is_running() or self.sw_acq.is_running() or - self.tggeneration.is_running()): - time.sleep(1) + self.synchronization.is_running()): + time.sleep(.1) self.do_asserts(self.channel_names, repetitions, jobs_before) def tearDown(self): From 67450b2a4d1aec4f775b6c2df98999eefd0f9da6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 25 Oct 2018 22:46:06 +0200 Subject: [PATCH 262/652] Add test for software start acquisition --- src/sardana/pool/test/test_acquisition.py | 80 +++++++++++++++++++++-- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index d134e65512..c99095104e 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -26,14 +26,14 @@ import numpy import threading -from taurus.external import unittest +from taurus.external.unittest import TestCase from taurus.test import insertTest from sardana.pool import AcqSynch from sardana.pool.pooldefs import SynchDomain, SynchParam from sardana.pool.poolsynchronization import PoolSynchronization from sardana.pool.poolacquisition import PoolAcquisitionHardware, \ - PoolAcquisitionSoftware + PoolAcquisitionSoftware, PoolAcquisitionSoftwareStart from sardana.sardanathreadpool import get_thread_pool from sardana.pool.test import createControllerConfiguration, \ createTimerableControllerConfiguration, BasePoolTestCase, FakeElement @@ -146,7 +146,7 @@ def tearDown(self): @insertTest(helper_name='continuous_acquisition', offset=0, active_interval=0.001, passive_interval=0.1, repetitions=10, integ_time=0.01) -class DummyAcquisitionTestCase(AcquisitionTestCase, unittest.TestCase): +class DummyAcquisitionTestCase(AcquisitionTestCase, TestCase): """Integration test of PoolSynchronization, PoolAcquisitionHardware and PoolAcquisitionSoftware actions. This test plays the role of the PoolAcquisition macro action (it aggregates the sub-actions and assign the @@ -158,7 +158,7 @@ def setUp(self): """Create a Controller, TriggerGate and PoolSynchronization objects from dummy configurations. """ - unittest.TestCase.setUp(self) + TestCase.setUp(self) AcquisitionTestCase.setUp(self) def event_received(self, *args, **kwargs): @@ -246,4 +246,74 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, def tearDown(self): AcquisitionTestCase.tearDown(self) - unittest.TestCase.tearDown(self) + TestCase.tearDown(self) + + +@insertTest(helper_name='acquire', integ_time=0.01, repetitions=10, + latency_time=0.02) +class AcquisitionSoftwareStartTestCase(AcquisitionTestCase, TestCase): + + def setUp(self): + """Create a Controller, TriggerGate and PoolSynchronization objects from + dummy configurations. + """ + TestCase.setUp(self) + AcquisitionTestCase.setUp(self) + + def event_received(self, *args, **kwargs): + """Execute software start acquisition.""" + _, type_, value = args + name = type_.name + if name != "start": + return + args = self.acq_args + kwargs = self.acq_kwargs + kwargs['idx'] = value + get_thread_pool().add(self.acquisition.run, None, *args, **kwargs) + + def acquire(self, integ_time, repetitions, latency_time): + # obtain elements/controllers involved in the test + tg_1_1 = self.tgs['_test_tg_1_1'] + tg_ctrl_1 = tg_1_1.get_controller() + ct_1_1 = self.cts['_test_ct_1_1'] + ct_ctrl_1 = ct_1_1.get_controller() + ct_ctrl_1.set_ctrl_par("synchronization", AcqSynch.SoftwareStart) + + self.channel_names.append('_test_ct_1_1') + + conf_ct_ctrl_1 = createTimerableControllerConfiguration(ct_ctrl_1, + [ct_1_1]) + conf_ct_1_1 = conf_ct_ctrl_1.timer + conf_tg_ctrl_1 = createControllerConfiguration(tg_ctrl_1, [tg_1_1]) + # creating synchronization action + self.synchronization = self.create_action(PoolSynchronization, + [tg_1_1]) + self.synchronization.add_listener(self) + # add_listeners + self.add_listeners([ct_1_1]) + # creating acquisition actions + self.acquisition = self.create_action(PoolAcquisitionSoftwareStart, + [ct_1_1]) + self.acq_args = ([conf_ct_ctrl_1], integ_time) + self.acq_kwargs = {"master": conf_ct_1_1} + + total_interval = integ_time + latency_time + group = { + SynchParam.Delay: {SynchDomain.Time: 0}, + SynchParam.Active: {SynchDomain.Time: integ_time}, + SynchParam.Total: {SynchDomain.Time: total_interval}, + SynchParam.Repeats: repetitions + } + synchronization = [group] + # get the current number of jobs + jobs_before = get_thread_pool().qsize + self.synchronization.run([conf_tg_ctrl_1], synchronization) + # waiting for acquisition and synchronization to finish + while (self.acquisition.is_running() + or self.synchronization.is_running()): + time.sleep(.1) + self.do_asserts(self.channel_names, repetitions, jobs_before) + + def tearDown(self): + AcquisitionTestCase.tearDown(self) + TestCase.tearDown(self) \ No newline at end of file From 96e119dd7fd9e2b992be3284fabbd3a986eb5828 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 25 Oct 2018 23:02:57 +0200 Subject: [PATCH 263/652] Implement action_loop of software start acquisition --- src/sardana/pool/poolacquisition.py | 67 +++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 7d00cac42d..ea3274ef8c 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -687,6 +687,73 @@ def action_loop(self): acquirable.set_state_info(state_info, propagate=2) +class PoolAcquisitionSoftwareStart(PoolAcquisitionBase): + """Acquisition action for controllers synchronized by software start + + .. note:: + The PoolAcquisitionSoftwareStart class has been included in Sardana + on a provisional basis. Backwards incompatible changes + (up to and including removal of the module) may occur if + deemed necessary by the core developers. + """ + + def __init__(self, main_element, name="AcquisitionSoftwareStart"): + PoolAcquisitionBase.__init__(self, main_element, name) + + @DebugIt() + def action_loop(self): + i = 0 + + states, values = {}, {} + for channel in self._channels: + element = channel.element + states[element] = None + values[element] = None + + nap = self._acq_sleep_time + nb_states_per_value = self._nb_states_per_value + + while True: + self.read_state_info(ret=states) + if not self.in_acquisition(states): + break + + # read value every n times + if not i % nb_states_per_value: + self.read_value_loop(ret=values) + for acquirable, value in values.items(): + if is_value_error(value): + self.error("Loop read value error for %s" % + acquirable.name) + acquirable.put_value(value) + else: + acquirable.extend_value_buffer(value) + + time.sleep(nap) + i += 1 + + with ActionContext(self): + self.raw_read_state_info(ret=states) + self.raw_read_value_loop(ret=values) + + for acquirable, state_info in states.items(): + # first update the element state so that value calculation + # that is done after takes the updated state into account + acquirable.set_state_info(state_info, propagate=0) + if acquirable in values: + value = values[acquirable] + if is_value_error(value): + self.error("Loop final read value error for: %s" % + acquirable.name) + acquirable.put_value(value) + else: + acquirable.extend_value_buffer(value, propagate=2) + with acquirable: + acquirable.clear_operation() + state_info = acquirable._from_ctrl_state_info(state_info) + acquirable.set_state_info(state_info, propagate=2) + + class PoolCTAcquisition(PoolAcquisitionBase): def __init__(self, main_element, name="CTAcquisition", slaves=None): From 7795b99b7aa1431047ca44560276afc9943c479a Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 25 Oct 2018 23:03:12 +0200 Subject: [PATCH 264/652] Fix test of software start acquisition --- src/sardana/pool/test/test_acquisition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index c99095104e..5a516ddadf 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -294,7 +294,7 @@ def acquire(self, integ_time, repetitions, latency_time): # creating acquisition actions self.acquisition = self.create_action(PoolAcquisitionSoftwareStart, [ct_1_1]) - self.acq_args = ([conf_ct_ctrl_1], integ_time) + self.acq_args = ([conf_ct_ctrl_1], integ_time, repetitions) self.acq_kwargs = {"master": conf_ct_1_1} total_interval = integ_time + latency_time From 6b65154ec1118fb39847b7c2ece328a541a5b52c Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 26 Oct 2018 10:10:59 +0200 Subject: [PATCH 265/652] Refactor acquisition tests to facilitate development of new tests --- src/sardana/pool/test/test_acquisition.py | 65 +++++++++++------------ 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index 5a516ddadf..ad45c770c8 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -90,9 +90,15 @@ class AcquisitionTestCase(BasePoolTestCase): def setUp(self): """Create dummy controllers and elements.""" BasePoolTestCase.setUp(self) + self.acquisition = None + self.synchronization = None self.data_listener = AttributeListener() - self.channel_names = [] self.main_element = FakeElement(self.pool) + self.tg_1_1 = self.tgs['_test_tg_1_1'] + self.tg_ctrl_1 = self.tg_1_1.get_controller() + self.ct_1_1 = self.cts['_test_ct_1_1'] + self.ct_ctrl_1 = self.ct_1_1.get_controller() + self.channel_names = ['_test_ct_1_1'] def create_action(self, class_, elements): action = class_(self.main_element) @@ -104,7 +110,13 @@ def add_listeners(self, chn_list): for chn in chn_list: chn.add_listener(self.data_listener) - def do_asserts(self, channel_names, repetitions, jobs_before): + def wait_finish(self): + # waiting for acquisition and synchronization to finish + while (self.acquisition.is_running() + or self.synchronization.is_running()): + time.sleep(.1) + + def do_asserts(self, repetitions, jobs_before): # print acquisition records table = self.data_listener.get_table() header = table.dtype.names @@ -113,7 +125,7 @@ def do_asserts(self, channel_names, repetitions, jobs_before): for row in xrange(n_rows): print row, table[row] # checking if all channels produced data - for channel in channel_names: + for channel in self.channel_names: msg = 'data from channel %s were not acquired' % channel self.assertIn(channel, header, msg) # checking if all the data were acquired @@ -223,10 +235,6 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, self.sw_acq_args = ([conf_ct_ctrl_2], integ_time) self.sw_acq_kwargs = {"master": conf_ct_2_1} - - # get the current number of jobs - jobs_before = get_thread_pool().qsize - self.hw_acq.run([conf_ct_ctrl_1], integ_time, repetitions) total_interval = active_interval + passive_interval group = { @@ -236,13 +244,16 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, SynchParam.Repeats: repetitions } synchronization = [group] + # get the current number of jobs + jobs_before = get_thread_pool().qsize + self.hw_acq.run([conf_ct_ctrl_1], integ_time, repetitions) self.synchronization.run([conf_tg_ctrl_1], synchronization) # waiting for acquisition and synchronization to finish while (self.hw_acq.is_running() or self.sw_acq.is_running() or self.synchronization.is_running()): time.sleep(.1) - self.do_asserts(self.channel_names, repetitions, jobs_before) + self.do_asserts(repetitions, jobs_before) def tearDown(self): AcquisitionTestCase.tearDown(self) @@ -254,46 +265,37 @@ def tearDown(self): class AcquisitionSoftwareStartTestCase(AcquisitionTestCase, TestCase): def setUp(self): - """Create a Controller, TriggerGate and PoolSynchronization objects from - dummy configurations. - """ + """Create test actors (controllers and elements)""" TestCase.setUp(self) AcquisitionTestCase.setUp(self) def event_received(self, *args, **kwargs): - """Execute software start acquisition.""" + """Callback to execute software start acquisition.""" _, type_, value = args name = type_.name if name != "start": return args = self.acq_args kwargs = self.acq_kwargs - kwargs['idx'] = value get_thread_pool().add(self.acquisition.run, None, *args, **kwargs) def acquire(self, integ_time, repetitions, latency_time): - # obtain elements/controllers involved in the test - tg_1_1 = self.tgs['_test_tg_1_1'] - tg_ctrl_1 = tg_1_1.get_controller() - ct_1_1 = self.cts['_test_ct_1_1'] - ct_ctrl_1 = ct_1_1.get_controller() - ct_ctrl_1.set_ctrl_par("synchronization", AcqSynch.SoftwareStart) + """Acquire with a dummy C/T synchronized by a hardware start + trigger from a dummy T/G.""" + self.ct_ctrl_1.set_ctrl_par("synchronization", AcqSynch.SoftwareStart) - self.channel_names.append('_test_ct_1_1') - - conf_ct_ctrl_1 = createTimerableControllerConfiguration(ct_ctrl_1, - [ct_1_1]) + conf_ct_ctrl_1 = createTimerableControllerConfiguration(self.ct_ctrl_1, + [self.ct_1_1]) conf_ct_1_1 = conf_ct_ctrl_1.timer - conf_tg_ctrl_1 = createControllerConfiguration(tg_ctrl_1, [tg_1_1]) # creating synchronization action self.synchronization = self.create_action(PoolSynchronization, - [tg_1_1]) + [self.tg_1_1]) self.synchronization.add_listener(self) # add_listeners - self.add_listeners([ct_1_1]) + self.add_listeners([self.ct_1_1]) # creating acquisition actions self.acquisition = self.create_action(PoolAcquisitionSoftwareStart, - [ct_1_1]) + [self.ct_1_1]) self.acq_args = ([conf_ct_ctrl_1], integ_time, repetitions) self.acq_kwargs = {"master": conf_ct_1_1} @@ -307,12 +309,9 @@ def acquire(self, integ_time, repetitions, latency_time): synchronization = [group] # get the current number of jobs jobs_before = get_thread_pool().qsize - self.synchronization.run([conf_tg_ctrl_1], synchronization) - # waiting for acquisition and synchronization to finish - while (self.acquisition.is_running() - or self.synchronization.is_running()): - time.sleep(.1) - self.do_asserts(self.channel_names, repetitions, jobs_before) + self.synchronization.run([], synchronization) + self.wait_finish() + self.do_asserts(repetitions, jobs_before) def tearDown(self): AcquisitionTestCase.tearDown(self) From 7b70a05963051ed0dcc680d5846541d7e22db50c Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 26 Oct 2018 10:11:27 +0200 Subject: [PATCH 266/652] Add hardware start acquisition test --- src/sardana/pool/test/test_acquisition.py | 58 +++++++++++++++++++++-- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index ad45c770c8..0cdc1e5452 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -235,7 +235,7 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, self.sw_acq_args = ([conf_ct_ctrl_2], integ_time) self.sw_acq_kwargs = {"master": conf_ct_2_1} - + total_interval = active_interval + passive_interval group = { SynchParam.Delay: {SynchDomain.Time: offset}, @@ -249,9 +249,9 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, self.hw_acq.run([conf_ct_ctrl_1], integ_time, repetitions) self.synchronization.run([conf_tg_ctrl_1], synchronization) # waiting for acquisition and synchronization to finish - while (self.hw_acq.is_running() or - self.sw_acq.is_running() or - self.synchronization.is_running()): + while (self.hw_acq.is_running() + or self.sw_acq.is_running() + or self.synchronization.is_running()): time.sleep(.1) self.do_asserts(repetitions, jobs_before) @@ -263,6 +263,7 @@ def tearDown(self): @insertTest(helper_name='acquire', integ_time=0.01, repetitions=10, latency_time=0.02) class AcquisitionSoftwareStartTestCase(AcquisitionTestCase, TestCase): + """Integration test of PoolSynchronization and PoolAcquisitionHardware""" def setUp(self): """Create test actors (controllers and elements)""" @@ -315,4 +316,51 @@ def acquire(self, integ_time, repetitions, latency_time): def tearDown(self): AcquisitionTestCase.tearDown(self) - TestCase.tearDown(self) \ No newline at end of file + TestCase.tearDown(self) + + +@insertTest(helper_name='acquire', integ_time=0.01, repetitions=10, + latency_time=0.02) +class AcquisitionHardwareStartTestCase(AcquisitionTestCase, TestCase): + """Integration test of PoolSynchronization and PoolAcquisitionHardware""" + + def setUp(self): + """Create test actors (controllers and elements)""" + TestCase.setUp(self) + AcquisitionTestCase.setUp(self) + + def acquire(self, integ_time, repetitions, latency_time): + """Acquire with a dummy C/T synchronized by a hardware start + trigger from a dummy T/G.""" + self.ct_ctrl_1.set_ctrl_par("synchronization", AcqSynch.HardwareStart) + conf_ct_ctrl_1 = createTimerableControllerConfiguration( + self.ct_ctrl_1, [self.ct_1_1]) + conf_tg_ctrl_1 = createControllerConfiguration(self.tg_ctrl_1, + [self.tg_1_1]) + self.synchronization = self.create_action(PoolSynchronization, + [self.tg_1_1]) + # add data listeners + self.add_listeners([self.ct_1_1]) + # creating acquisition actions + self.acquisition = self.create_action(PoolAcquisitionHardware, + [self.ct_1_1]) + self.acq_args = ([conf_ct_ctrl_1], integ_time, repetitions) + # prepare synchronization description + total_interval = integ_time + latency_time + group = { + SynchParam.Delay: {SynchDomain.Time: 0}, + SynchParam.Active: {SynchDomain.Time: integ_time}, + SynchParam.Total: {SynchDomain.Time: total_interval}, + SynchParam.Repeats: repetitions + } + synchronization = [group] + # get the current number of jobs + jobs_before = get_thread_pool().qsize + self.acquisition.run([conf_ct_ctrl_1], integ_time, repetitions) + self.synchronization.run([conf_tg_ctrl_1], synchronization) + self.wait_finish() + self.do_asserts(repetitions, jobs_before) + + def tearDown(self): + AcquisitionTestCase.tearDown(self) + TestCase.tearDown(self) From d1afe5180fdc5fd6c7956c0936bcdc250a567ae2 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 26 Oct 2018 11:18:00 +0200 Subject: [PATCH 267/652] Fix minor error --- src/sardana/pool/poolacquisition.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index ea3274ef8c..547d1f290e 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -153,9 +153,10 @@ def prepare(self, ctrl_lodeable, value, repetitions, latency, nr_of_starts): """Prepare measurement.""" - for ctrl, lodeable in ctrl_lodeable.items(): + for conf_ctrl, lodeable in ctrl_lodeable.items(): axis = lodeable.axis - ctrl.PrepareOne(axis, value, repetitions, latency, nr_of_starts) + conf_ctrl.ctrl.PrepareOne(axis, value, repetitions, latency, + nr_of_starts) def is_running(self): return self._0d_acq.is_running() or\ From 06dfb5ed8e257ed80de3492cb0acfb01ff74776f Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 26 Oct 2018 11:22:51 +0200 Subject: [PATCH 268/652] Fix flake8 errors --- src/sardana/pool/poolacquisition.py | 3 +-- src/sardana/pool/poolmeasurementgroup.py | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 547d1f290e..8c28b50fc9 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -193,7 +193,6 @@ def run(self, head, config, multiple, acq_mode, value, synchronization, ctrls_acq_hw = config.get_timerable_ctrls(acq_synch=acq_sync_hw, enabled=True) - if len(ctrls_acq_hw): self._hw_acq.run(conf_ctrls=ctrls_acq_hw, value=value, @@ -225,7 +224,7 @@ def run(self, head, config, multiple, acq_mode, value, synchronization, zerod_acq_kwargs = dict(conf_ctrls=ctrls_acq_0d) self.set_0d_config(zerod_acq_kwargs) - #start the synchonization action + # start the synchonization action ctrls_synch = config.get_synch_ctrls(enabled=True) self._synch.run(conf_ctrls=ctrls_synch, synchronization=synchronization, diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index c68da969cb..92d021dd7a 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -318,7 +318,6 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): master_monitor_sw_start = None master_timer = None master_monitor = None - element_acq_synch = {} master_timer_idx_sw = float("+inf") master_monitor_idx_sw = float("+inf") user_elem_ids = {} @@ -507,6 +506,8 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): self._other_ctrls = other_ctrls self._master_timer_sw = master_timer_sw self._master_monitor_sw = master_monitor_sw + self._master_timer_sw_start = master_timer_sw_start + self._master_monitor_sw_start = master_monitor_sw_start self._user_confg = user_config self._channel_acq_synch = channel_acq_synch self._ctrl_acq_synch = ctrl_acq_synch @@ -595,7 +596,8 @@ def __init__(self, **kwargs): # TODO: Check if it needed # configuration = kwargs.get("configuration") # self.set_configuration(configuration) - # # if the configuration was never "really" written e.g. newly created MG + # # if the configuration was never "really" written e.g. newly created + # # MG # # just sets it now so the _channe_to_acq_synch and ctrl_to_acq_synch # # are properly populated # # TODO: make it more elegant From 1bb06b16b6c518a3f5beb2400937bed1a915e78a Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 26 Oct 2018 11:25:11 +0200 Subject: [PATCH 269/652] Remove unused imports --- src/sardana/pool/poolacquisition.py | 2 +- src/sardana/pool/poolmeasurementgroup.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 8c28b50fc9..453ee13923 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -39,7 +39,7 @@ from sardana import SardanaValue, State, ElementType, TYPE_TIMERABLE_ELEMENTS from sardana.sardanathreadpool import get_thread_pool -from sardana.pool import SynchParam, SynchDomain, AcqSynch, AcqMode +from sardana.pool import AcqSynch, AcqMode from sardana.pool.poolaction import ActionContext, PoolActionItem, PoolAction from sardana.pool.poolsynchronization import PoolSynchronization diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 92d021dd7a..2c70a52395 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -41,10 +41,9 @@ from taurus.core.tango.tangovalidator import TangoAttributeNameValidator from sardana import State, ElementType, \ - TYPE_EXP_CHANNEL_ELEMENTS, TYPE_TIMERABLE_ELEMENTS + TYPE_EXP_CHANNEL_ELEMENTS from sardana.sardanaevent import EventType -from sardana.pool.pooldefs import (AcqMode, AcqSynchType, SynchParam, AcqSynch, - SynchDomain) +from sardana.pool.pooldefs import AcqMode, SynchParam, AcqSynch, SynchDomain from sardana.pool.poolgroupelement import PoolGroupElement from sardana.pool.poolacquisition import PoolAcquisition from sardana.pool.poolsynchronization import SynchronizationDescription From 966e654bbe321a471691638d352dadd0fe165c0d Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 26 Oct 2018 11:32:21 +0200 Subject: [PATCH 270/652] Adapt synchronization test to start_action new API --- src/sardana/pool/test/test_synchronization.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/sardana/pool/test/test_synchronization.py b/src/sardana/pool/test/test_synchronization.py index 869a2f5c04..bfddbcbdc9 100644 --- a/src/sardana/pool/test/test_synchronization.py +++ b/src/sardana/pool/test/test_synchronization.py @@ -36,9 +36,9 @@ from sardana.pool.poolsynchronization import PoolSynchronization from sardana.sardanadefs import State from sardana.pool.pooldefs import SynchDomain, SynchParam -from sardana.pool.test import (FakePool, createCtrlConf, createElemConf, - createPoolController, createPoolTriggerGate, - createPoolSynchronizationConfiguration) +from sardana.pool.test import FakePool, createCtrlConf, createElemConf, \ + createPoolController, createPoolTriggerGate, \ + createControllerConfiguration class SynchronizationTestCase(object): @@ -60,10 +60,8 @@ def createElements(self, ctrl_klass, ctrl_lib, ctrl_props): self.pool.add_element(self.tg_ctrl) self.pool.add_element(self.tg_elem) # create Synchronization action and its configuration - self.tg_cfg = createPoolSynchronizationConfiguration( - (self.tg_ctrl,), ((self.tg_elem,),),) - # TODO: The TriggerGate should have a configuration - self.tg_elem.configuration = self.tg_cfg + conf_ctrl = createControllerConfiguration(self.tg_ctrl, [self.tg_elem]) + self.tg_cfg = [conf_ctrl] self.tgaction = PoolSynchronization(self.tg_elem) self.tgaction.add_element(self.tg_elem) @@ -97,7 +95,7 @@ def tggeneration(self, ctrl_lib, ctrl_klass, ctrl_props, # create start_action arguments args = () - kwargs = {'config': self.tg_cfg, + kwargs = {'conf_ctrls': self.tg_cfg, 'synchronization': synchronization } # starting action @@ -145,7 +143,7 @@ def abort_tggeneration(self, ctrl_lib, ctrl_klass, ctrl_props, # create start_action arguments args = () - kwargs = {'config': self.tg_cfg, + kwargs = {'conf_ctrls': self.tg_cfg, 'synchronization': synchronization } # starting action From 03ed3d7dace80a89182bdb987fc07ed0b4f912fb Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 26 Oct 2018 11:34:15 +0200 Subject: [PATCH 271/652] Remove unused helper --- src/sardana/pool/test/helper.py | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index a2889630ed..bfa440ae8c 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -29,7 +29,6 @@ 'createPoolPseudoMotor', 'createPoolMeasurementGroup', 'createControllerConfiguration', 'createTimerableControllerConfiguration', - 'createPoolSynchronizationConfiguration', 'createCTAcquisitionConfiguration', 'createMGConfiguration', 'createElemConf', 'createCtrlConf', 'createConfbyCtrlKlass', 'createMGUserConfiguration'] @@ -170,36 +169,6 @@ def createTimerableControllerConfiguration(pool_ctrl, pool_channels): return conf_ctrl -def createPoolSynchronizationConfiguration(ctrls, ctrl_channels): - '''Method to create PoolSynchronization configuration. Order of the - sequences is important. For all sequences, the element of a given position - refers the same controller. - - :param ctrls: sequence of the controllers used by the action - :type ctrls: seq - :param ctrl_channels: sequence of the sequences of the channels - corresponding to the controllers - :type ctrl_channels: seq> - - :return: a configuration dictionary - :rtype: dict<> - ''' - ctrls_configuration = {} - for ctrl, channels in zip(ctrls, ctrl_channels): - ctrl_data = createConfFromObj(ctrl) - ctrl_data['channels'] = {} - for channel in channels: - channel_conf = createConfFromObj(channel) - ctrl_data['channels'][channel] = channel_conf - ctrls_configuration[ctrl] = ctrl_data - configuration = {'controllers': ctrls_configuration} - - mc = MeasurementConfiguration() - mc._config = configuration - mc.ctrl_tg_sync = ctrls_configuration - return mc - - def createCTAcquisitionConfiguration(ctrls, ctrl_channels): '''Method to create CTAcquisition configuration. Order of the sequences is important. For all sequences, the element of a given position refers From 1cbfda06b185c9c387792548c242ad1cdb6dae86 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Fri, 26 Oct 2018 12:41:57 +0200 Subject: [PATCH 272/652] fix pep8 --- src/sardana/macroserver/scan/gscan.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index 9f349bd063..c04ea1a7e8 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -385,8 +385,9 @@ def _check_moveables_limits(self): low = None for pos in (m.min_value, m.max_value): if pos is None: - self._macro.warning("Macro did not define position for %s. " - "Limit check was not possible." % m.moveable.getName()) + self._macro.warning("Macro did not define position for %s." + " Limit check was not possible." + % m.moveable.getName()) continue if high is not None: if float(pos) > high: From 2d7f594142b8202d5181406c480871a2d3e02e1e Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 26 Oct 2018 15:11:17 +0200 Subject: [PATCH 273/652] Remove unused helper --- src/sardana/pool/test/helper.py | 59 +-------------------------------- 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index bfa440ae8c..257a2e9ecf 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -29,7 +29,7 @@ 'createPoolPseudoMotor', 'createPoolMeasurementGroup', 'createControllerConfiguration', 'createTimerableControllerConfiguration', - 'createCTAcquisitionConfiguration', 'createMGConfiguration', + 'createCTAcquisitionConfiguration', 'createElemConf', 'createCtrlConf', 'createConfbyCtrlKlass', 'createMGUserConfiguration'] import copy @@ -287,63 +287,6 @@ def createMGUserConfiguration(pool, channels): return (MG_configuration, channel_ids, channel_names) -def createMGConfiguration(ctrls, ctrls_conf, ctrl_channels, ctrl_channels_conf, - ctrl_trigger_elements, synchronizations): - '''Method to create general MeasurementGroup (and CT) configuration. - Order of the sequences is important. For all sequences, the element of a - given position refers the same controller. - - :param ctrls: sequence of the controllers used by the action - :type ctrls: seq - :param ctrls_conf: sequence of the controllers configuration dictionaries - :type ctrls_conf: dict - :param ctrl_channels: sequence of the sequences of the channels - corresponding to the controllers - :type ctrl_channels: seq> - :param ctrl_channels_conf: sequence of the sequences of the channels - configuration dictionaries - :type ctrl_channels_conf: seq> - :param trigger_elements: sequence of the sequences of the trigger elements - :type trigger_elements: seq> - :param synchronizations: sequence of the sequences of the synchronizations - :type synchronizations: seq> - :return: a configuration dictionary - :rtype: dict<> - ''' - - synchronizers = [] - master_ctrl_idx = 0 - master_idx = 0 - MG_configuration = {} - ctrls_configuration = {} - MG_configuration['timer'] = ctrl_channels[master_ctrl_idx][master_idx] - MG_configuration['monitor'] = ctrl_channels[master_ctrl_idx][master_idx] - for ctrl, ctrl_data, channels, channels_conf, trigger_elements, \ - trigger_types in zip(ctrls, ctrls_conf, ctrl_channels, - ctrl_channels_conf, ctrl_trigger_elements, synchronizations): - ctrl_data['channels'] = {} - index = 0 - for channel, channel_conf, synchronizer, synchronization in \ - zip(channels, channels_conf, trigger_elements, trigger_types): - ctrl_data['channels'][channel] = channel_conf - # this way we are forcing the synchronization of the last channel - ctrl_data['synchronization'] = synchronization - ctrl_data['synchronizer'] = synchronizer - # TODO: investigate why we need the index! - # adding a dummy index - ctrl_data['channels'][channel]['index'] = index - if synchronizer not in synchronizers: - synchronizers.append(synchronizer) - index += 1 - - ctrl_data['timer'] = channels[master_idx] - ctrl_data['monitor'] = channels[master_idx] - ctrls_configuration[ctrl] = ctrl_data - MG_configuration['controllers'] = ctrls_configuration - - return MG_configuration - - def createConfbyCtrlKlass(pool, ctrl_klass, ctrl_name): pool_mng = pool.get_manager() klass = ctrl_klass From 3c73b9d8f03527d56d9a9b3327a6ab48808c1193 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 26 Oct 2018 10:33:15 +0200 Subject: [PATCH 274/652] Move AttributeListener to util module --- src/sardana/pool/test/__init__.py | 1 + src/sardana/pool/test/helper.py | 1 + src/sardana/pool/test/test_acquisition.py | 50 +------------ .../pool/test/test_measurementgroup.py | 7 +- src/sardana/pool/test/util.py | 75 +++++++++++++++++++ 5 files changed, 81 insertions(+), 53 deletions(-) create mode 100644 src/sardana/pool/test/util.py diff --git a/src/sardana/pool/test/__init__.py b/src/sardana/pool/test/__init__.py index da5894db98..99157d243a 100644 --- a/src/sardana/pool/test/__init__.py +++ b/src/sardana/pool/test/__init__.py @@ -27,6 +27,7 @@ from .fake import * # NOQA from .helper import * # NOQA +from .util import * # NOQA from .dummyconfs import * # NOQA from .base import * # NOQA from .test_acquisition import * # NOQA diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index 257a2e9ecf..dfaa844322 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -33,6 +33,7 @@ 'createElemConf', 'createCtrlConf', 'createConfbyCtrlKlass', 'createMGUserConfiguration'] import copy + from sardana.sardanadefs import ElementType from sardana.pool.poolcontroller import PoolController,\ PoolPseudoMotorController, PoolPseudoCounterController diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index 0cdc1e5452..b34e20675c 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -23,7 +23,6 @@ ## ############################################################################## import time -import numpy import threading from taurus.external.unittest import TestCase @@ -36,53 +35,8 @@ PoolAcquisitionSoftware, PoolAcquisitionSoftwareStart from sardana.sardanathreadpool import get_thread_pool from sardana.pool.test import createControllerConfiguration, \ - createTimerableControllerConfiguration, BasePoolTestCase, FakeElement - - -class AttributeListener(object): - - def __init__(self): - self.data = {} - self.data_lock = threading.RLock() - - def event_received(self, *args, **kwargs): - # s - type: sardana.sardanavalue.SardanaValue - # t - type: sardana.sardanaevent.EventType - # v - type: sardana.sardanaattribute.SardanaAttribute e.g. - # sardana.pool.poolbasechannel.Value - s, t, v = args - if t.name.lower() != "valuebuffer": - return - # obtaining sardana element e.g. exp. channel (the attribute owner) - obj_name = s.name - # obtaining the SardanaValue(s) either from the value_chunk (in case - # of buffered attributes) or from the value in case of normal - # attributes - chunk = v - idx = chunk.keys() - value = [sardana_value.value for sardana_value in chunk.values()] - # filling the measurement records - with self.data_lock: - channel_data = self.data.get(obj_name, []) - expected_idx = len(channel_data) - pad = [None] * (idx[0] - expected_idx) - channel_data.extend(pad + value) - self.data[obj_name] = channel_data - - def get_table(self): - '''Construct a table-like array with padded channel data as columns. - Return the ''' - with self.data_lock: - max_len = max([len(d) for d in self.data.values()]) - dtype_spec = [] - table = [] - for k in sorted(self.data.keys()): - v = self.data[k] - v.extend([None] * (max_len - len(v))) - table.append(v) - dtype_spec.append((k, 'float64')) - a = numpy.array(zip(*table), dtype=dtype_spec) - return a + createTimerableControllerConfiguration, BasePoolTestCase, FakeElement, \ + AttributeListener class AcquisitionTestCase(BasePoolTestCase): diff --git a/src/sardana/pool/test/test_measurementgroup.py b/src/sardana/pool/test/test_measurementgroup.py index c10bd51403..ff3981a9c6 100644 --- a/src/sardana/pool/test/test_measurementgroup.py +++ b/src/sardana/pool/test/test_measurementgroup.py @@ -32,11 +32,8 @@ from sardana.sardanathreadpool import get_thread_pool from sardana.pool import AcqSynchType, AcqMode from sardana.pool.pooldefs import SynchDomain, SynchParam -from sardana.pool.test import (BasePoolTestCase, createPoolMeasurementGroup, - dummyMeasurementGroupConf01, - createMGUserConfiguration) -# TODO Import AttributeListener from the right location. -from sardana.pool.test.test_acquisition import AttributeListener +from sardana.pool.test import BasePoolTestCase, createPoolMeasurementGroup,\ + dummyMeasurementGroupConf01, createMGUserConfiguration class BaseAcquisition(object): diff --git a/src/sardana/pool/test/util.py b/src/sardana/pool/test/util.py new file mode 100644 index 0000000000..1bc68e1c25 --- /dev/null +++ b/src/sardana/pool/test/util.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python + +############################################################################## +## +# This file is part of Sardana +## +# http://www.sardana-controls.org/ +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Sardana 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. +## +# Sardana 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 Sardana. If not, see . +## +############################################################################## + +__all__ = ['AttributeListener'] + +import numpy +import threading + + +class AttributeListener(object): + + def __init__(self): + self.data = {} + self.data_lock = threading.RLock() + + def event_received(self, *args, **kwargs): + # s - type: sardana.sardanavalue.SardanaValue + # t - type: sardana.sardanaevent.EventType + # v - type: sardana.sardanaattribute.SardanaAttribute e.g. + # sardana.pool.poolbasechannel.Value + s, t, v = args + if t.name.lower() != "valuebuffer": + return + # obtaining sardana element e.g. exp. channel (the attribute owner) + obj_name = s.name + # obtaining the SardanaValue(s) either from the value_chunk (in case + # of buffered attributes) or from the value in case of normal + # attributes + chunk = v + idx = chunk.keys() + value = [sardana_value.value for sardana_value in chunk.values()] + # filling the measurement records + with self.data_lock: + channel_data = self.data.get(obj_name, []) + expected_idx = len(channel_data) + pad = [None] * (idx[0] - expected_idx) + channel_data.extend(pad + value) + self.data[obj_name] = channel_data + + def get_table(self): + '''Construct a table-like array with padded channel data as columns. + Return the ''' + with self.data_lock: + max_len = max([len(d) for d in self.data.values()]) + dtype_spec = [] + table = [] + for k in sorted(self.data.keys()): + v = self.data[k] + v.extend([None] * (max_len - len(v))) + table.append(v) + dtype_spec.append((k, 'float64')) + a = numpy.array(zip(*table), dtype=dtype_spec) + return a From 376eb2096c5e09ac08dde41953d0b8e6f0689001 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 26 Oct 2018 15:42:12 +0200 Subject: [PATCH 275/652] (minor) Refactor of measurement group tests --- src/sardana/pool/test/test_measurementgroup.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/sardana/pool/test/test_measurementgroup.py b/src/sardana/pool/test/test_measurementgroup.py index ff3981a9c6..4cbce44c6c 100644 --- a/src/sardana/pool/test/test_measurementgroup.py +++ b/src/sardana/pool/test/test_measurementgroup.py @@ -33,21 +33,18 @@ from sardana.pool import AcqSynchType, AcqMode from sardana.pool.pooldefs import SynchDomain, SynchParam from sardana.pool.test import BasePoolTestCase, createPoolMeasurementGroup,\ - dummyMeasurementGroupConf01, createMGUserConfiguration + dummyMeasurementGroupConf01, createMGUserConfiguration, AttributeListener class BaseAcquisition(object): def setUp(self, pool): - """ - """ self.pool = pool self.pmg = None self.attr_listener = None def prepare_meas(self, config): - """ Prepare the measurement group and returns the channel names - """ + """ Prepare measurement group and returns the channel names""" pool = self.pool # creating mg user configuration and obtaining channel ids mg_conf, channel_ids, channel_names = \ @@ -63,13 +60,13 @@ def prepare_meas(self, config): def prepare_attribute_listener(self): self.attr_listener = AttributeListener() - # Add listeners + # Add data listener attributes = self.pmg.get_user_elements() for attr in attributes: attr.add_listener(self.attr_listener) def remove_attribute_listener(self): - # Remove listeners + # Remove data listener attributes = self.pmg.get_user_elements() for attr in attributes: attr.remove_listener(self.attr_listener) @@ -79,9 +76,8 @@ def acquire(self): """ self.pmg.start_acquisition() acq = self.pmg.acquisition - # waiting for acquisition while acq.is_running(): - time.sleep(1) + time.sleep(.1) def acq_asserts(self, channel_names, repetitions): # printing acquisition records @@ -188,7 +184,7 @@ def meas_cont_acquisition(self, config, synchronization, moveable=None, '(before: %d)') % (jobs_after, jobs_before) self.assertEqual(jobs_before, jobs_after, msg) - def stopAcquisition(self): + def stop_acquisition(self): """Method used to abort a running acquisition""" self.pmg.stop() @@ -207,7 +203,7 @@ def meas_cont_stop_acquisition(self, config, synchronization, acq = self.pmg.acquisition # starting timer (0.05 s) which will stop the acquisiton - threading.Timer(0.2, self.stopAcquisition).start() + threading.Timer(0.2, self.stop_acquisition).start() # waiting for acquisition and tggeneration to be stoped by thread while acq.is_running(): time.sleep(0.05) From cfc5fba5bc615d7a636585ed81e98f42b9f01982 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 26 Oct 2018 15:42:51 +0200 Subject: [PATCH 276/652] Add test to software and hardware start acquisition --- src/sardana/pool/test/helper.py | 2 +- src/sardana/pool/test/test_measurementgroup.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index dfaa844322..72b38ec82b 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -285,7 +285,7 @@ def createMGUserConfiguration(pool, channels): all_ctrls_d.update(ctrl_d) MG_configuration.update({'controllers': all_ctrls_d}) - return (MG_configuration, channel_ids, channel_names) + return MG_configuration, channel_ids, channel_names def createConfbyCtrlKlass(pool, ctrl_klass, ctrl_name): diff --git a/src/sardana/pool/test/test_measurementgroup.py b/src/sardana/pool/test/test_measurementgroup.py index 4cbce44c6c..7c50c3ce77 100644 --- a/src/sardana/pool/test/test_measurementgroup.py +++ b/src/sardana/pool/test/test_measurementgroup.py @@ -336,7 +336,17 @@ def tearDown(self): [('_test_ct_2_1', 'software', AcqSynchType.Trigger), ], [('_test_0d_1_1', 'software', AcqSynchType.Gate), ]] +doc_14 = 'Acquisition using 2 controllers, with 2 channels in each '\ + + 'controller, using software and hardware start synchronization' +config_14 = [[('_test_ct_1_1', 'software', AcqSynchType.Start), + ('_test_ct_1_2', 'software', AcqSynchType.Start)], + [('_test_ct_2_1', '_test_tg_1_1', AcqSynchType.Start), + ('_test_ct_2_2', '_test_tg_1_1', AcqSynchType.Start)]] + + +@insertTest(helper_name='meas_cont_acquisition', test_method_doc=doc_14, + config=config_14, synchronization=synchronization1) @insertTest(helper_name='meas_contpos_acquisition', test_method_doc=doc_12, config=config_12, synchronization=synchronization4, moveable="_test_mot_1_1") From 28c848cb73204c37efd52f921a943792d6a98cd0 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 26 Oct 2018 15:45:51 +0200 Subject: [PATCH 277/652] Add software start acquisition action to super acquisition action --- src/sardana/pool/poolacquisition.py | 40 +++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 453ee13923..12e6be2976 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -83,18 +83,25 @@ def __init__(self, main_element, name="Acquisition"): zerodname = name + ".0DAcquisition" hwname = name + ".HardwareAcquisition" swname = name + ".SoftwareAcquisition" + sw_start_name = name + ".SoftwareStartAcquisition" synchname = name + ".Synchronization" self._sw_acq_config = None + self._sw_start_acq_config = None self._0d_config = None self._0d_acq = Pool0DAcquisition(main_element, name=zerodname) self._sw_acq = PoolAcquisitionSoftware(main_element, name=swname) + self._sw_start_acq = PoolAcquisitionSoftwareStart( + main_element, name=sw_start_name) self._hw_acq = PoolAcquisitionHardware(main_element, name=hwname) self._synch = PoolSynchronization(main_element, name=synchname) def set_sw_config(self, config): self._sw_acq_config = config + def set_sw_start_config(self, config): + self._sw_start_acq_config = config + def set_0d_config(self, config): self._0d_config = config @@ -108,6 +115,14 @@ def event_received(self, *args, **kwargs): t_str = datetime.datetime.fromtimestamp(timestamp).strftime(t_fmt) msg = '%s event with id: %d received at: %s' % (name, value, t_str) self.debug(msg) + if name == "start": + if self._sw_start_acq_config: + self.debug('Executing software start acquisition.') + args = () + kwargs = self._sw_start_acq_config + # TODO: key synch is not used on the code, remove it + kwargs['synch'] = True + get_thread_pool().add(self._sw_start_acq.run, *args, **kwargs) if name == "active": # this code is not thread safe, but for the moment we assume that # only one EventGenerator will work at the same time @@ -203,10 +218,25 @@ def run(self, head, config, multiple, acq_mode, value, synchronization, acq_sync_sw = [AcqSynch.SoftwareGate, AcqSynch.SoftwareTrigger] ctrls_acq_sw = config.get_timerable_ctrls(acq_synch=acq_sync_sw, enabled=True) + ctrls_acq_sw_start = config.get_timerable_ctrls( + acq_synch=AcqSynch.SoftwareStart, enabled=True) ctrls_acq_0d = config.get_zerod_ctrls(enabled=True) - if len(ctrls_acq_sw) or len(ctrls_acq_0d): + if len(ctrls_acq_sw) or len(ctrls_acq_0d) or len(ctrls_acq_sw_start): self._synch.add_listener(self) + if len(ctrls_acq_sw_start): + master = None + if acq_mode is AcqMode.Timer: + master = config.get_master_timer_software_start() + elif acq_mode is AcqMode.Monitor: + master = config.get_master_monitor_software_start() + + sw_acq_kwargs = dict(conf_ctrls=ctrls_acq_sw_start, + value=value, + repetitions=repetitions, + latency_time=latency_time, + master=master) + self.set_sw_start_config(sw_acq_kwargs) if len(ctrls_acq_sw): master = None if acq_mode is AcqMode.Timer: @@ -239,12 +269,12 @@ def _get_action_for_element(self, element): if acq_synch in (AcqSynch.SoftwareTrigger, AcqSynch.SoftwareGate): return self._sw_acq + elif acq_synch == AcqSynch.SoftwareStart: + return self._sw_start_acq elif acq_synch in (AcqSynch.HardwareTrigger, - AcqSynch.HardwareGate): + AcqSynch.HardwareGate, + AcqSynch.HardwareStart): return self._hw_acq - else: - # by default software synchronization is in use - return self._sw_acq elif elem_type == ElementType.ZeroDExpChannel: return self._0d_acq elif elem_type == ElementType.TriggerGate: From 8e3140749aa07ba734cc29a9e5f936080c7dac69 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 26 Oct 2018 16:41:35 +0200 Subject: [PATCH 278/652] Add defaults values for measurement configuration keys --- src/sardana/pool/poolmeasurementgroup.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 2c70a52395..5c560d0eed 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -43,7 +43,9 @@ from sardana import State, ElementType, \ TYPE_EXP_CHANNEL_ELEMENTS from sardana.sardanaevent import EventType -from sardana.pool.pooldefs import AcqMode, SynchParam, AcqSynch, SynchDomain +from sardana.pool.pooldefs import AcqMode, SynchParam, AcqSynch, \ + SynchDomain, AcqSynchType + from sardana.pool.poolgroupelement import PoolGroupElement from sardana.pool.poolacquisition import PoolAcquisition from sardana.pool.poolsynchronization import SynchronizationDescription @@ -398,7 +400,7 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): "configuration in order to upgrade.") self._parent.warning(msg) except KeyError: - synchronization = None + synchronization = AcqSynchType.Trigger ctrl_conf['synchronization'] = synchronization user_config_ctrl['synchronization'] = synchronization @@ -526,6 +528,7 @@ def _fill_channel_data(self, channel, channel_data): name = channel.name full_name = channel.full_name + ctrl_name = channel.controller.full_name source = channel.get_source() ndim = None ctype = channel.get_type() @@ -548,7 +551,7 @@ def _fill_channel_data(self, channel, channel_data): # Definitively should be initialized by measurement group # index MUST be here already (asserting this in the following line) - channel_data['index'] = channel_data.get('index', None) + channel_data['index'] = channel_data['index'] channel_data['name'] = channel_data.get('name', name) channel_data['full_name'] = channel_data.get('full_name', full_name) channel_data['source'] = channel_data.get('source', source) @@ -565,11 +568,12 @@ def _fill_channel_data(self, channel, channel_data): channel_data['normalization'] = channel_data.get('normalization', Normalization.No) # TODO use real values - channel_data['data_type'] = channel_data.get('data_type', None) - channel_data['data_units'] = channel_data.get('data_units', None) + channel_data['data_type'] = channel_data.get('data_type', 'float64') + channel_data['data_units'] = channel_data.get('data_units', 'No unit') channel_data['nexus_path'] = channel_data.get('nexus_path', '') channel_data['shape'] = channel_data.get('shape', []) - + channel_data['_controller_name'] = channel_data.get('_controller_name', + ctrl_name) return channel_data From 5438e095cb944a47bc77d602f0b48a508db5a160 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Fri, 26 Oct 2018 16:42:02 +0200 Subject: [PATCH 279/652] Remove not mandatory keys from the configuration helper --- src/sardana/pool/test/helper.py | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index 257a2e9ecf..f4d0dd759a 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -257,27 +257,10 @@ def createMGUserConfiguration(pool, channels): channel_element = pool.get_element_by_full_name(channel_name_str) channel_ids.append(channel_element.id) one_channel_d = {} - one_channel_d.update({'plot_type': 1}) - one_channel_d.update({'plot_axes': ['']}) - one_channel_d.update({'data_type': 'float64'}) - one_channel_d.update({'index': index}) - one_channel_d.update({'enabled': True}) - one_channel_d.update({'nexus_path': ''}) - one_channel_d.update({'shape': []}) - ctrl_from_channel = channel_element.get_controller() - ctrl_name = ctrl_from_channel.full_name - one_channel_d.update({'_controller_name': ctrl_name}) - one_channel_d.update({'conditioning': ''}) one_channel_d.update({'full_name': channel_name_str}) - one_channel_d.update({'id': channel_element.id}) - one_channel_d.update({'normalization': 0}) - one_channel_d.update({'output': True}) - one_channel_d.update({'label': channel_element.name}) - one_channel_d.update({'data_units': 'No unit'}) - one_channel_d.update({'name': channel_element.name}) + one_channel_d.update({'index': index}) channels_d.update({channel_name_str: one_channel_d}) index += 1 - ctrl_data['channels'] = {} ctrl_data['channels'].update(channels_d) ctrl_d[ctrl_full_name] = ctrl_data From 9383df7a59814a7cb934f7b5978d091db8553451 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 26 Oct 2018 16:50:46 +0200 Subject: [PATCH 280/652] Select master timer/monitor for software start acquisition --- src/sardana/pool/poolmeasurementgroup.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 5c560d0eed..778e0d1a64 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -321,6 +321,8 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): master_monitor = None master_timer_idx_sw = float("+inf") master_monitor_idx_sw = float("+inf") + master_timer_idx_sw_start = float("+inf") + master_monitor_idx_sw_start = float("+inf") user_elem_ids = {} channel_acq_synch = {} ctrl_acq_synch = {} @@ -480,13 +482,21 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): timerable_ctrls[acq_synch].append(ctrl_item) # Find master timer/monitor the system take the channel with # less index - if ctrl_item.synchronizer == 'software': + if acq_synch in (AcqSynch.SoftwareTrigger, + AcqSynch.SoftwareGate): if ctrl_item.timer.index < master_timer_idx_sw: master_timer_sw = ctrl_item.timer master_timer_idx_sw = ctrl_item.timer.index if ctrl_item.monitor.index < master_monitor_idx_sw: master_monitor_sw = ctrl_item.monitor master_monitor_idx_sw = ctrl_item.monitor.index + elif acq_synch == AcqSynch.SoftwareStart: + if ctrl_item.timer.index < master_timer_idx_sw_start: + master_timer_sw_start = ctrl_item.timer + master_timer_idx_sw_start = ctrl_item.timer.index + if ctrl_item.monitor.index < master_monitor_idx_sw_start: + master_monitor_sw_start = ctrl_item.monitor + master_monitor_idx_sw_start = ctrl_item.monitor.index elif ctrl.get_ctrl_types()[0] == ElementType.ZeroDExpChannel: zerod_ctrls.append(ctrl_item) else: From ba477129a087b4f686f4f6ee0af63b489972d57c Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 26 Oct 2018 18:19:02 +0200 Subject: [PATCH 281/652] Start refactoring of acquisition action --- src/sardana/pool/poolacquisition.py | 96 ++++++++++++++++++----------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 12e6be2976..935901352b 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -32,6 +32,7 @@ __docformat__ = 'restructuredtext' import time +import weakref import datetime from taurus.core.util.log import DebugIt @@ -76,6 +77,35 @@ def is_value_error(value): return False +class ActionArgs(object): + + def __init__(self, args, kwargs=None): + self.args = args + if kwargs is None: + kwargs = {} + self.kwargs = kwargs + + +class CtrlActionItem(object): + + def __init__(self, element, master=None): + self._element = weakref.ref(element) + self.master = master + + def __getattr__(self, item): + return getattr(self.element, item) + + def get_element(self): + """Returns the element associated with this item""" + return self._element() + + def set_element(self, element): + """Sets the element for this item""" + self._element = weakref.ref(element) + + element = property(get_element) + + class PoolAcquisition(PoolAction): def __init__(self, main_element, name="Acquisition"): @@ -83,28 +113,22 @@ def __init__(self, main_element, name="Acquisition"): zerodname = name + ".0DAcquisition" hwname = name + ".HardwareAcquisition" swname = name + ".SoftwareAcquisition" - sw_start_name = name + ".SoftwareStartAcquisition" + sw_start_name = name + ".SoftwareStartAcquisition" synchname = name + ".Synchronization" - self._sw_acq_config = None - self._sw_start_acq_config = None - self._0d_config = None - self._0d_acq = Pool0DAcquisition(main_element, name=zerodname) + self._sw_acq_args = None + self._sw_start_acq_args = None + self._0d_acq_args = None + self._hw_acq_args = None + self._synch_args = None + self._sw_acq = PoolAcquisitionSoftware(main_element, name=swname) self._sw_start_acq = PoolAcquisitionSoftwareStart( main_element, name=sw_start_name) + self._0d_acq = Pool0DAcquisition(main_element, name=zerodname) self._hw_acq = PoolAcquisitionHardware(main_element, name=hwname) self._synch = PoolSynchronization(main_element, name=synchname) - def set_sw_config(self, config): - self._sw_acq_config = config - - def set_sw_start_config(self, config): - self._sw_start_acq_config = config - - def set_0d_config(self, config): - self._0d_config = config - def event_received(self, *args, **kwargs): timestamp = time.time() _, type_, value = args @@ -116,17 +140,15 @@ def event_received(self, *args, **kwargs): msg = '%s event with id: %d received at: %s' % (name, value, t_str) self.debug(msg) if name == "start": - if self._sw_start_acq_config: + if self._sw_start_acq_args is not None: self.debug('Executing software start acquisition.') - args = () - kwargs = self._sw_start_acq_config - # TODO: key synch is not used on the code, remove it - kwargs['synch'] = True - get_thread_pool().add(self._sw_start_acq.run, *args, **kwargs) - if name == "active": + get_thread_pool().add(self._sw_start_acq.run, + *self._sw_start_acq_args.args, + **self._sw_start_acq_args.kwargs) + elif name == "active": # this code is not thread safe, but for the moment we assume that # only one EventGenerator will work at the same time - if self._sw_acq_config: + if self._sw_acq_args is not None: if self._sw_acq._is_started() or self._sw_acq.is_running(): msg = ('Skipping trigger: software acquisition is still' ' in progress.') @@ -134,14 +156,12 @@ def event_received(self, *args, **kwargs): return else: self.debug('Executing software acquisition.') - args = () - kwargs = self._sw_acq_config - # TODO: key synch is not used on the code, remove it - kwargs['synch'] = True - kwargs['index'] = value + self._sw_acq_args.kwargs.update({'index': value}) self._sw_acq._started = True - get_thread_pool().add(self._sw_acq.run, *args, **kwargs) - if self._0d_config: + get_thread_pool().add(self._sw_acq.run, + *self._sw_acq_args.args, + **self._sw_acq_args.kwargs) + if self._0d_acq_args is not None: if self._0d_acq._is_started() or self._0d_acq.is_running(): msg = ('Skipping trigger: ZeroD acquisition is still in' ' progress.') @@ -149,24 +169,26 @@ def event_received(self, *args, **kwargs): return else: self.debug('Executing ZeroD acquisition.') - args = () - kwargs = self._0d_config - # TODO: key synch is not used on the code, remove it - kwargs['synch'] = True - kwargs['index'] = value + self._0d_acq_args.kwargs.update({'index': value}) self._0d_acq._started = True self._0d_acq._stopped = False self._0d_acq._aborted = False - get_thread_pool().add(self._0d_acq.run, *args, **kwargs) + get_thread_pool().add(self._0d_acq.run, + *self._0d_acq_args.args, + **self._0d_acq_args.kwargs) elif name == "passive": - if self._0d_config and (self._0d_acq._is_started() or - self._0d_acq.is_running()): + # TODO: _0d_acq_args comparison may not be necessary + if (self._0d_acq_args is not None + and (self._0d_acq._is_started() + or self._0d_acq.is_running())): self.debug('Stopping ZeroD acquisition.') self._0d_acq.stop_action() def prepare(self, ctrl_lodeable, value, repetitions, latency, nr_of_starts): """Prepare measurement.""" + # TODO: set synch to true for software, software start and 0D acq + # kwargs['synch'] = True for conf_ctrl, lodeable in ctrl_lodeable.items(): axis = lodeable.axis From 43c059d8fcf9b990c23add504af87962b7a3d7b0 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 29 Oct 2018 17:20:28 +0100 Subject: [PATCH 282/652] Fix ParamDecode with repeat params with one member and one repetition --- src/sardana/macroserver/msparameter.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sardana/macroserver/msparameter.py b/src/sardana/macroserver/msparameter.py index 0d75e69e1c..ca34c56c8b 100644 --- a/src/sardana/macroserver/msparameter.py +++ b/src/sardana/macroserver/msparameter.py @@ -39,6 +39,7 @@ from taurus.core.util.containers import CaselessDict from sardana import ElementType, INTERFACES_EXPANDED +from sardana.sardanautils import is_non_str_seq from sardana.macroserver.msbase import MSBaseObject from sardana.macroserver.msexception import MacroServerException, \ UnknownMacro, UnknownMacroLibrary @@ -469,6 +470,10 @@ def decodeRepeat(self, raw_param_repeat, param_repeat_def): msg = 'Found %d repetitions of param %s, max is %d' % \ (len_rep, name, max_rep) raise SupernumeraryRepeat, msg + # repeat params with only one member and only one repetition value are + # allowed - encapsulate it in list and try to decode anyway + if not is_non_str_seq(raw_param_repeat): + raw_param_repeat = [raw_param_repeat] for raw_repeat in raw_param_repeat: if len(param_type) > 1: repeat = [] From 4f2edcf9318d7bb71d50b85fa358e77512ea66e4 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Tue, 30 Oct 2018 08:24:11 +0100 Subject: [PATCH 283/652] fix documentation error --- src/sardana/macroserver/macro.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/macroserver/macro.py b/src/sardana/macroserver/macro.py index 2e0e88b025..6e063bab2e 100644 --- a/src/sardana/macroserver/macro.py +++ b/src/sardana/macroserver/macro.py @@ -1186,7 +1186,7 @@ def prepareMacro(self, *args, **kwargs): self.execMacro('mv', th, 0) # backwards compatibility - see note # a sequence of parameters: - self.execMacro(['ascan', 'th', '0', '100', '10', '1.0') + self.execMacro(['ascan', 'th', '0', '100', '10', '1.0']) self.execMacro(['mv', [[motor.getName(), '0']]]) self.execMacro(['mv', motor.getName(), '0']) # backwards compatibility - see note self.execMacro(('ascan', 'th', 0, 100, 10, 1.0)) From f679bcd0bd134805c44311c4669beaf2bb53f1ca Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Tue, 30 Oct 2018 08:25:19 +0100 Subject: [PATCH 284/652] Improve Unittest --- .../macroserver/test/res/macros/testmacros.py | 119 ++++++++++++++++-- 1 file changed, 112 insertions(+), 7 deletions(-) diff --git a/src/sardana/macroserver/test/res/macros/testmacros.py b/src/sardana/macroserver/test/res/macros/testmacros.py index 5f23ceaf87..7b49332b43 100644 --- a/src/sardana/macroserver/test/res/macros/testmacros.py +++ b/src/sardana/macroserver/test/res/macros/testmacros.py @@ -1,29 +1,116 @@ from sardana.macroserver.macro import Type, Macro +MSG_TEMP = "Parsing failed (result: %r; expected: %r)" + class runMacro(Macro): def run(self, *args): - macro, _ = self.prepareMacro("testParamMacros1", 99, [1, 2]) + + expect_params = (99, [1., 2.]) + macro, _ = self.prepareMacro("testParamMacros1", *expect_params) self.runMacro(macro) - macro, _ = self.prepareMacro("testParamMacros1", 99, 1, 2) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg + + params = (99, 1., 2.) + macro, _ = self.prepareMacro("testParamMacros1", *params) + expect_params = (99, [1., 2.]) self.runMacro(macro) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg + + expect_params = ([92], True) + macro, _ = self.prepareMacro("testParamsFirstRepeat", *expect_params) + self.runMacro(macro) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg + + params = (91, True) + expect_params = ([91], True) + macro, _ = self.prepareMacro("testParamsFirstRepeat", *params) + self.runMacro(macro) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg class createMacro(Macro): def run(self, *args): - macro, pars = self.createMacro('testParamMacros1', 99, 1, 3) + + expect_params = (99, [1., 2.]) + macro, pars = self.createMacro('testParamMacros1', *expect_params) + self.runMacro(macro) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg + + params = (99, 1., 2.) + expect_params = (99, [1., 2.]) + self.runMacro(macro) + macro, pars = self.createMacro('testParamMacros1', *params) self.runMacro(macro) - macro, pars = self.createMacro('testParamMacros1', 99, [1, 3]) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg + + expect_params = ([92], True) + macro, _ = self.createMacro("testParamsFirstRepeat", *expect_params) + self.runMacro(macro) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg + + params = (91, True) + expect_params = ([91.], True) + macro, _ = self.createMacro("testParamsFirstRepeat", *params) self.runMacro(macro) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg class execMacro(Macro): def run(self, *args): - self.execMacro('testParamMacros1 99 [1 3]') - self.execMacro('testParamMacros1', '99', '1', '3') + + expect_params = (99, [1., 2.]) + macro = self.execMacro('testParamMacros1', *expect_params) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg + + params = (99, 1., 2.) + macro = self.execMacro('testParamMacros1', *params) + result = macro.data + expect_params = (99, [1., 2.]) + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg + + expect_params = ([92], True) + macro = self.execMacro('testParamsFirstRepeat', *expect_params) + self.runMacro(macro) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg + + expect_params = ([99.], True) + macro = self.execMacro("testParamsFirstRepeat [99] True") + self.runMacro(macro) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg + + expect_params = ([999.], True) + macro = self.execMacro("testParamsFirstRepeat", 999, True) + self.runMacro(macro) + result = macro.data + msg = MSG_TEMP % (result, expect_params) + assert expect_params == result, msg class testParamMacros1(Macro): @@ -35,9 +122,27 @@ class testParamMacros1(Macro): param_def = [ ['val1', Type.Float, None, 'value 1'], + ['numb_list', [['pos', Type.Float, None, 'value']], None, + 'List of values'], + ] + + def run(self, *args, **kwargs): + self.data = args + + +class testParamsFirstRepeat(Macro): + """Macro with a motor parameter followed by a list of numbers. + Usages from Spock, ex.: + pt5 99 [1 3] + pt5 99 1 3 + """ + + param_def = [ + ['numb_list', [['pos', Type.Float, None, 'value']], None, 'List of ' 'values'], + ['val1', Type.Boolean, None, 'value 1'], ] def run(self, *args, **kwargs): - print args + self.data = args From 367534cdb02c28e09afa7892e9f9a85505b0769d Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 30 Oct 2018 10:04:38 +0100 Subject: [PATCH 285/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dbda64311..a273424bd0 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ This file follows the formats and conventions from [keepachangelog.com] code are coherent (#936) - Macro/controller module description when module does not have a docstring (#945) +- Make cleanup (remove configuration) if spock profile creation was interrupted + or failed (#791, #793) ### Changed - Move pre-scan and post-scan hooks out of `scan_loop` method (#920, #922, From d4fceb0da350b7abc8bd193b95e4cc7a0a9dd62f Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 30 Oct 2018 12:24:49 +0100 Subject: [PATCH 286/652] Allow the dynamic attribute creation on PoolActionItem Update the wrapper attributes by using a configuration dict on the class initialization. Access to the element attributes from the wrapper. --- src/sardana/pool/poolaction.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sardana/pool/poolaction.py b/src/sardana/pool/poolaction.py index 2a20c406e3..432a9ada9a 100644 --- a/src/sardana/pool/poolaction.py +++ b/src/sardana/pool/poolaction.py @@ -52,8 +52,13 @@ class PoolActionItem(object): """The base class for an atomic action item""" - def __init__(self, element): + def __init__(self, element, config=None): self._element = weakref.ref(element) + if config is not None: + self.__dict__.update(config) + + def __getattr__(self, item): + return getattr(self.element, item) def get_element(self): """Returns the element associated with this item""" From f66dcdb3b21c7a4f458863c40bce81074d73fa65 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 30 Oct 2018 14:44:20 +0100 Subject: [PATCH 287/652] Fix typo mistake --- src/sardana/pool/poolmeasurementgroup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 778e0d1a64..be1edac744 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -186,7 +186,7 @@ def update_state(self): def get_channels(self, enabled=None): if enabled is None: - return list(self.channels) + return list(self._channels) elif enabled: return list(self._channels_enabled) else: From ed70375d5ba3629a8c4262358300a6ba90967e99 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 30 Oct 2018 14:45:39 +0100 Subject: [PATCH 288/652] Add changed attribute to MeasurementConfiguration --- src/sardana/pool/poolmeasurementgroup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index be1edac744..ea2e0fba48 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -237,6 +237,7 @@ def __init__(self, parent=None): self._user_confg = {} self._channel_acq_synch = {} self._ctrl_acq_synch = {} + self.changed = False def get_acq_synch_by_channel(self, element): if isinstance(element, ConfigurationItem): @@ -531,6 +532,8 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): user_elem_ids_list.append(conf_synch.id) self._parent.set_user_element_ids(user_elem_ids_list) + self.changed = True + def _fill_channel_data(self, channel, channel_data): """ Fills the channel default values for the given channel dictionary From caa18e474c08f9237bb1080bbfda6c39244b4ff4 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 30 Oct 2018 15:05:16 +0100 Subject: [PATCH 289/652] Use PoolActionController instead of CtrlActionItem --- src/sardana/pool/poolacquisition.py | 32 +++++++++++++---------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 935901352b..e685dde1ef 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -86,24 +86,20 @@ def __init__(self, args, kwargs=None): self.kwargs = kwargs -class CtrlActionItem(object): - - def __init__(self, element, master=None): - self._element = weakref.ref(element) - self.master = master - - def __getattr__(self, item): - return getattr(self.element, item) - - def get_element(self): - """Returns the element associated with this item""" - return self._element() - - def set_element(self, element): - """Sets the element for this item""" - self._element = weakref.ref(element) - - element = property(get_element) +class PoolActionController(PoolActionItem): + def __init__(self, element, config=None): + self._channels = [] + self._channels_enabled = [] + self._channels_disabled = [] + ch_config = {'controller': self} + for conf_channel in element._channels: + action_channel = PoolActionItem(conf_channel, ch_config) + self._channels.append(action_channel) + if conf_channel in element._channels_enabled: + self._channels_enabled.append(action_channel) + if conf_channel in element._channels_disabled: + self._channels_disabled.append(action_channel) + PoolActionItem.__init__(self, element, config) class PoolAcquisition(PoolAction): From 00e92c4a9efdf728019352cf7a065b212b587c37 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 30 Oct 2018 15:15:42 +0100 Subject: [PATCH 290/652] Fix error on adding jobs --- src/sardana/pool/poolacquisition.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index e685dde1ef..f38392db27 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -138,7 +138,7 @@ def event_received(self, *args, **kwargs): if name == "start": if self._sw_start_acq_args is not None: self.debug('Executing software start acquisition.') - get_thread_pool().add(self._sw_start_acq.run, + get_thread_pool().add(self._sw_start_acq.run, None, *self._sw_start_acq_args.args, **self._sw_start_acq_args.kwargs) elif name == "active": @@ -154,7 +154,7 @@ def event_received(self, *args, **kwargs): self.debug('Executing software acquisition.') self._sw_acq_args.kwargs.update({'index': value}) self._sw_acq._started = True - get_thread_pool().add(self._sw_acq.run, + get_thread_pool().add(self._sw_acq.run, None, *self._sw_acq_args.args, **self._sw_acq_args.kwargs) if self._0d_acq_args is not None: @@ -169,7 +169,7 @@ def event_received(self, *args, **kwargs): self._0d_acq._started = True self._0d_acq._stopped = False self._0d_acq._aborted = False - get_thread_pool().add(self._0d_acq.run, + get_thread_pool().add(self._0d_acq.run, None, *self._0d_acq_args.args, **self._0d_acq_args.kwargs) elif name == "passive": From 0c13e55ec8bcebfea8720270e977510766c51bc9 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 30 Oct 2018 15:30:47 +0100 Subject: [PATCH 291/652] Move configuration loading to the action prepare --- src/sardana/pool/poolmeasurementgroup.py | 29 ------------------------ 1 file changed, 29 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index ea2e0fba48..4542bf92ec 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -698,35 +698,6 @@ def set_configuration_from_user(self, cfg, propagate=1, to_fqdn=True): def get_user_configuration(self): return self._config.get_configuration_for_user() - def load_configuration(self, force=False): - """Loads the current configuration to all involved controllers""" - - # g_timer, g_monitor = cfg['timer'], cfg['monitor'] - - for ctrl_item in self._config.get_timerable_ctrls(enabled=True): - ctrl = ctrl_item.element - if not ctrl.is_online(): - continue - - ctrl.set_ctrl_par('acquisition_mode', self.acquisition_mode) - # @TODO: fix optimization and enable it again - if ctrl.operator == self and not force and not self._config_dirty: - continue - ctrl.operator = self - # ctrl_data = self._config.configuration['controllers'][ctrl] - # # if ctrl == g_timer.controller: - # # ctrl.set_ctrl_par('timer', g_timer.axis) - # # if ctrl == g_monitor.controller: - # # ctrl.set_ctrl_par('monitor', g_monitor.axis) - ctrl.set_ctrl_par('timer', ctrl_item.timer.axis) - ctrl.set_ctrl_par('monitor', ctrl_item.monitor.axis) - synchronization = self._config.get_acq_synch_by_controller(ctrl) - self.debug('load_configuration: setting trigger_type: %s ' - 'to ctrl: %s' % (synchronization, ctrl)) - ctrl.set_ctrl_par('synchronization', synchronization) - - self._config_dirty = False - def get_timer(self): # TODO: Adapt to the new future MeasurementConfiguration API return self._config._master_timer From 2b34c560d49cfd85ea0f84df08dc0bf57ab50fcc Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Tue, 30 Oct 2018 15:31:28 +0100 Subject: [PATCH 292/652] Adapt to use the action prepare --- src/sardana/pool/poolmeasurementgroup.py | 58 ++++++------------------ 1 file changed, 14 insertions(+), 44 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 4542bf92ec..7f001c832a 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -863,27 +863,21 @@ def set_nr_of_starts(self, nr_of_starts, propagate=1): # acquisition # ------------------------------------------------------------------------- - def prepare(self): - # load configuration into controller(s) if necessary - self.load_configuration() - conf_ctrls = self.configuration.get_timerable_ctrls(enabled=True) - ctrl_lodeable = {} - for conf_ctrl in conf_ctrls: - if self.acquisition_mode == AcqMode.Timer: - lodeable = conf_ctrl.timer - elif self.acquisition_mode == AcqMode.Monitor: - lodeable = conf_ctrl.monitor - else: - continue - ctrl_lodeable[conf_ctrl] = lodeable - + def prepare(self, multiple=1): value = self._get_value() - repetitions = self.synchronization.repetitions - latency = self.synchronization.passive_time self._pending_starts = self.nr_of_starts - self.acquisition.prepare(ctrl_lodeable, value, repetitions, - latency, self.nr_of_starts) + kwargs = {'head': self, + 'multiple': multiple} + + self.acquisition.prepare(self.configuration, + self.acquisition_mode, + value, + self._synchronization, + self._moveable_obj, + self.sw_synch_initial_domain, + self.nr_of_starts, + **kwargs) def start_acquisition(self, value=None, multiple=1): if self._pending_starts == 0: @@ -894,37 +888,13 @@ def start_acquisition(self, value=None, multiple=1): nr_of_starts = self.nr_of_starts self.set_nr_of_starts(1, propagate=0) try: - self.prepare() + self.prepare(multiple) finally: self.set_nr_of_starts(nr_of_starts, propagate=0) self._aborted = False self._pending_starts -= 1 if not self._simulation_mode: - # determining the acquisition parameters - value = self._get_value() - - self.acquisition.run( - head=self, - config=self._config, - multiple=multiple, - acq_mode=self.acquisition_mode, - value=value, - synchronization=self._synchronization, - moveable=self._moveable_obj, - sw_synch_initial_domain=self.sw_synch_initial_domain) - - # - # kwargs = dict(head=self, config=self._config, multiple=multiple) - # acquisition_mode = self.acquisition_mode - # if acquisition_mode is AcqMode.Timer: - # kwargs['integ_time'] = self.get_integration_time() - # elif acquisition_mode is AcqMode.Monitor: - # kwargs['monitor'] = self._monitor - # kwargs['synchronization'] = self._synchronization - # kwargs['moveable'] = self._moveable_obj - # kwargs['sw_synch_initial_domain'] = self._sw_synch_initial_domain - # # start acquisition - # self.acquisition.run(**kwargs) + self.acquisition.run() def _get_value(self): if self._acquisition_mode is AcqMode.Timer: From 6842211e923af4b6c9b901a7e0615ed966d06fe9 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Tue, 30 Oct 2018 16:12:38 +0100 Subject: [PATCH 293/652] Renamed macros and docstring --- .../macroserver/test/res/macros/testmacros.py | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/sardana/macroserver/test/res/macros/testmacros.py b/src/sardana/macroserver/test/res/macros/testmacros.py index 7b49332b43..4725121ed4 100644 --- a/src/sardana/macroserver/test/res/macros/testmacros.py +++ b/src/sardana/macroserver/test/res/macros/testmacros.py @@ -8,14 +8,14 @@ class runMacro(Macro): def run(self, *args): expect_params = (99, [1., 2.]) - macro, _ = self.prepareMacro("testParamMacros1", *expect_params) + macro, _ = self.prepareMacro("pt6_base", *expect_params) self.runMacro(macro) result = macro.data msg = MSG_TEMP % (result, expect_params) assert expect_params == result, msg params = (99, 1., 2.) - macro, _ = self.prepareMacro("testParamMacros1", *params) + macro, _ = self.prepareMacro("pt6_base", *params) expect_params = (99, [1., 2.]) self.runMacro(macro) result = macro.data @@ -23,7 +23,7 @@ def run(self, *args): assert expect_params == result, msg expect_params = ([92], True) - macro, _ = self.prepareMacro("testParamsFirstRepeat", *expect_params) + macro, _ = self.prepareMacro("pt10_base", *expect_params) self.runMacro(macro) result = macro.data msg = MSG_TEMP % (result, expect_params) @@ -31,7 +31,7 @@ def run(self, *args): params = (91, True) expect_params = ([91], True) - macro, _ = self.prepareMacro("testParamsFirstRepeat", *params) + macro, _ = self.prepareMacro("pt10_base", *params) self.runMacro(macro) result = macro.data msg = MSG_TEMP % (result, expect_params) @@ -43,7 +43,7 @@ class createMacro(Macro): def run(self, *args): expect_params = (99, [1., 2.]) - macro, pars = self.createMacro('testParamMacros1', *expect_params) + macro, pars = self.createMacro('pt6_base', *expect_params) self.runMacro(macro) result = macro.data msg = MSG_TEMP % (result, expect_params) @@ -52,14 +52,14 @@ def run(self, *args): params = (99, 1., 2.) expect_params = (99, [1., 2.]) self.runMacro(macro) - macro, pars = self.createMacro('testParamMacros1', *params) + macro, pars = self.createMacro('pt6_base', *params) self.runMacro(macro) result = macro.data msg = MSG_TEMP % (result, expect_params) assert expect_params == result, msg expect_params = ([92], True) - macro, _ = self.createMacro("testParamsFirstRepeat", *expect_params) + macro, _ = self.createMacro("pt10_base", *expect_params) self.runMacro(macro) result = macro.data msg = MSG_TEMP % (result, expect_params) @@ -67,7 +67,7 @@ def run(self, *args): params = (91, True) expect_params = ([91.], True) - macro, _ = self.createMacro("testParamsFirstRepeat", *params) + macro, _ = self.createMacro("pt10_base", *params) self.runMacro(macro) result = macro.data msg = MSG_TEMP % (result, expect_params) @@ -79,45 +79,45 @@ class execMacro(Macro): def run(self, *args): expect_params = (99, [1., 2.]) - macro = self.execMacro('testParamMacros1', *expect_params) + macro = self.execMacro('pt6_base', *expect_params) result = macro.data msg = MSG_TEMP % (result, expect_params) assert expect_params == result, msg params = (99, 1., 2.) - macro = self.execMacro('testParamMacros1', *params) + macro = self.execMacro('pt6_base', *params) result = macro.data expect_params = (99, [1., 2.]) msg = MSG_TEMP % (result, expect_params) assert expect_params == result, msg expect_params = ([92], True) - macro = self.execMacro('testParamsFirstRepeat', *expect_params) + macro = self.execMacro('pt10_base', *expect_params) self.runMacro(macro) result = macro.data msg = MSG_TEMP % (result, expect_params) assert expect_params == result, msg expect_params = ([99.], True) - macro = self.execMacro("testParamsFirstRepeat [99] True") + macro = self.execMacro("pt10_base [99] True") self.runMacro(macro) result = macro.data msg = MSG_TEMP % (result, expect_params) assert expect_params == result, msg expect_params = ([999.], True) - macro = self.execMacro("testParamsFirstRepeat", 999, True) + macro = self.execMacro("pt10_base", 999, True) self.runMacro(macro) result = macro.data msg = MSG_TEMP % (result, expect_params) assert expect_params == result, msg -class testParamMacros1(Macro): - """Macro with a motor parameter followed by a list of numbers. +class pt6_base(Macro): + """Macro with a number parameter followed by a list of numbers. Usages from Spock, ex.: - pt5 99 [1 3] - pt5 99 1 3 + pt6_base 99 [1 3] + pt6_base 99 1 3 """ param_def = [ @@ -130,17 +130,17 @@ def run(self, *args, **kwargs): self.data = args -class testParamsFirstRepeat(Macro): - """Macro with a motor parameter followed by a list of numbers. +class pt10_base(Macro): + """Macro with a list of numbers followed by a number parameter. Usages from Spock, ex.: - pt5 99 [1 3] - pt5 99 1 3 + pt10_base 99 [1 3] + pt10_base 99 1 3 """ param_def = [ - ['numb_list', [['pos', Type.Float, None, 'value']], None, 'List of ' - 'values'], + ['numb_list', [['pos', Type.Float, None, 'value']], None, + 'List of values'], ['val1', Type.Boolean, None, 'value 1'], ] From 6923430d779d98e034b2f19930d42d0e6d6e5185 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Wed, 31 Oct 2018 10:55:28 +0100 Subject: [PATCH 294/652] Modify macros DocString --- .../macroserver/test/res/macros/testmacros.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/sardana/macroserver/test/res/macros/testmacros.py b/src/sardana/macroserver/test/res/macros/testmacros.py index 4725121ed4..855a151b51 100644 --- a/src/sardana/macroserver/test/res/macros/testmacros.py +++ b/src/sardana/macroserver/test/res/macros/testmacros.py @@ -4,7 +4,10 @@ class runMacro(Macro): - + """ + Macro to test the parameters parsing/decoding using the macro API, + 'runMacro' + """ def run(self, *args): expect_params = (99, [1., 2.]) @@ -39,7 +42,10 @@ def run(self, *args): class createMacro(Macro): - + """ + Macro to test the parameters parsing/decoding using the macro API, + 'createMacro' + """ def run(self, *args): expect_params = (99, [1., 2.]) @@ -75,7 +81,10 @@ def run(self, *args): class execMacro(Macro): - + """ + Macro to test the parameters parsing/decoding using the macro API, + 'execMacro' + """ def run(self, *args): expect_params = (99, [1., 2.]) @@ -131,10 +140,10 @@ def run(self, *args, **kwargs): class pt10_base(Macro): - """Macro with a list of numbers followed by a number parameter. + """Macro with a list of numbers followed by a boolean parameter. Usages from Spock, ex.: - pt10_base 99 [1 3] - pt10_base 99 1 3 + pt10_base [1] True + pt10_base 1 True """ param_def = [ From b31a5be9ebfbb9d9d5226dc0ab3e395cc52468c2 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Wed, 31 Oct 2018 10:56:01 +0100 Subject: [PATCH 295/652] Modify the parse/decode error message --- .../macroserver/test/res/macros/testmacros.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sardana/macroserver/test/res/macros/testmacros.py b/src/sardana/macroserver/test/res/macros/testmacros.py index 855a151b51..4dcf2c51b1 100644 --- a/src/sardana/macroserver/test/res/macros/testmacros.py +++ b/src/sardana/macroserver/test/res/macros/testmacros.py @@ -1,6 +1,6 @@ from sardana.macroserver.macro import Type, Macro -MSG_TEMP = "Parsing failed (result: %r; expected: %r)" +FAIL_MSG = "Parsing or decoding failed (result: %r; expected: %r)" class runMacro(Macro): @@ -14,7 +14,7 @@ def run(self, *args): macro, _ = self.prepareMacro("pt6_base", *expect_params) self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg params = (99, 1., 2.) @@ -22,14 +22,14 @@ def run(self, *args): expect_params = (99, [1., 2.]) self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg expect_params = ([92], True) macro, _ = self.prepareMacro("pt10_base", *expect_params) self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg params = (91, True) @@ -37,7 +37,7 @@ def run(self, *args): macro, _ = self.prepareMacro("pt10_base", *params) self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg @@ -52,7 +52,7 @@ def run(self, *args): macro, pars = self.createMacro('pt6_base', *expect_params) self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg params = (99, 1., 2.) @@ -61,14 +61,14 @@ def run(self, *args): macro, pars = self.createMacro('pt6_base', *params) self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg expect_params = ([92], True) macro, _ = self.createMacro("pt10_base", *expect_params) self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg params = (91, True) @@ -76,7 +76,7 @@ def run(self, *args): macro, _ = self.createMacro("pt10_base", *params) self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg @@ -90,35 +90,35 @@ def run(self, *args): expect_params = (99, [1., 2.]) macro = self.execMacro('pt6_base', *expect_params) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg params = (99, 1., 2.) macro = self.execMacro('pt6_base', *params) result = macro.data expect_params = (99, [1., 2.]) - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg expect_params = ([92], True) macro = self.execMacro('pt10_base', *expect_params) self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg expect_params = ([99.], True) macro = self.execMacro("pt10_base [99] True") self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg expect_params = ([999.], True) macro = self.execMacro("pt10_base", 999, True) self.runMacro(macro) result = macro.data - msg = MSG_TEMP % (result, expect_params) + msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg From 6f064eb1b915c77bf0c492cdd000a9cb5d53296f Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 11:19:33 +0100 Subject: [PATCH 296/652] Remove unused method --- src/sardana/pool/poolmeasurementgroup.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 7f001c832a..4255e7d1ef 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -136,10 +136,6 @@ def __init__(self, element, conf=None): def __getattr__(self, item): return getattr(self.element, item) - def get_config(self): - """ Returns the configuration dictionary""" - raise NotImplementedError() - def get_element(self): """Returns the element associated with this item""" return self._element() From ef5bbc230016e8265425c464c7f3b2803fb65454 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 11:21:23 +0100 Subject: [PATCH 297/652] Rename parameter Change the parameter config by attrs that is more appropriate according to its use. --- src/sardana/pool/poolmeasurementgroup.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 4255e7d1ef..5a1cdb023e 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -126,12 +126,12 @@ def _to_fqdn(name, logger=None): class ConfigurationItem(object): - def __init__(self, element, conf=None): + def __init__(self, element, attrs=None): self._element = weakref.ref(element) self.enabled = True - if conf is not None: - self.__dict__.update(conf) + if attrs is not None: + self.__dict__.update(attrs) def __getattr__(self, item): return getattr(self.element, item) @@ -150,8 +150,8 @@ def set_element(self, element): class ControllerConfiguration(ConfigurationItem): """Configuration: 'timer', 'monitor', 'synchronization', 'channels'""" - def __init__(self, element, conf=None): - ConfigurationItem.__init__(self, element, conf) + def __init__(self, element, attrs=None): + ConfigurationItem.__init__(self, element, attrs) self.enabled = False self._channels = [] self._channels_enabled = [] @@ -196,8 +196,8 @@ class ChannelConfiguration(ConfigurationItem): class SynchronizerConfiguration(ConfigurationItem): - def __init__(self, element, conf=None): - ConfigurationItem.__init__(self, element, conf) + def __init__(self, element, attrs=None): + ConfigurationItem.__init__(self, element, attrs) self.enabled = False From f3945ac3739d3110e82a7b88cdab8e503ce2c89c Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 13:10:39 +0100 Subject: [PATCH 298/652] Include AcqSynch and AcqSynchType --- src/sardana/pool/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/pool/__init__.py b/src/sardana/pool/__init__.py index 232369c6cb..0990a95788 100644 --- a/src/sardana/pool/__init__.py +++ b/src/sardana/pool/__init__.py @@ -25,7 +25,8 @@ """This is the main device pool module""" -__all__ = ["ControllerAPI", "AcqTriggerType", "AcqMode", "PoolUtil"] +__all__ = ["ControllerAPI", "AcqTriggerType", "AcqSynch", "AcqSynchType", + "AcqMode", "PoolUtil"] __docformat__ = 'restructuredtext' From b842fd91f66dc6c70d90b27ec09520bce5cd1560 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 13:12:21 +0100 Subject: [PATCH 299/652] Add classes to __all__ --- src/sardana/pool/poolmeasurementgroup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 5a1cdb023e..3bcb2cba76 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -26,7 +26,9 @@ """This module is part of the Python Pool library. It defines the base classes for""" -__all__ = ["PoolMeasurementGroup"] +__all__ = ["PoolMeasurementGroup", "MeasurementConfiguration", + "ControllerConfiguration", "ChannelConfiguration", + "SynchronizerConfiguration"] __docformat__ = 'restructuredtext' From 07f67391f76cb3568206d520654b31ba22e5f8e3 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 13:17:22 +0100 Subject: [PATCH 300/652] Refactor PoolSynchronization * Add synchronization as a mandatory start_action paramter. * Remove unused code. * Rename local variables to make them more redeable. --- src/sardana/pool/poolsynchronization.py | 83 +++++++++++-------------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/src/sardana/pool/poolsynchronization.py b/src/sardana/pool/poolsynchronization.py index aa8ee028d0..c9d6d4d7fd 100644 --- a/src/sardana/pool/poolsynchronization.py +++ b/src/sardana/pool/poolsynchronization.py @@ -131,11 +131,11 @@ def __init__(self, main_element, name="Synchronization"): def add_listener(self, listener): self._listener = listener - def start_action(self, conf_ctrls, synchronization=None, moveable=None, + def start_action(self, ctrls, synchronization, moveable=None, sw_synch_initial_domain=None, *args, **kwargs): '''Start action method. Expects the following kwargs: - - config - dictionary containing measurement group configuration + - ctrls - dictionary containing measurement group configuration - synchronization - list of dictionaries containing information about the expected synchronization - moveable (optional)- moveable object used as the synchronization @@ -145,36 +145,21 @@ def start_action(self, conf_ctrls, synchronization=None, moveable=None, - sw_synch_initial_domain (optional) - initial domain for software synchronizer, can be either SynchDomain.Time or SynchDomain.Position ''' - - # cfg = self.main_element.configuration - # ctrls_config = cfg.ctrl_tg_sync - # pool_ctrls = ctrls_config.keys() - # - # # Prepare a dictionary with the involved channels - # self._channels = channels = {} - # for pool_ctrl in pool_ctrls: - # pool_ctrl_data = ctrls_config[pool_ctrl] - # elements = pool_ctrl_data['channels'] - # - # for element, element_info in elements.items(): - # channel = TGChannel(element, info=element_info) - # channels[element] = channel - with ActionContext(self): # loads synchronization description - for conf_ctrl in conf_ctrls: - ctrl = conf_ctrl.ctrl - ctrl.PreSynchAll() - for conf_channel in conf_ctrl.get_channels(enabled=True): - axis = conf_channel.axis - ret = ctrl.PreSynchOne(axis, synchronization) + for ctrl in ctrls: + pool_ctrl = ctrl.element + pool_ctrl.ctrl.PreSynchAll() + for channel in ctrl.get_channels(enabled=True): + axis = channel.axis + ret = pool_ctrl.ctrl.PreSynchOne(axis, synchronization) if not ret: msg = ("%s.PreSynchOne(%d) returns False" % - (conf_ctrl.name, axis)) + (ctrl.name, axis)) raise Exception(msg) - ctrl.SynchOne(axis, synchronization) - ctrl.SynchAll() + pool_ctrl.ctrl.SynchOne(axis, synchronization) + pool_ctrl.ctrl.SynchAll() # attaching listener (usually acquisition action) # to the software trigger gate generator @@ -206,30 +191,32 @@ def start_action(self, conf_ctrls, synchronization=None, moveable=None, get_thread_pool().add(self._synch_soft.run) # PreStartAll on all controllers - for conf_ctrl in conf_ctrls: - conf_ctrl.ctrl.PreStartAll() + for ctrl in ctrls: + pool_ctrl = ctrl.element + pool_ctrl.ctrl.PreStartAll() # PreStartOne & StartOne on all elements - for conf_ctrl in conf_ctrls: - ctrl = conf_ctrl.ctrl - for conf_channel in conf_ctrl.get_channels(enabled=True): - axis = conf_channel.axis - ret = ctrl.PreStartOne(axis) + for ctrl in ctrls: + pool_ctrl = ctrl.element + for channel in ctrl.get_channels(enabled=True): + axis = channel.axis + ret = pool_ctrl.ctrl.PreStartOne(axis) if not ret: raise Exception("%s.PreStartOne(%d) returns False" - % (ctrl.name, axis)) - ctrl.StartOne(axis) + % (pool_ctrl.name, axis)) + pool_ctrl.ctrl.StartOne(axis) # set the state of all elements to inform their listeners self._channels = [] - for conf_ctrl in conf_ctrls: - for conf_channel in conf_ctrl.get_channels(enabled=True): - conf_channel.set_state(State.Moving, propagate=2) - self._channels.append(conf_channel) + for ctrl in ctrls: + for channel in ctrl.get_channels(enabled=True): + channel.set_state(State.Moving, propagate=2) + self._channels.append(channel) # StartAll on all controllers - for conf_ctrl in conf_ctrls: - conf_ctrl.ctrl.StartAll() + for ctrl in ctrls: + pool_ctrl = ctrl.element + pool_ctrl.ctrl.StartAll() def is_triggering(self, states): """Determines if we are triggering or if the triggering has ended @@ -254,8 +241,8 @@ def action_loop(self): '''action_loop method ''' states = {} - for conf_channel in self._channels: - element = conf_channel.element + for channel in self._channels: + element = channel.element states[element] = None # Triggering loop @@ -268,11 +255,11 @@ def action_loop(self): time.sleep(nap) # Set element states after ending the triggering - for triggerelement, state_info in states.items(): - with triggerelement: - triggerelement.clear_operation() - state_info = triggerelement._from_ctrl_state_info(state_info) - triggerelement.set_state_info(state_info, propagate=2) + for element, state_info in states.items(): + with element: + element.clear_operation() + state_info = element._from_ctrl_state_info(state_info) + element.set_state_info(state_info, propagate=2) # wait for software synchronizer to finish if self._listener is not None: From 6b8018d0a0ffab26ab5f20c5460532b10d6059ba Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 13:22:58 +0100 Subject: [PATCH 301/652] Add Acquisition wrappers Add AcqConfigurationItem and AcqController classes to wrap the configuration object and add necessary information for the acquisition actions, such as the master channel used in the timerable controllers. --- src/sardana/pool/poolacquisition.py | 55 ++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index f38392db27..8d223ea2fa 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -86,20 +86,59 @@ def __init__(self, args, kwargs=None): self.kwargs = kwargs -class PoolActionController(PoolActionItem): - def __init__(self, element, config=None): +class AcqConfigurationItem(object): + + def __init__(self, configuration, attrs=None): + self._configuration = weakref.ref(configuration) + self.enabled = True + + if attrs is not None: + self.__dict__.update(attrs) + + def __getattr__(self, item): + return getattr(self.configuration, item) + + def get_configuration(self): + """Returns the element associated with this item""" + return self._configuration() + + def set_configuration(self, configuration): + """Sets the element for this item""" + self._configuration = weakref.ref(configuration) + + configuration = property(get_configuration) + + +class AcqController(AcqConfigurationItem): + + def __init__(self, configuration, attrs=None): + if attrs is not None: + master = attrs.get('master') self._channels = [] self._channels_enabled = [] self._channels_disabled = [] - ch_config = {'controller': self} - for conf_channel in element._channels: - action_channel = PoolActionItem(conf_channel, ch_config) + ch_attrs = {'controller': self} + for conf_channel in configuration._channels: + action_channel = AcqConfigurationItem(conf_channel, ch_attrs) self._channels.append(action_channel) - if conf_channel in element._channels_enabled: + if conf_channel in configuration._channels_enabled: self._channels_enabled.append(action_channel) - if conf_channel in element._channels_disabled: + if conf_channel in configuration._channels_disabled: self._channels_disabled.append(action_channel) - PoolActionItem.__init__(self, element, config) + if master is None: + continue + if master == conf_channel: + attrs['master'] = action_channel + master = None + AcqConfigurationItem.__init__(self, configuration, attrs) + + def get_channels(self, enabled=None): + if enabled is None: + return list(self._channels) + elif enabled: + return list(self._channels_enabled) + else: + return list(self._channels_disabled) class PoolAcquisition(PoolAction): From bb6f84071e21c4c0df64c048855f547381cd1cf6 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 13:31:35 +0100 Subject: [PATCH 302/652] Add helpers to get the items for the actions --- src/sardana/pool/poolacquisition.py | 54 +++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 8d223ea2fa..aec10728b6 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -77,6 +77,60 @@ def is_value_error(value): return False +def get_acq_ctrls(ctrls, acq_mode=None): + action_ctrls = [] + for ctrl in ctrls: + attrs = {} + if acq_mode is not None: + master = None + if acq_mode is AcqMode.Timer: + master = ctrl.timer + elif acq_mode is AcqMode.Monitor: + master = ctrl.monitor + attrs = {'master': master} + action_ctrl = AcqController(ctrl, attrs) + action_ctrls.append(action_ctrl) + return action_ctrls + + +def get_synch_acq_items(ctrls): + ctrls = get_acq_ctrls(ctrls) + # ctrls = config.get_synch_ctrls(enabled=True) + return ctrls + + +def get_0d_acq_items(ctrls): + ctrls = get_acq_ctrls(ctrls) + return ctrls + + +def get_sw_acq_items(ctrls, master, acq_mode=AcqMode.Timer): + ctrls = get_acq_ctrls(ctrls, acq_mode) + # Search master AcqConfigurationItem obj + for ctrl in ctrls: + for channel in ctrl.get_channels(): + if channel.configuration == master: + master = channel + break + return ctrls, master + + +def get_sw_start_acq_items(ctrls, master, acq_mode=AcqMode.Timer): + ctrls = get_acq_ctrls(ctrls, acq_mode) + # Search master AcqConfigurationItem obj + for ctrl in ctrls: + for channel in ctrl.get_channels(): + if channel.configuration == master: + master = channel + break + return ctrls, master + + +def get_hw_acq_items(ctrls, acq_mode=AcqMode.Timer): + ctrls = get_acq_ctrls(ctrls, acq_mode) + return ctrls + + class ActionArgs(object): def __init__(self, args, kwargs=None): From 0f9a8c903d7410577a48aacbac2762d1951b0810 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 13:32:07 +0100 Subject: [PATCH 303/652] Remove unused import --- src/sardana/pool/poolacquisition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index aec10728b6..416b28fdad 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -41,7 +41,7 @@ from sardana import SardanaValue, State, ElementType, TYPE_TIMERABLE_ELEMENTS from sardana.sardanathreadpool import get_thread_pool from sardana.pool import AcqSynch, AcqMode -from sardana.pool.poolaction import ActionContext, PoolActionItem, PoolAction +from sardana.pool.poolaction import ActionContext, PoolAction from sardana.pool.poolsynchronization import PoolSynchronization #: enumeration representing possible motion states From dee712b48fa1f03d04424ce3200301949e6d2fa4 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 13:33:26 +0100 Subject: [PATCH 304/652] Remove unsued Channel class --- src/sardana/pool/poolacquisition.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 416b28fdad..c204cd487f 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -26,8 +26,8 @@ """This module is part of the Python Pool libray. It defines the class for an acquisition""" -__all__ = ["AcquisitionState", "AcquisitionMap", "PoolCTAcquisition", - "Pool0DAcquisition", "Channel", "PoolIORAcquisition"] +__all__ = ["get_acq_ctrls", "AcquisitionState", "AcquisitionMap", + "PoolCTAcquisition", "Pool0DAcquisition", "PoolIORAcquisition"] __docformat__ = 'restructuredtext' @@ -466,17 +466,6 @@ def read_value(self, ret=None, serial=False): return ret -class Channel(PoolActionItem): - - def __init__(self, acquirable, info=None): - PoolActionItem.__init__(self, acquirable) - if info: - self.__dict__.update(info) - - def __getattr__(self, name): - return getattr(self.element, name) - - class PoolAcquisitionBase(PoolAction): """Base class for acquisitions with a generic start_action method. From cbe268eb1bdee19d00924b80704a2b6453b0f006 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 13:35:54 +0100 Subject: [PATCH 305/652] Rename local variables --- src/sardana/pool/poolacquisition.py | 82 +++++++++++++++-------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index c204cd487f..31c68b2441 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -510,14 +510,14 @@ def in_acquisition(self, states): return True @DebugIt() - def start_action(self, conf_ctrls, value, repetitions=1, latency=0, + def start_action(self, ctrls, value, repetitions=1, latency=0, master=None, index=None, acq_sleep_time=None, nb_states_per_value=None, *args, **kwargs): """ Prepares everything for acquisition and starts it - :param conf_ctrls: List of enabled controllers - :type conf_ctrls: list + :param ctrls: List of enabled pool acquisition controllers + :type ctrls: list :param value: integration time/monitor counts :type value: float/int or seq :param repetitions: repetitions @@ -554,18 +554,18 @@ def start_action(self, conf_ctrls, value, repetitions=1, latency=0, # make sure the controller which has the master channel is the last to # be called if master is not None: - conf_ctrls.remove(master.controller) - conf_ctrls.append(master.controller) + ctrls.remove(master.controller) + ctrls.append(master.controller) # controllers that will be read at during the action - self._set_pool_ctrl_dict_loop(conf_ctrls) + self._set_pool_ctrl_dict_loop(ctrls) # channels that are acquired (only enabled) self._channels = [] - def load(conf_channel, value, repetitions, latency=0): - axis = conf_channel.axis - pool_ctrl = conf_channel.controller + def load(channel, value, repetitions, latency=0): + axis = channel.axis + pool_ctrl = channel.controller ctrl = pool_ctrl.ctrl ctrl.PreLoadAll() try: @@ -607,70 +607,74 @@ def load(conf_channel, value, repetitions, latency=0): with ActionContext(self): # PreLoadAll, PreLoadOne, LoadOne and LoadAll - for conf_ctrl in conf_ctrls: + for ctrl in ctrls: # TODO find solution for master now sardana only use timer - load(conf_ctrl.timer, value, repetitions, latency) + load(ctrl.timer, value, repetitions, latency) # TODO: remove when the action allows to use tango attributes try: - conf_ctrls.pop('__tango__') + ctrls.pop('__tango__') except Exception: pass # PreStartAll on all enabled controllers - for conf_ctrl in conf_ctrls: - conf_ctrl.ctrl.PreStartAll() + for ctrl in ctrls: + pool_ctrl = ctrl.element + pool_ctrl.ctrl.PreStartAll() # PreStartOne & StartOne on all enabled elements - for conf_ctrl in conf_ctrls: - conf_channels = conf_ctrl.get_channels(enabled=True) + for ctrl in ctrls: + channels = ctrl.get_channels(enabled=True) # make sure that the master timer/monitor is started as the # last one - conf_channels.remove(conf_ctrl.timer) - conf_channels.append(conf_ctrl.timer) - for conf_channel in conf_channels: - axis = conf_channel.axis - ret = conf_ctrl.ctrl.PreStartOne(axis, value) + channels.remove(ctrl.master) + channels.append(ctrl.master) + for channel in channels: + axis = channel.axis + pool_ctrl = ctrl.element + ret = pool_ctrl.ctrl.PreStartOne(axis, value) if not ret: msg = ("%s.PreStartOne(%d) returns False" % - (conf_ctrl.name, axis)) + (ctrl.name, axis)) raise Exception(msg) try: - conf_ctrl.ctrl.StartOne(axis, value) + pool_ctrl = ctrl.element + pool_ctrl.ctrl.StartOne(axis, value) except Exception as e: self.debug(e, exc_info=True) - conf_channel.set_state(State.Fault, propagate=2) + channel.set_state(State.Fault, propagate=2) msg = ("%s.StartOne(%d) failed" % - (conf_ctrl.name, axis)) + (ctrl.name, axis)) raise Exception(msg) - self._channels.append(conf_channel) + self._channels.append(channel) # set the state of all elements to and inform their listeners - for conf_channel in self._channels: - conf_channel.set_state(State.Moving, propagate=2) + for channel in self._channels: + channel.set_state(State.Moving, propagate=2) # StartAll on all enabled controllers - for conf_ctrl in conf_ctrls: + for ctrl in ctrls: try: - conf_ctrl.ctrl.StartAll() + pool_ctrl = ctrl.element + pool_ctrl.ctrl.StartAll() except Exception as e: - conf_channels = conf_ctrl.get_channels(enabled=True) + channels = ctrl.get_channels(enabled=True) self.debug(e, exc_info=True) - for conf_channel in conf_channels: - conf_channel.set_state(State.Fault, propagate=2) - msg = ("%s.StartAll() failed" % conf_ctrl.name) + for channel in channels: + channel.set_state(State.Fault, propagate=2) + msg = ("%s.StartAll() failed" % ctrl.name) raise Exception(msg) - def _set_pool_ctrl_dict_loop(self, conf_ctrls): + def _set_pool_ctrl_dict_loop(self, ctrls): ctrl_channels = {} - for conf_ctrl in conf_ctrls: + for ctrl in ctrls: pool_channels = [] - pool_ctrl = conf_ctrl.element + pool_ctrl = ctrl.element # TODO: filter 1D and 2D for software synchronize acquisition - for conf_channel in conf_ctrl.get_channels(enabled=True): - pool_channels.append(conf_channel.element) + for channel in ctrl.get_channels(enabled=True): + pool_channels.append(channel.element) ctrl_channels[pool_ctrl] = pool_channels self._pool_ctrl_dict_loop = ctrl_channels From 35f3019392ca4593bbc627cd5ea8f9b4c1538997 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 13:41:10 +0100 Subject: [PATCH 306/652] Refactor PoolAcquistion run and prepare method Move the preparation logic from the run to the prepare method. --- src/sardana/pool/poolacquisition.py | 210 ++++++++++++++++++---------- 1 file changed, 136 insertions(+), 74 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 31c68b2441..73ff660816 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -210,7 +210,7 @@ def __init__(self, main_element, name="Acquisition"): self._0d_acq_args = None self._hw_acq_args = None self._synch_args = None - + self._prepared = False self._sw_acq = PoolAcquisitionSoftware(main_element, name=swname) self._sw_start_acq = PoolAcquisitionSoftwareStart( main_element, name=sw_start_name) @@ -273,25 +273,16 @@ def event_received(self, *args, **kwargs): self.debug('Stopping ZeroD acquisition.') self._0d_acq.stop_action() - def prepare(self, ctrl_lodeable, value, repetitions, latency, - nr_of_starts): + def prepare(self, config, acq_mode, value, synchronization=None, + moveable=None, sw_synch_initial_domain=None, + nr_of_starts=1, **kwargs): """Prepare measurement.""" - # TODO: set synch to true for software, software start and 0D acq - # kwargs['synch'] = True - - for conf_ctrl, lodeable in ctrl_lodeable.items(): - axis = lodeable.axis - conf_ctrl.ctrl.PrepareOne(axis, value, repetitions, latency, - nr_of_starts) - - def is_running(self): - return self._0d_acq.is_running() or\ - self._sw_acq.is_running() or\ - self._hw_acq.is_running() or\ - self._synch.is_running() - - def run(self, head, config, multiple, acq_mode, value, synchronization, - moveable, sw_synch_initial_domain=None, *args, **kwargs): + self._sw_acq_args = None + self._sw_start_acq_args = None + self._0d_acq_args = None + self._hw_acq_args = None + self._synch_args = None + self._prepared = False for elem in self.get_elements(): elem.put_state(None) @@ -308,69 +299,140 @@ def run(self, head, config, multiple, acq_mode, value, synchronization, for pseudo_elem in elem.get_pseudo_elements(): pseudo_elem.clear_value_buffer() - if acq_mode is AcqMode.Timer: - value = synchronization.active_time repetitions = synchronization.repetitions - latency_time = 0 + latency = synchronization.passive_time - # starting continuous acquisition only if there are any controllers + # Prepare controllers synchronized by hardware acq_sync_hw = [AcqSynch.HardwareTrigger, AcqSynch.HardwareStart, AcqSynch.HardwareGate] - ctrls_acq_hw = config.get_timerable_ctrls(acq_synch=acq_sync_hw, - enabled=True) + ctrls = config.get_timerable_ctrls(acq_synch=acq_sync_hw, enabled=True) + ctrls_hw = get_hw_acq_items(ctrls, acq_mode) + if len(ctrls_hw) > 0: + hw_args = (ctrls_hw, value) + hw_kwargs = {'repetitions': repetitions, + 'latency': latency} + hw_kwargs.update(kwargs) + self._hw_acq_args = ActionArgs(hw_args, hw_kwargs) + + # Prepare controllers synchronized by software Trigger and Gate + acq_sync_sw = [AcqSynch.SoftwareGate, AcqSynch.SoftwareTrigger] + ctrls = config.get_timerable_ctrls(acq_synch=acq_sync_sw, enabled=True) + if acq_mode is AcqMode.Timer: + master = config.get_master_timer_software() + elif acq_mode is AcqMode.Monitor: + master = config.get_master_monitor_software() + + ctrls_sw, master_sw = get_sw_acq_items(ctrls, master, acq_mode) + if len(ctrls_sw) > 0: + sw_args = (ctrls_sw, value) + sw_kwargs = {'latency': latency, + 'master': master_sw, + 'synch': True} + sw_kwargs.update(kwargs) + self._sw_acq_args = ActionArgs(sw_args, sw_kwargs) + + # Prepare controllers synchronized by software Start + ctrls = config.get_timerable_ctrls(acq_synch=AcqSynch.SoftwareStart, + enabled=True) + if acq_mode is AcqMode.Timer: + master = config.get_master_timer_software_start() + elif acq_mode is AcqMode.Monitor: + master = config.get_master_monitor_software_start() + + ctrls_sw_start, master_sw_start = get_sw_start_acq_items(ctrls, + master, + acq_mode) + if len(ctrls_sw_start) > 0: + sw_start_args = (ctrls_sw_start, value) + sw_start_kwargs = {'repetitions': repetitions, + 'latency': latency, + 'master': master_sw_start, + 'synch': True} + sw_start_kwargs.update(kwargs) + self._sw_start_acq_args = ActionArgs(sw_start_args, + sw_start_kwargs) + + # Prepare 0D controllers + ctrls = config.get_zerod_ctrls(enabled=True) + ctrls_acq_0d = get_0d_acq_items(ctrls) + if len(ctrls_acq_0d) > 0: + zerod_args = (ctrls_acq_0d,) + zerod_kwargs = {'synch': True} + zerod_kwargs.update(kwargs) + self._0d_acq_args = ActionArgs(zerod_args, zerod_kwargs) + + # Prepare synchronizer controllers + ctrls = config.get_synch_ctrls(enabled=True) + ctrls_synch = get_synch_acq_items(ctrls) + synch_args = (ctrls_synch,) + synch_kwargs = {'synchronization': synchronization, + 'moveable': moveable, + 'sw_synch_initial_domain': sw_synch_initial_domain} + synch_kwargs.update(kwargs) + self._synch_args = ActionArgs(synch_args, synch_kwargs) + + # Load the configuration to the timerable controllers if it changed: + if config.changed: + ctrls = ctrls_hw + ctrls_sw_start + ctrls_sw - if len(ctrls_acq_hw): - self._hw_acq.run(conf_ctrls=ctrls_acq_hw, - value=value, - repetitions=repetitions, - latency_time=latency_time) + for ctrl in ctrls: + pool_ctrl = ctrl.element + if not pool_ctrl.is_online(): + raise RuntimeError('The controller {0} is ' + 'offline'.format(pool_ctrl.name)) + pool_ctrl.set_ctrl_par('acquisition_mode', acq_mode) + pool_ctrl.operator = self.main_element + pool_ctrl.set_ctrl_par('timer', ctrl.timer.axis) + pool_ctrl.set_ctrl_par('monitor', ctrl.monitor.axis) + synch = config.get_acq_synch_by_controller(pool_ctrl) + pool_ctrl.set_ctrl_par('synchronization', synch) + config.changed = False + + # Call hardware and software start controllers prepare method + ctrls = ctrls_hw + ctrls_sw_start + self._prepare_ctrls(ctrls, value, repetitions, latency, + nr_of_starts) + + # Call software controllers prepare method + nr_of_starts = repetitions + repetitions = 1 + self._prepare_ctrls(ctrls_sw, value, repetitions, latency, + nr_of_starts) + self._prepared = True + + + def _prepare_ctrls(self, ctrls, value, repetitions, latency, + nr_of_starts): + for ctrl in ctrls: + axis = ctrl.master.axis + pool_ctrl = ctrl.element + pool_ctrl.ctrl.PrepareOne(axis, value, repetitions, latency, + nr_of_starts) - # starting software acquisition only if there are any controller - acq_sync_sw = [AcqSynch.SoftwareGate, AcqSynch.SoftwareTrigger] - ctrls_acq_sw = config.get_timerable_ctrls(acq_synch=acq_sync_sw, - enabled=True) - ctrls_acq_sw_start = config.get_timerable_ctrls( - acq_synch=AcqSynch.SoftwareStart, enabled=True) - ctrls_acq_0d = config.get_zerod_ctrls(enabled=True) + def is_running(self): + return self._0d_acq.is_running() or\ + self._sw_acq.is_running() or\ + self._hw_acq.is_running() or\ + self._synch.is_running() + + def run(self, *args, **kwargs): + if not self._prepared: + raise RuntimeError('You must call first to prepare method.') + + if self._hw_acq_args is not None: + self._hw_acq.run(*self._hw_acq_args.args, + **self._hw_acq_args.kwargs) - if len(ctrls_acq_sw) or len(ctrls_acq_0d) or len(ctrls_acq_sw_start): + if self._sw_acq_args is not None\ + or self._sw_start_acq_args is not None\ + or self._0d_acq_args is not None: self._synch.add_listener(self) - if len(ctrls_acq_sw_start): - master = None - if acq_mode is AcqMode.Timer: - master = config.get_master_timer_software_start() - elif acq_mode is AcqMode.Monitor: - master = config.get_master_monitor_software_start() - - sw_acq_kwargs = dict(conf_ctrls=ctrls_acq_sw_start, - value=value, - repetitions=repetitions, - latency_time=latency_time, - master=master) - self.set_sw_start_config(sw_acq_kwargs) - if len(ctrls_acq_sw): - master = None - if acq_mode is AcqMode.Timer: - master = config.get_master_timer_software() - elif acq_mode is AcqMode.Monitor: - master = config.get_master_monitor_software() - - sw_acq_kwargs = dict(conf_ctrls=ctrls_acq_sw, - value=value, - repetitions=1, - latency_time=latency_time, - master=master) - self.set_sw_config(sw_acq_kwargs) - if len(ctrls_acq_0d): - zerod_acq_kwargs = dict(conf_ctrls=ctrls_acq_0d) - self.set_0d_config(zerod_acq_kwargs) - - # start the synchonization action - ctrls_synch = config.get_synch_ctrls(enabled=True) - self._synch.run(conf_ctrls=ctrls_synch, - synchronization=synchronization, - moveable=moveable, - sw_synch_initial_domain=sw_synch_initial_domain) + + if self._synch_args is not None: + self._synch.run(*self._synch_args.args, + **self._synch_args.kwargs) + + self._prepared = False def _get_action_for_element(self, element): elem_type = element.get_type() From d5ef79fb2a294506c269b921f3d2452ebcf34c21 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 31 Oct 2018 15:08:33 +0100 Subject: [PATCH 307/652] Remove Preparable interface and add PrepareOne to Loadable --- doc/source/sep/SEP18.md | 12 +++++------- src/sardana/pool/controller.py | 34 ++++++++++++++-------------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 9899a7f37f..4354d2fe1a 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -148,12 +148,10 @@ the following options: #### Option 1 -* Add `Preparable` interface with -`PrepareOne(axis, integ_time, repeats, latency_time, starts)` TODO: or -directly add it to the Loadable interface -* Make C/T, 1D and 2D controllers inherit from this interface +* Add `PrepareOne(axis, value, repeats, latency, starts)` +to the Loadable interface * Add extra argument to `LoadOne`, etc. methods of the `Loadable` interface -`latency_time`: `LoadOne(axis, integ_time, repeats, latency_time)` +`latency_time`: `LoadOne(axis, value, repeats, latency)` This option maintains backwards compatibility. @@ -221,8 +219,8 @@ StartOne(1) #### Option 2 * Add extra arguments to `LoadOne`, etc. methods of the `Loadable` interface -`latency_time` and `starts` and switch the order of arguments so the API is: -`LoadOne(axis, integ_time, latency_time, repeats, starts)`. +`latency` and `nr_of_starts` and switch the order of arguments so the API is: +`LoadOne(axis, value, latency, repeats, nr_of_starts)`. * Make the `LoadOne`, etc. be called only once per measurement, in the measurement group prepare command. diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index cd9e6873af..c1daa3609c 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -655,12 +655,11 @@ def ReadOne(self, axis): raise NotImplementedError("ReadOne must be defined in the controller") -class Preparable(object): - """A Preparable interface. A controller for which its axis are - 'pareparable' for a measurement (like a counter, 1D or 2D for example) - should implement this interface +class Loadable(object): + """A Loadable interface. A controller for which it's axis are 'loadable' + (like a counter, 1D or 2D for example) should implement this interface - .. note: Do not inherit directly from Preparable.""" + .. note: Do not inherit directly from Loadable.""" def PrepareOne(self, axis, value, repetitions, latency, nr_of_starts): """**Controller API**. Override if necessary. @@ -669,24 +668,19 @@ def PrepareOne(self, axis, value, repetitions, latency, nr_of_starts): :param int axis: axis number :param int repetitions: number of repetitions - :param float value: integration time /monitor value + :param float value: integration time / monitor count + :param float latency: latency time + :param int nr_of_starts: number of starts """ pass - -class Loadable(object): - """A Loadable interface. A controller for which it's axis are 'loadable' - (like a counter, 1D or 2D for example) should implement this interface - - .. note: Do not inherit directly from Loadable.""" - def PreLoadAll(self): """**Controller API**. Override if necessary. Called to prepare loading the integration time / monitor value. Default implementation does nothing.""" pass - def PreLoadOne(self, axis, value, repetitions): + def PreLoadOne(self, axis, value, repetitions, latency): """**Controller API**. Override if necessary. Called to prepare loading the master channel axis with the integration time / monitor value. @@ -695,6 +689,7 @@ def PreLoadOne(self, axis, value, repetitions): :param int axis: axis number :param float value: integration time /monitor value :param int repetitions: number of repetitions + :param float latency: latency time :return: True means a successfull PreLoadOne or False for a failure :rtype: bool""" return True @@ -705,7 +700,7 @@ def LoadAll(self): Default implementation does nothing.""" pass - def LoadOne(self, axis, value, repetitions): + def LoadOne(self, axis, value, repetitions, latency): """**Controller API**. Override is MANDATORY! Called to load the integration time / monitor value. Default implementation raises :exc:`NotImplementedError`. @@ -713,6 +708,7 @@ def LoadOne(self, axis, value, repetitions): :param int axis: axis number :param float value: integration time /monitor value :param int repetitions: number of repetitions + :param float latency: latency time :param float value: integration time /monitor value""" raise NotImplementedError("LoadOne must be defined in the controller") @@ -889,7 +885,7 @@ def DefinePosition(self, axis, position): class CounterTimerController(Controller, Readable, Startable, Stopable, - Loadable, Preparable): + Loadable): """Base class for a counter/timer controller. Inherit from this class to implement your own counter/timer controller for the device pool. @@ -1052,8 +1048,7 @@ def AbortOne(self, axis): pass -class OneDController(Controller, Readable, Startable, Stopable, Loadable, - Preparable): +class OneDController(Controller, Readable, Startable, Stopable, Loadable): """Base class for a 1D controller. Inherit from this class to implement your own 1D controller for the device pool. @@ -1091,8 +1086,7 @@ def GetAxisPar(self, axis, parameter): return self.GetPar(axis, parameter) -class TwoDController(Controller, Readable, Startable, Stopable, Loadable, - Preparable): +class TwoDController(Controller, Readable, Startable, Stopable, Loadable): """Base class for a 2D controller. Inherit from this class to implement your own 2D controller for the device pool.""" From 9eb3be282008c1ec42016e88ea045ceda20480c6 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 14:45:39 +0100 Subject: [PATCH 308/652] Adapt test_acquisition --- src/sardana/pool/test/test_acquisition.py | 31 ++++++++++++++--------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index b34e20675c..4a85bc9180 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -28,11 +28,11 @@ from taurus.external.unittest import TestCase from taurus.test import insertTest -from sardana.pool import AcqSynch +from sardana.pool import AcqSynch, AcqMode from sardana.pool.pooldefs import SynchDomain, SynchParam from sardana.pool.poolsynchronization import PoolSynchronization from sardana.pool.poolacquisition import PoolAcquisitionHardware, \ - PoolAcquisitionSoftware, PoolAcquisitionSoftwareStart + PoolAcquisitionSoftware, PoolAcquisitionSoftwareStart, get_acq_ctrls from sardana.sardanathreadpool import get_thread_pool from sardana.pool.test import createControllerConfiguration, \ createTimerableControllerConfiguration, BasePoolTestCase, FakeElement, \ @@ -165,8 +165,11 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, [ct_1_1]) conf_ct_ctrl_2 = createTimerableControllerConfiguration(ct_ctrl_2, [ct_2_1]) - conf_ct_2_1 = conf_ct_ctrl_2.timer + hw_ctrls = get_acq_ctrls([conf_ct_ctrl_1], acq_mode=AcqMode.Timer) + sw_ctrls = get_acq_ctrls([conf_ct_ctrl_2], acq_mode=AcqMode.Timer) + sw_master = sw_ctrls[0].master conf_tg_ctrl_1 = createControllerConfiguration(tg_ctrl_1, [tg_1_1]) + synch_ctrls = get_acq_ctrls([conf_tg_ctrl_1]) # creating synchronization action self.synchronization = self.create_action(PoolSynchronization, [tg_1_1]) @@ -187,8 +190,8 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, self.sw_acq_busy = threading.Event() self.sw_acq.add_finish_hook(self.sw_acq_busy.clear) - self.sw_acq_args = ([conf_ct_ctrl_2], integ_time) - self.sw_acq_kwargs = {"master": conf_ct_2_1} + self.sw_acq_args = (sw_ctrls, integ_time) + self.sw_acq_kwargs = {"master": sw_master} total_interval = active_interval + passive_interval group = { @@ -200,8 +203,8 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, synchronization = [group] # get the current number of jobs jobs_before = get_thread_pool().qsize - self.hw_acq.run([conf_ct_ctrl_1], integ_time, repetitions) - self.synchronization.run([conf_tg_ctrl_1], synchronization) + self.hw_acq.run(hw_ctrls, integ_time, repetitions) + self.synchronization.run(synch_ctrls, synchronization) # waiting for acquisition and synchronization to finish while (self.hw_acq.is_running() or self.sw_acq.is_running() @@ -241,7 +244,8 @@ def acquire(self, integ_time, repetitions, latency_time): conf_ct_ctrl_1 = createTimerableControllerConfiguration(self.ct_ctrl_1, [self.ct_1_1]) - conf_ct_1_1 = conf_ct_ctrl_1.timer + ctrls = get_acq_ctrls([conf_ct_ctrl_1], AcqMode.Timer) + master = ctrls[0].master # creating synchronization action self.synchronization = self.create_action(PoolSynchronization, [self.tg_1_1]) @@ -251,8 +255,9 @@ def acquire(self, integ_time, repetitions, latency_time): # creating acquisition actions self.acquisition = self.create_action(PoolAcquisitionSoftwareStart, [self.ct_1_1]) - self.acq_args = ([conf_ct_ctrl_1], integ_time, repetitions) - self.acq_kwargs = {"master": conf_ct_1_1} + + self.acq_args = (ctrls, integ_time, repetitions) + self.acq_kwargs = {"master": master} total_interval = integ_time + latency_time group = { @@ -289,8 +294,10 @@ def acquire(self, integ_time, repetitions, latency_time): self.ct_ctrl_1.set_ctrl_par("synchronization", AcqSynch.HardwareStart) conf_ct_ctrl_1 = createTimerableControllerConfiguration( self.ct_ctrl_1, [self.ct_1_1]) + ctrls = get_acq_ctrls([conf_ct_ctrl_1], AcqMode.Timer) conf_tg_ctrl_1 = createControllerConfiguration(self.tg_ctrl_1, [self.tg_1_1]) + synch_ctrls = get_acq_ctrls([conf_tg_ctrl_1]) self.synchronization = self.create_action(PoolSynchronization, [self.tg_1_1]) # add data listeners @@ -310,8 +317,8 @@ def acquire(self, integ_time, repetitions, latency_time): synchronization = [group] # get the current number of jobs jobs_before = get_thread_pool().qsize - self.acquisition.run([conf_ct_ctrl_1], integ_time, repetitions) - self.synchronization.run([conf_tg_ctrl_1], synchronization) + self.acquisition.run(ctrls, integ_time, repetitions) + self.synchronization.run(synch_ctrls, synchronization) self.wait_finish() self.do_asserts(repetitions, jobs_before) From 62f1e5fca76389e505be61c4501673a33e143b90 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 15:01:27 +0100 Subject: [PATCH 309/652] Adapt test_poolsynchronization --- src/sardana/pool/test/test_poolsynchronization.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/test/test_poolsynchronization.py b/src/sardana/pool/test/test_poolsynchronization.py index ecd643fc38..4401796561 100644 --- a/src/sardana/pool/test/test_poolsynchronization.py +++ b/src/sardana/pool/test/test_poolsynchronization.py @@ -27,6 +27,7 @@ from taurus.external import unittest from sardana.pool.poolsynchronization import PoolSynchronization +from sardana.pool.poolacquisition import get_acq_ctrls from sardana.sardanadefs import State from sardana.pool.test import FakePool, createPoolController, \ createPoolTriggerGate, dummyPoolTGCtrlConf01, dummyTriggerGateConf01, \ @@ -52,9 +53,10 @@ def setUp(self): dummy_tg_ctrl.add_element(self.dummy_tg) pool.add_element(dummy_tg_ctrl) pool.add_element(self.dummy_tg) - conf_ctrl = createControllerConfiguration(dummy_tg_ctrl, - [self.dummy_tg]) - self.conf_ctrls = [conf_ctrl] + self.conf_ctrl = createControllerConfiguration(dummy_tg_ctrl, + [self.dummy_tg]) + + self.ctrls = get_acq_ctrls([self.conf_ctrl]) # self.cfg = createPoolSynchronizationConfiguration((dummy_tg_ctrl,), # ((self.dummy_tg,),),) # Create mock and define its functions @@ -74,9 +76,10 @@ def stopGeneration(self): def test_tggeneration(self): """Verify trigger element states before and after action_loop.""" - from mock import call + from mock import call, MagicMock # starting action - self.tgaction.start_action(self.conf_ctrls) + synchronization = MagicMock() + self.tgaction.start_action(self.ctrls, synchronization) # verifying that the action correctly started the involved controller self.mock_tg_ctrl.assert_has_calls([call.PreStartAll(), (call.PreStartOne(1,)), From 06cc56f292e792e884ea63572603d5ee807b00c7 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 15:06:06 +0100 Subject: [PATCH 310/652] Adapt test_synchronization --- src/sardana/pool/test/test_synchronization.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/sardana/pool/test/test_synchronization.py b/src/sardana/pool/test/test_synchronization.py index bfddbcbdc9..061d19820e 100644 --- a/src/sardana/pool/test/test_synchronization.py +++ b/src/sardana/pool/test/test_synchronization.py @@ -34,6 +34,7 @@ from taurus.external import unittest from sardana.pool.poolsynchronization import PoolSynchronization +from sardana.pool.poolacquisition import get_acq_ctrls from sardana.sardanadefs import State from sardana.pool.pooldefs import SynchDomain, SynchParam from sardana.pool.test import FakePool, createCtrlConf, createElemConf, \ @@ -60,8 +61,9 @@ def createElements(self, ctrl_klass, ctrl_lib, ctrl_props): self.pool.add_element(self.tg_ctrl) self.pool.add_element(self.tg_elem) # create Synchronization action and its configuration - conf_ctrl = createControllerConfiguration(self.tg_ctrl, [self.tg_elem]) - self.tg_cfg = [conf_ctrl] + self.conf_ctrl = createControllerConfiguration(self.tg_ctrl, + [self.tg_elem]) + self.ctrls = get_acq_ctrls([self.conf_ctrl]) self.tgaction = PoolSynchronization(self.tg_elem) self.tgaction.add_element(self.tg_elem) @@ -94,10 +96,8 @@ def tggeneration(self, ctrl_lib, ctrl_klass, ctrl_props, self.createElements(ctrl_klass, ctrl_lib, ctrl_props) # create start_action arguments - args = () - kwargs = {'conf_ctrls': self.tg_cfg, - 'synchronization': synchronization - } + args = (self.ctrls, synchronization) + kwargs = {} # starting action self.tgaction.start_action(*args, **kwargs) # verifying that the elements involved in action changed its state @@ -142,10 +142,8 @@ def abort_tggeneration(self, ctrl_lib, ctrl_klass, ctrl_props, self.createElements(ctrl_klass, ctrl_lib, ctrl_props) # create start_action arguments - args = () - kwargs = {'conf_ctrls': self.tg_cfg, - 'synchronization': synchronization - } + args = (self.ctrls, synchronization) + kwargs = {} # starting action self.tgaction.start_action(*args, **kwargs) # verifying that the elements involved in action changed its state From 6dd45878a208ad3d360065e121e5ccfb435ce675 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 15:07:10 +0100 Subject: [PATCH 311/652] Add classes to __all__ variable --- src/sardana/pool/poolacquisition.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 73ff660816..af5852ad06 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -27,7 +27,9 @@ acquisition""" __all__ = ["get_acq_ctrls", "AcquisitionState", "AcquisitionMap", - "PoolCTAcquisition", "Pool0DAcquisition", "PoolIORAcquisition"] + "PoolCTAcquisition", "Pool0DAcquisition", "PoolIORAcquisition", + "PoolAcquisitionHardware", "PoolAcquisitionSoftware", + "PoolAcquisitionSoftwareStart"] __docformat__ = 'restructuredtext' @@ -1057,7 +1059,6 @@ def start_action(self, conf_ctrls, index=None, acq_sleep_time=None, # self._stopped = False self._index = index - self._acq_sleep_time = acq_sleep_time if self._acq_sleep_time is None: self._acq_sleep_time = pool.acq_loop_sleep_time From 3833dcd747f903302c54918e3ad1ad1b6e4012b6 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 15:09:59 +0100 Subject: [PATCH 312/652] Remove *args from start_action methods --- src/sardana/pool/poolacquisition.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index af5852ad06..3b397b618c 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -402,7 +402,6 @@ def prepare(self, config, acq_mode, value, synchronization=None, nr_of_starts) self._prepared = True - def _prepare_ctrls(self, ctrls, value, repetitions, latency, nr_of_starts): for ctrl in ctrls: @@ -576,8 +575,7 @@ def in_acquisition(self, states): @DebugIt() def start_action(self, ctrls, value, repetitions=1, latency=0, master=None, index=None, acq_sleep_time=None, - nb_states_per_value=None, *args, - **kwargs): + nb_states_per_value=None, **kwargs): """ Prepares everything for acquisition and starts it :param ctrls: List of enabled pool acquisition controllers @@ -1046,7 +1044,7 @@ def __init__(self, main_element, name="0DAcquisition"): PoolAction.__init__(self, main_element, name) def start_action(self, conf_ctrls, index=None, acq_sleep_time=None, - nb_states_per_value=None, *args, **kwargs): + nb_states_per_value=None, **kwargs): """Prepares everything for acquisition and starts it. :param: config""" From 97bc04deb4a68c1e0cba4b16aec5a7026494a6f2 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 16:03:39 +0100 Subject: [PATCH 313/652] Change local variable name Use index instead of value to be more explicit. --- src/sardana/pool/poolacquisition.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 3b397b618c..d2196895f6 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -222,13 +222,13 @@ def __init__(self, main_element, name="Acquisition"): def event_received(self, *args, **kwargs): timestamp = time.time() - _, type_, value = args + _, type_, index = args name = type_.name if name == "state": return t_fmt = '%Y-%m-%d %H:%M:%S.%f' t_str = datetime.datetime.fromtimestamp(timestamp).strftime(t_fmt) - msg = '%s event with id: %d received at: %s' % (name, value, t_str) + msg = '%s event with id: %d received at: %s' % (name, index, t_str) self.debug(msg) if name == "start": if self._sw_start_acq_args is not None: @@ -247,7 +247,7 @@ def event_received(self, *args, **kwargs): return else: self.debug('Executing software acquisition.') - self._sw_acq_args.kwargs.update({'index': value}) + self._sw_acq_args.kwargs.update({'index': index}) self._sw_acq._started = True get_thread_pool().add(self._sw_acq.run, None, *self._sw_acq_args.args, @@ -260,7 +260,7 @@ def event_received(self, *args, **kwargs): return else: self.debug('Executing ZeroD acquisition.') - self._0d_acq_args.kwargs.update({'index': value}) + self._0d_acq_args.kwargs.update({'index': index}) self._0d_acq._started = True self._0d_acq._stopped = False self._0d_acq._aborted = False From 5181155834d7c92b67036ff193095b9265f275f2 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Wed, 31 Oct 2018 16:14:17 +0100 Subject: [PATCH 314/652] Change start_action methods Adapt each start_action method according to the action requirements. --- src/sardana/pool/poolacquisition.py | 55 +++++++++++++++-------- src/sardana/pool/test/test_acquisition.py | 17 ++++--- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index d2196895f6..54fa4d86a1 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -310,9 +310,8 @@ def prepare(self, config, acq_mode, value, synchronization=None, ctrls = config.get_timerable_ctrls(acq_synch=acq_sync_hw, enabled=True) ctrls_hw = get_hw_acq_items(ctrls, acq_mode) if len(ctrls_hw) > 0: - hw_args = (ctrls_hw, value) - hw_kwargs = {'repetitions': repetitions, - 'latency': latency} + hw_args = (ctrls_hw, value, repetitions, latency) + hw_kwargs = {} hw_kwargs.update(kwargs) self._hw_acq_args = ActionArgs(hw_args, hw_kwargs) @@ -326,10 +325,8 @@ def prepare(self, config, acq_mode, value, synchronization=None, ctrls_sw, master_sw = get_sw_acq_items(ctrls, master, acq_mode) if len(ctrls_sw) > 0: - sw_args = (ctrls_sw, value) - sw_kwargs = {'latency': latency, - 'master': master_sw, - 'synch': True} + sw_args = (ctrls_sw, value, master_sw) + sw_kwargs = {'synch': True} sw_kwargs.update(kwargs) self._sw_acq_args = ActionArgs(sw_args, sw_kwargs) @@ -345,11 +342,9 @@ def prepare(self, config, acq_mode, value, synchronization=None, master, acq_mode) if len(ctrls_sw_start) > 0: - sw_start_args = (ctrls_sw_start, value) - sw_start_kwargs = {'repetitions': repetitions, - 'latency': latency, - 'master': master_sw_start, - 'synch': True} + sw_start_args = (ctrls_sw_start, value, master_sw_start, + repetitions, latency) + sw_start_kwargs = {'synch': True} sw_start_kwargs.update(kwargs) self._sw_start_acq_args = ActionArgs(sw_start_args, sw_start_kwargs) @@ -402,8 +397,8 @@ def prepare(self, config, acq_mode, value, synchronization=None, nr_of_starts) self._prepared = True - def _prepare_ctrls(self, ctrls, value, repetitions, latency, - nr_of_starts): + @staticmethod + def _prepare_ctrls(ctrls, value, repetitions, latency, nr_of_starts): for ctrl in ctrls: axis = ctrl.master.axis pool_ctrl = ctrl.element @@ -418,7 +413,7 @@ def is_running(self): def run(self, *args, **kwargs): if not self._prepared: - raise RuntimeError('You must call first to prepare method.') + raise RuntimeError('You must call first "prepare" method.') if self._hw_acq_args is not None: self._hw_acq.run(*self._hw_acq_args.args, @@ -573,9 +568,9 @@ def in_acquisition(self, states): return True @DebugIt() - def start_action(self, ctrls, value, repetitions=1, latency=0, - master=None, index=None, acq_sleep_time=None, - nb_states_per_value=None, **kwargs): + def start_action(self, ctrls, value, master, repetitions, latency, + index, acq_sleep_time, nb_states_per_value, + **kwargs): """ Prepares everything for acquisition and starts it :param ctrls: List of enabled pool acquisition controllers @@ -758,6 +753,14 @@ class PoolAcquisitionHardware(PoolAcquisitionBase): def __init__(self, main_element, name="AcquisitionHardware"): PoolAcquisitionBase.__init__(self, main_element, name) + def start_action(self, ctrls, value, repetitions, latency, + acq_sleep_time=None, nb_states_per_value=None, + **kwargs): + PoolAcquisitionBase.start_action(self, ctrls, value, None, + repetitions, latency, None, + acq_sleep_time, nb_states_per_value, + **kwargs) + @DebugIt() def action_loop(self): i = 0 @@ -829,6 +832,12 @@ def __init__(self, main_element, name="AcquisitionSoftware", slaves=None): slaves = () self._slaves = slaves + def start_action(self, ctrls, value, master, index, acq_sleep_time=None, + nb_states_per_value=None, **kwargs): + PoolAcquisitionBase.start_action(self, ctrls, value, master, 1, 0, + index, acq_sleep_time, + nb_states_per_value, **kwargs) + @DebugIt() def action_loop(self): states, values = {}, {} @@ -896,6 +905,14 @@ class PoolAcquisitionSoftwareStart(PoolAcquisitionBase): def __init__(self, main_element, name="AcquisitionSoftwareStart"): PoolAcquisitionBase.__init__(self, main_element, name) + def start_action(self, ctrls, value, master, repetitions, latency, + acq_sleep_time=None, nb_states_per_value=None, + **kwargs): + PoolAcquisitionBase.start_action(self, ctrls, value, master, + repetitions, latency, None, + acq_sleep_time, nb_states_per_value, + **kwargs) + @DebugIt() def action_loop(self): i = 0 @@ -1043,7 +1060,7 @@ def __init__(self, main_element, name="0DAcquisition"): self._index = None PoolAction.__init__(self, main_element, name) - def start_action(self, conf_ctrls, index=None, acq_sleep_time=None, + def start_action(self, conf_ctrls, index, acq_sleep_time=None, nb_states_per_value=None, **kwargs): """Prepares everything for acquisition and starts it. diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index 4a85bc9180..3e94916862 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -129,7 +129,7 @@ def setUp(self): def event_received(self, *args, **kwargs): """Executes a single software triggered acquisition.""" - _, type_, value = args + _, type_, index = args name = type_.name if name == "active": if self.sw_acq_busy.is_set(): @@ -139,7 +139,7 @@ def event_received(self, *args, **kwargs): self.sw_acq_busy.set() args = self.sw_acq_args kwargs = self.sw_acq_kwargs - kwargs['idx'] = value + kwargs['index'] = index get_thread_pool().add(self.sw_acq.run, None, *args, @@ -189,9 +189,8 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, # acquisition action pending. self.sw_acq_busy = threading.Event() self.sw_acq.add_finish_hook(self.sw_acq_busy.clear) - - self.sw_acq_args = (sw_ctrls, integ_time) - self.sw_acq_kwargs = {"master": sw_master} + self.sw_acq_args = (sw_ctrls, integ_time, sw_master) + self.sw_acq_kwargs = {} total_interval = active_interval + passive_interval group = { @@ -203,7 +202,7 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, synchronization = [group] # get the current number of jobs jobs_before = get_thread_pool().qsize - self.hw_acq.run(hw_ctrls, integ_time, repetitions) + self.hw_acq.run(hw_ctrls, integ_time, repetitions, 0) self.synchronization.run(synch_ctrls, synchronization) # waiting for acquisition and synchronization to finish while (self.hw_acq.is_running() @@ -256,8 +255,8 @@ def acquire(self, integ_time, repetitions, latency_time): self.acquisition = self.create_action(PoolAcquisitionSoftwareStart, [self.ct_1_1]) - self.acq_args = (ctrls, integ_time, repetitions) - self.acq_kwargs = {"master": master} + self.acq_args = (ctrls, integ_time, master, repetitions, 0) + self.acq_kwargs = {} total_interval = integ_time + latency_time group = { @@ -317,7 +316,7 @@ def acquire(self, integ_time, repetitions, latency_time): synchronization = [group] # get the current number of jobs jobs_before = get_thread_pool().qsize - self.acquisition.run(ctrls, integ_time, repetitions) + self.acquisition.run(ctrls, integ_time, repetitions, 0) self.synchronization.run(synch_ctrls, synchronization) self.wait_finish() self.do_asserts(repetitions, jobs_before) From fd826dfc2eb1273e8d690d4b23d2f5db3ef9747e Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 31 Oct 2018 18:34:10 +0100 Subject: [PATCH 315/652] Return SoftrwareTrigger acq synch by default --- src/sardana/pool/poolacquisition.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 54fa4d86a1..d4bde7c196 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -434,7 +434,14 @@ def _get_action_for_element(self, element): elem_type = element.get_type() if elem_type in TYPE_TIMERABLE_ELEMENTS: config = self.main_element.configuration - acq_synch = config.get_acq_synch_by_channel(element) + try: + acq_synch = config.get_acq_synch_by_channel(element) + # when configuration was not yet set and one sets the + # measurement group's integration time (this may happen on Tango + # device initialization when memorized attributes are set we + # fallback to software acquisition + except KeyError: + acq_synch = AcqSynch.SoftwareTrigger if acq_synch in (AcqSynch.SoftwareTrigger, AcqSynch.SoftwareGate): return self._sw_acq From e520ad799a5c8a49be152db78b2f2fb5f44bc609 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 31 Oct 2018 18:34:55 +0100 Subject: [PATCH 316/652] Consider software start acq action ctrls in top acq action --- src/sardana/pool/poolacquisition.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index d4bde7c196..2bfd02df3b 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -509,6 +509,7 @@ def get_pool_controllers(self): ret = {} ret.update(self._hw_acq.get_pool_controllers()) ret.update(self._sw_acq.get_pool_controllers()) + ret.update(self._sw_start_acq.get_pool_controllers()) ret.update(self._0d_acq.get_pool_controllers()) return ret From 377fccf396a152016aaa61485961646c600a3a81 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Mon, 5 Nov 2018 11:01:35 +0100 Subject: [PATCH 317/652] Fix flake8 --- src/sardana/macroserver/msparameter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/macroserver/msparameter.py b/src/sardana/macroserver/msparameter.py index ca34c56c8b..c4de3c6328 100644 --- a/src/sardana/macroserver/msparameter.py +++ b/src/sardana/macroserver/msparameter.py @@ -469,7 +469,7 @@ def decodeRepeat(self, raw_param_repeat, param_repeat_def): if max_rep and len_rep > max_rep: msg = 'Found %d repetitions of param %s, max is %d' % \ (len_rep, name, max_rep) - raise SupernumeraryRepeat, msg + raise SupernumeraryRepeat(msg) # repeat params with only one member and only one repetition value are # allowed - encapsulate it in list and try to decode anyway if not is_non_str_seq(raw_param_repeat): From f8bb13e0956384f91df43a8c42f84521c3f196e8 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 5 Nov 2018 11:55:09 +0100 Subject: [PATCH 318/652] Rename variables to be more friendly --- .../macroserver/test/res/macros/testmacros.py | 89 +++++++++++-------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/src/sardana/macroserver/test/res/macros/testmacros.py b/src/sardana/macroserver/test/res/macros/testmacros.py index 4dcf2c51b1..5dfffd1fe5 100644 --- a/src/sardana/macroserver/test/res/macros/testmacros.py +++ b/src/sardana/macroserver/test/res/macros/testmacros.py @@ -9,17 +9,21 @@ class runMacro(Macro): 'runMacro' """ def run(self, *args): - - expect_params = (99, [1., 2.]) - macro, _ = self.prepareMacro("pt6_base", *expect_params) + params = expected_params = (99, [1., 2.]) + macro, _ = self.prepareMacro("pt6_base", *params) self.runMacro(macro) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg params = (99, 1., 2.) macro, _ = self.prepareMacro("pt6_base", *params) - expect_params = (99, [1., 2.]) + expected_params = (99, [1., 2.]) + self.runMacro(macro) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg + self.runMacro(macro) result = macro.data msg = FAIL_MSG % (result, expect_params) @@ -31,14 +35,20 @@ def run(self, *args): result = macro.data msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg + params = expected_params = ([92], True) + macro, _ = self.prepareMacro("pt10_base", *params) + self.runMacro(macro) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg params = (91, True) - expect_params = ([91], True) + expected_params = ([91], True) macro, _ = self.prepareMacro("pt10_base", *params) self.runMacro(macro) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg class createMacro(Macro): @@ -48,21 +58,21 @@ class createMacro(Macro): """ def run(self, *args): - expect_params = (99, [1., 2.]) - macro, pars = self.createMacro('pt6_base', *expect_params) + params = expected_params = (99, [1., 2.]) + macro, pars = self.createMacro('pt6_base', *params) self.runMacro(macro) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg params = (99, 1., 2.) - expect_params = (99, [1., 2.]) + expected_params = (99, [1., 2.]) self.runMacro(macro) macro, pars = self.createMacro('pt6_base', *params) self.runMacro(macro) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg expect_params = ([92], True) macro, _ = self.createMacro("pt10_base", *expect_params) @@ -70,14 +80,20 @@ def run(self, *args): result = macro.data msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg + params = expected_params = ([92], True) + macro, _ = self.createMacro("pt10_base", *params) + self.runMacro(macro) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg params = (91, True) - expect_params = ([91.], True) + expected_params = ([91.], True) macro, _ = self.createMacro("pt10_base", *params) self.runMacro(macro) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg class execMacro(Macro): @@ -86,19 +102,18 @@ class execMacro(Macro): 'execMacro' """ def run(self, *args): - - expect_params = (99, [1., 2.]) - macro = self.execMacro('pt6_base', *expect_params) + params = expected_params = (99, [1., 2.]) + macro = self.execMacro('pt6_base', *params) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg params = (99, 1., 2.) macro = self.execMacro('pt6_base', *params) result = macro.data - expect_params = (99, [1., 2.]) - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + expected_params = (99, [1., 2.]) + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg expect_params = ([92], True) macro = self.execMacro('pt10_base', *expect_params) @@ -107,19 +122,23 @@ def run(self, *args): msg = FAIL_MSG % (result, expect_params) assert expect_params == result, msg - expect_params = ([99.], True) + params = expected_params = ([92], True) + macro = self.execMacro('pt10_base', *params) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg + + expected_params = ([99.], True) macro = self.execMacro("pt10_base [99] True") - self.runMacro(macro) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg - expect_params = ([999.], True) + expected_params = ([999.], True) macro = self.execMacro("pt10_base", 999, True) - self.runMacro(macro) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg class pt6_base(Macro): From 8940e9039d90c9e099ec63720de442f7cdf527c6 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 5 Nov 2018 11:55:44 +0100 Subject: [PATCH 319/652] Add execution test for spock syntax string --- .../macroserver/test/res/macros/testmacros.py | 95 ++++++++++++++++--- 1 file changed, 80 insertions(+), 15 deletions(-) diff --git a/src/sardana/macroserver/test/res/macros/testmacros.py b/src/sardana/macroserver/test/res/macros/testmacros.py index 5dfffd1fe5..a55b5253b6 100644 --- a/src/sardana/macroserver/test/res/macros/testmacros.py +++ b/src/sardana/macroserver/test/res/macros/testmacros.py @@ -24,17 +24,22 @@ def run(self, *args): msg = FAIL_MSG % (result, expected_params) assert expected_params == result, msg + params = "pt6_base 99 [1. 2.]" + macro, _ = self.prepareMacro(params) + expected_params = (99, [1., 2.]) self.runMacro(macro) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg - expect_params = ([92], True) - macro, _ = self.prepareMacro("pt10_base", *expect_params) + params = "pt6_base 99 1. 2." + macro, _ = self.prepareMacro(params) + expected_params = (99, [1., 2.]) self.runMacro(macro) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg + params = expected_params = ([92], True) macro, _ = self.prepareMacro("pt10_base", *params) self.runMacro(macro) @@ -50,6 +55,21 @@ def run(self, *args): msg = FAIL_MSG % (result, expected_params) assert expected_params == result, msg + params = "pt10_base [91] True" + expected_params = ([91], True) + macro, _ = self.prepareMacro(params) + self.runMacro(macro) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg + + params = "pt10_base 91 True" + expected_params = ([91], True) + macro, _ = self.prepareMacro(params) + self.runMacro(macro) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg class createMacro(Macro): """ @@ -74,12 +94,22 @@ def run(self, *args): msg = FAIL_MSG % (result, expected_params) assert expected_params == result, msg - expect_params = ([92], True) - macro, _ = self.createMacro("pt10_base", *expect_params) + params = "pt6_base 99 [1. 2.]" + macro, _ = self.createMacro(params) + expected_params = (99, [1., 2.]) + self.runMacro(macro) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg + + params = "pt6_base 99 1. 2." + macro, _ = self.createMacro(params) + expected_params = (99, [1., 2.]) self.runMacro(macro) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg + params = expected_params = ([92], True) macro, _ = self.createMacro("pt10_base", *params) self.runMacro(macro) @@ -95,6 +125,21 @@ def run(self, *args): msg = FAIL_MSG % (result, expected_params) assert expected_params == result, msg + params = "pt10_base [91] True" + expected_params = ([91], True) + macro, _ = self.createMacro(params) + self.runMacro(macro) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg + + params = "pt10_base 91 True" + expected_params = ([91], True) + macro, _ = self.createMacro(params) + self.runMacro(macro) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg class execMacro(Macro): """ @@ -115,12 +160,19 @@ def run(self, *args): msg = FAIL_MSG % (result, expected_params) assert expected_params == result, msg - expect_params = ([92], True) - macro = self.execMacro('pt10_base', *expect_params) - self.runMacro(macro) + params = "pt6_base 99 [1 2]" + macro = self.execMacro(params) + expected_params = (99, [1., 2.]) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg + + params = "pt6_base 99 1 2" + macro = self.execMacro(params) + expected_params = (99, [1., 2.]) result = macro.data - msg = FAIL_MSG % (result, expect_params) - assert expect_params == result, msg + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg params = expected_params = ([92], True) macro = self.execMacro('pt10_base', *params) @@ -140,6 +192,19 @@ def run(self, *args): msg = FAIL_MSG % (result, expected_params) assert expected_params == result, msg + params = "pt10_base [91] True" + expected_params = ([91], True) + macro = self.execMacro(params) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg + + params = "pt10_base 91 True" + expected_params = ([91], True) + macro = self.execMacro(params) + result = macro.data + msg = FAIL_MSG % (result, expected_params) + assert expected_params == result, msg class pt6_base(Macro): """Macro with a number parameter followed by a list of numbers. From 6548a7750b57f6b02a818c9ca9ddcf3c9b2ac96b Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 5 Nov 2018 12:44:31 +0100 Subject: [PATCH 320/652] Change BaseMacroServerTestCase setUp method to pass pool_name as a property --- src/sardana/macroserver/macros/test/test_macro.py | 4 ++-- src/sardana/macroserver/macros/test/test_scanct.py | 3 ++- src/sardana/tango/macroserver/test/base.py | 10 ++++++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/sardana/macroserver/macros/test/test_macro.py b/src/sardana/macroserver/macros/test/test_macro.py index cc230f2834..861d37c6dc 100644 --- a/src/sardana/macroserver/macros/test/test_macro.py +++ b/src/sardana/macroserver/macros/test/test_macro.py @@ -15,9 +15,9 @@ def setUp(self): macros_test_path = '../../test/res/macros' source = os.path.join(os.path.dirname(__file__), macros_test_path) path = os.path.abspath(source) - environment = {'MacroPath': [path]} + properties = {'MacroPath': [path]} unittest.TestCase.setUp(self) - BaseMacroServerTestCase.setUp(self, properties=environment) + BaseMacroServerTestCase.setUp(self, properties) RunMacroTestCase.setUp(self) def tearDown(self): diff --git a/src/sardana/macroserver/macros/test/test_scanct.py b/src/sardana/macroserver/macros/test/test_scanct.py index b9972159df..dc2a551bbc 100644 --- a/src/sardana/macroserver/macros/test/test_scanct.py +++ b/src/sardana/macroserver/macros/test/test_scanct.py @@ -63,7 +63,8 @@ class ScanctTest(MeasSarTestTestCase, BaseMacroServerTestCase, def setUp(self): MeasSarTestTestCase.setUp(self) - BaseMacroServerTestCase.setUp(self, self.pool_name) + properties = {'PoolNames': self.pool_name} + BaseMacroServerTestCase.setUp(self, properties) RunStopMacroTestCase.setUp(self) def configure_motors(self, motor_names): diff --git a/src/sardana/tango/macroserver/test/base.py b/src/sardana/tango/macroserver/test/base.py index e017ee3dc6..621582964a 100755 --- a/src/sardana/tango/macroserver/test/base.py +++ b/src/sardana/tango/macroserver/test/base.py @@ -44,8 +44,12 @@ class BaseMacroServerTestCase(object): door_name = getattr(sardanacustomsettings, 'UNITTEST_DOOR_NAME', "door/demo1/1") - def setUp(self, pool_name=None, properties=None): - """Start MacroServer DS. + def setUp(self, properties=None): + """ + Start MacroServer DS. + + :param properties: dictionary with the macroserver properies. + """ try: db = PyTango.Database() @@ -68,8 +72,6 @@ def setUp(self, pool_name=None, properties=None): start_from = int(dev_name_parts[2]) self.door_name = get_free_device(db, prefix, start_from) self._msstarter.addNewDevice(self.door_name, klass='Door') - if pool_name is not None: - db.put_device_property(self.ms_name, {'PoolNames': pool_name}) # Add properties if properties: for key, values in properties.items(): From cbeea27457e3032feef907888653f7a0eb4ea5ac Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Mon, 5 Nov 2018 15:32:01 +0100 Subject: [PATCH 321/652] flake8 --- src/sardana/macroserver/test/res/macros/testmacros.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sardana/macroserver/test/res/macros/testmacros.py b/src/sardana/macroserver/test/res/macros/testmacros.py index a55b5253b6..638315865b 100644 --- a/src/sardana/macroserver/test/res/macros/testmacros.py +++ b/src/sardana/macroserver/test/res/macros/testmacros.py @@ -71,6 +71,7 @@ def run(self, *args): msg = FAIL_MSG % (result, expected_params) assert expected_params == result, msg + class createMacro(Macro): """ Macro to test the parameters parsing/decoding using the macro API, @@ -141,6 +142,7 @@ def run(self, *args): msg = FAIL_MSG % (result, expected_params) assert expected_params == result, msg + class execMacro(Macro): """ Macro to test the parameters parsing/decoding using the macro API, @@ -206,6 +208,7 @@ def run(self, *args): msg = FAIL_MSG % (result, expected_params) assert expected_params == result, msg + class pt6_base(Macro): """Macro with a number parameter followed by a list of numbers. Usages from Spock, ex.: From 242ed7d447c2bfdca85b54578ecbbdde5f5d594c Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Tue, 6 Nov 2018 12:37:03 +0100 Subject: [PATCH 322/652] check limits only if defined --- src/sardana/macroserver/scan/gscan.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index c04ea1a7e8..0962248fa1 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -383,11 +383,14 @@ def _check_moveables_limits(self): low = float(config.min_value) except ValueError: low = None + + if any((high, low)) and not any((m.min_value, m.max_value)): + self._macro.info("Scan range is not defined for %s and could " + "not be verified against motor limits." + % m.moveable.getName()) + for pos in (m.min_value, m.max_value): if pos is None: - self._macro.warning("Macro did not define position for %s." - " Limit check was not possible." - % m.moveable.getName()) continue if high is not None: if float(pos) > high: From f4d5fec9ae82d90e8c2d0569f0fc04718cafd171 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 7 Nov 2018 13:16:57 +0100 Subject: [PATCH 323/652] Update MG's master timer and monitor in user configuration --- src/sardana/pool/poolmeasurementgroup.py | 36 +++++++++++------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 3bcb2cba76..41699c4375 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -230,8 +230,6 @@ def __init__(self, parent=None): self._master_monitor_sw_start = None self._label = None self._description = None - self._master_timer = None - self._master_monitor = None self._user_confg = {} self._channel_acq_synch = {} self._ctrl_acq_synch = {} @@ -316,8 +314,6 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): master_monitor_sw = None master_timer_sw_start = None master_monitor_sw_start = None - master_timer = None - master_monitor = None master_timer_idx_sw = float("+inf") master_monitor_idx_sw = float("+inf") master_timer_idx_sw_start = float("+inf") @@ -327,13 +323,6 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): ctrl_acq_synch = {} user_config = {} - # Update the configuration for user - user_config['controllers'] = {} - user_config = {} - if 'timer' in cfg: - user_config['timer'] = cfg['timer'] - if 'monitor' in cfg: - user_config['monitor'] = cfg['monitor'] user_config['controllers'] = {} user_config['label'] = label user_config['description'] = description @@ -447,13 +436,6 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): if ch_name == ctrl_data['monitor']: ctrl_item.monitor = ch_item - # Update measurement configuration master timer - if ch_name == cfg.get('timer', None): - master_timer = ch_item - - # Update measurement configuration master timer - if ch_name == cfg.get('monitor', None): - master_monitor = ch_item if ch_item.enabled: ctrl_enabled = True @@ -505,9 +487,23 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): for conf_synch_ctrl in synch_ctrls: conf_synch_ctrl.update_state() + # Fill user configuration with measurement group's timer & monitor + # This is a backwards compatibility cause the measurement group's + # timer & monitor are not used + if master_timer_sw is not None: + user_config['timer'] = master_timer_sw.full_name + elif master_timer_sw_start is not None: + user_config['timer'] = master_timer_sw_start.full_name + else: + user_config['timer'] = cfg['timer'] + + if master_monitor_sw is not None: + user_config['monitor'] = master_monitor_sw.full_name + elif master_monitor_sw_start is not None: + user_config['monitor'] = master_monitor_sw_start.full_name + else: + user_config['monitor'] = cfg['monitor'] # Update internals values - self._master_monitor = master_monitor - self._master_timer = master_timer self._label = label self._description = description self._timerable_ctrls = timerable_ctrls From e4dd5ebb2b90d25dbc1314eab4a1a46e0b6285e4 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 7 Nov 2018 13:18:11 +0100 Subject: [PATCH 324/652] PEP8 --- src/sardana/pool/poolmeasurementgroup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 41699c4375..c98662b1e3 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -42,8 +42,7 @@ # TODO: For Taurus 4 compatibility from taurus.core.tango.tangovalidator import TangoAttributeNameValidator -from sardana import State, ElementType, \ - TYPE_EXP_CHANNEL_ELEMENTS +from sardana import State, ElementType, TYPE_EXP_CHANNEL_ELEMENTS from sardana.sardanaevent import EventType from sardana.pool.pooldefs import AcqMode, SynchParam, AcqSynch, \ SynchDomain, AcqSynchType @@ -503,6 +502,7 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): user_config['monitor'] = master_monitor_sw_start.full_name else: user_config['monitor'] = cfg['monitor'] + # Update internals values self._label = label self._description = description From c803670433ef3129df984dae1251a21f897ec77e Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 7 Nov 2018 13:18:58 +0100 Subject: [PATCH 325/652] Fix FQDN convertion for unit test cases --- src/sardana/pool/poolmeasurementgroup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index c98662b1e3..6c6a0c01ad 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -119,6 +119,8 @@ def _to_fqdn(name, logger=None): # if Taurus3 in use just continue except ImportError: pass + if full_name is None: + full_name = name if full_name != name and logger: msg = ("PQDN full name is deprecated in favor of FQDN full name." " Re-apply configuration in order to upgrade.") From 39c51c538bb76e4f0f1d06d2c35e1218360780fa Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 7 Nov 2018 13:24:31 +0100 Subject: [PATCH 326/652] Fix several issues with MG configuration * External attributes - Tango * Validation whether ctrl's timer/monitor is enabled * Creation of measurement group (fill default configuration) * element assignment to actions based on synchronizer's type (sw vs. hw) --- src/sardana/pool/poolmeasurementgroup.py | 163 ++++++++++++++++------- 1 file changed, 113 insertions(+), 50 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 6c6a0c01ad..ba0b8f9df7 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -129,6 +129,7 @@ def _to_fqdn(name, logger=None): class ConfigurationItem(object): + def __init__(self, element, attrs=None): self._element = weakref.ref(element) self.enabled = True @@ -191,6 +192,52 @@ def get_channels(self, enabled=None): else: return list(self._channels_disabled) + def validate(self): + pass + + +class TimerableControllerConfiguration(ControllerConfiguration): + + def update_timer(self): + self._update_master("timer") + + def update_monitor(self): + self._update_master("monitor") + + def _update_master(self, role): + master = getattr(self, role, None) + if master is None: + idx = float("+inf") + for channel in self._channels_enabled: + if channel.index > idx: + continue + master = channel + idx = channel.index + else: + for channel in self._channels_enabled: + if channel.full_name == master: + master = channel + setattr(self, role, master) + + def validate(self): + # validate if the timer and monitor are disabled if the + # controller is enabled + if self.enabled \ + and not self.timer.enabled \ + and not self.monitor.enabled: + err_msg = 'The channel {0} used as timer and the channel ' \ + '{1} used as monitor are disabled. One of them ' \ + 'must be enabled'.format(self.timer.name, + self.monitor.name) + raise ValueError(err_msg) + + +class ExternalControllerConfiguration(ControllerConfiguration): + + def __init__(self, element, attrs=None): + ControllerConfiguration.__init__(self, self, attrs) + self.full_name = element + class ChannelConfiguration(ConfigurationItem): """Configuration: 'index', 'enabled', 'output', 'plot_type', 'plot_axes', @@ -204,6 +251,37 @@ def __init__(self, element, attrs=None): self.enabled = False +def build_measurement_configuration(user_elements): + user_config = {} + external_user_elements = [] + user_config["controllers"] = controllers = {} + + for index, element in enumerate(user_elements): + elem_type = element.get_type() + if elem_type == ElementType.External: + external_user_elements.append((index, element)) + continue + + ctrl = element.controller + ctrl_data = controllers.get(ctrl.full_name) + + if ctrl_data is None: + controllers[ctrl.full_name] = ctrl_data = {} + ctrl_data['channels'] = channels = {} + else: + channels = ctrl_data['channels'] + channels[element.full_name] = channel_data = {} + channel_data['index'] = index + + if len(external_user_elements) > 0: + controllers['__tango__'] = ctrl_data = {} + ctrl_data['channels'] = channels = {} + for index, element in external_user_elements: + channels[element.full_name] = channel_data = {} + channel_data['index'] = index + return user_config + + class MeasurementConfiguration(object): """ .. todo: Reject configuration with errors: @@ -354,7 +432,7 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): user_config['controllers'][ctrl_name] = user_config_ctrl = {} ctrl_conf = {} - synchronizer = ctrl_data.get('synchronizer', None) + synchronizer = ctrl_data.get('synchronizer', 'software') conf_synch = None if synchronizer is None or synchronizer == 'software': ctrl_conf['synchronizer'] = 'software' @@ -395,72 +473,64 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): ctrl_conf['synchronization'] = synchronization user_config_ctrl['synchronization'] = synchronization - ctrl_conf['timer'] = None - ctrl_conf['monitor'] = None - ctrl_item = ControllerConfiguration(ctrl, ctrl_conf) acq_synch = None - if not external and ctrl.is_timerable(): + if external: + ctrl_item = ExternalControllerConfiguration(ctrl) + elif ctrl.is_timerable(): is_software = synchronizer == 'software' acq_synch = AcqSynch.from_synch_type(is_software, synchronization) ctrl_acq_synch[ctrl] = acq_synch + ctrl_item = TimerableControllerConfiguration(ctrl, ctrl_conf) + else: + ctrl_item = ControllerConfiguration(ctrl, ctrl_conf) ctrl_enabled = False if 'channels' in ctrl_data: user_config_ctrl['channels'] = user_config_channel = {} for ch_name, ch_data in ctrl_data['channels'].items(): - if external: validator = TangoAttributeNameValidator() - params = validator.getParams(ch_data['full_name']) + full_name = ch_data.get('full_name', ch_name) + params = validator.getParams(full_name) params['pool'] = pool channel = PoolExternalObject(**params) else: if to_fqdn: ch_name = _to_fqdn(ch_name, logger=self._parent) channel = pool.get_element_by_full_name(ch_name) - ch_data = self._fill_channel_data(channel, ch_data) user_config_channel[ch_name] = ch_data ch_item = ChannelConfiguration(channel, ch_data) ch_item.controller = ctrl_item ctrl_item.add_channel(ch_item) if ch_item.enabled: - user_elem_ids[ch_item.index] = channel.id - - # Update controller timer - if ch_name == ctrl_data['timer']: - ctrl_item.timer = ch_item - - # Update controller monitor - if ch_name == ctrl_data['monitor']: - ctrl_item.monitor = ch_item - + if external: + id_ = channel.full_name + else: + id_ = channel.id + user_elem_ids[ch_item.index] = id_ if ch_item.enabled: ctrl_enabled = True if acq_synch is not None: channel_acq_synch[channel] = acq_synch - - # Update syncrhonizer state + if not external and ctrl.is_timerable(): + ctrl_item.update_timer() + ctrl_item.update_monitor() + user_config_ctrl['timer'] = ctrl_item.timer.full_name + user_config_ctrl['monitor'] = ctrl_item.monitor.full_name + # Update synchronizer state if conf_synch is not None: conf_synch.enabled = ctrl_enabled - # validate if the timer and monitor are disabled if the - # controller is enabled - if ctrl_enabled and not ctrl_item.timer.enabled and \ - not ctrl_item.monitor.enabled: - timer_label = ctrl_item.timer.label - monitor_label = ctrl_item.monitor.label - - err_msg = 'The channel {0} used as timer and the channel ' \ - '{1} used as monitor are disabled. One of them ' \ - 'must be enabled'.format(timer_label, monitor_label) - raise ValueError(err_msg) + ctrl_item.validate() - if not external and ctrl.is_timerable(): + if external: + other_ctrls.append(ctrl_item) + elif ctrl.is_timerable(): timerable_ctrls[acq_synch].append(ctrl_item) # Find master timer/monitor the system take the channel with # less index @@ -481,8 +551,6 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): master_monitor_idx_sw_start = ctrl_item.monitor.index elif ctrl.get_ctrl_types()[0] == ElementType.ZeroDExpChannel: zerod_ctrls.append(ctrl_item) - else: - other_ctrls.append(ctrl_item) # Update synchronizer controller states for conf_synch_ctrl in synch_ctrls: @@ -534,10 +602,8 @@ def _fill_channel_data(self, channel, channel_data): """ Fills the channel default values for the given channel dictionary """ - name = channel.name full_name = channel.full_name - ctrl_name = channel.controller.full_name source = channel.get_source() ndim = None ctype = channel.get_type() @@ -581,8 +647,11 @@ def _fill_channel_data(self, channel, channel_data): channel_data['data_units'] = channel_data.get('data_units', 'No unit') channel_data['nexus_path'] = channel_data.get('nexus_path', '') channel_data['shape'] = channel_data.get('shape', []) - channel_data['_controller_name'] = channel_data.get('_controller_name', - ctrl_name) + + if ctype != ElementType.External: + ctrl_name = channel.controller.full_name + channel_data['_controller_name'] = channel_data.get( + '_controller_name', ctrl_name) return channel_data @@ -605,17 +674,11 @@ def __init__(self, **kwargs): kwargs['elem_type'] = ElementType.MeasurementGroup PoolGroupElement.__init__(self, **kwargs) - # TODO: Check if it needed - # configuration = kwargs.get("configuration") - # self.set_configuration(configuration) - # # if the configuration was never "really" written e.g. newly created - # # MG - # # just sets it now so the _channe_to_acq_synch and ctrl_to_acq_synch - # # are properly populated - # # TODO: make it more elegant - # if configuration is None: - # configuration = self.configuration.configuration - # self.set_configuration(configuration, propagate=0, to_fqdn=False) + configuration = kwargs.get("configuration") + if configuration is None: + user_elements = self.get_user_elements() + configuration = build_measurement_configuration(user_elements) + self.set_configuration_from_user(configuration) def _create_action_cache(self): acq_name = "%s.Acquisition" % self._name @@ -808,7 +871,7 @@ def set_moveable(self, moveable, propagate=1, to_fqdn=True): def get_latency_time(self): latency_time = 0 - pool_ctrls = self.acquisition.get_pool_controllers() + pool_ctrls = self.get_pool_controllers() for pool_ctrl in pool_ctrls: if not pool_ctrl.is_timerable(): continue From dd253f13db4be8b43a2d6e768becfe1046244251 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 7 Nov 2018 13:25:04 +0100 Subject: [PATCH 327/652] Add infrastructure for 2D tests --- src/sardana/pool/test/base.py | 28 +++++++++++++++++-- src/sardana/pool/test/helper.py | 12 +++++++- .../pool/test/test_measurementgroup.py | 6 ++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/test/base.py b/src/sardana/pool/test/base.py index 68bc15789d..19493afe0c 100644 --- a/src/sardana/pool/test/base.py +++ b/src/sardana/pool/test/base.py @@ -31,6 +31,7 @@ createPoolCounterTimer, createPoolTriggerGate, createPoolMotor, createElemConf, createPoolZeroDExpChannel, + createPoolTwoDExpChannel, createPoolPseudoCounter, createPoolPseudoMotor) @@ -65,6 +66,15 @@ def createZeroDElement(self, ctrl_obj, name, axis): self.pool.add_element(elem_obj) return elem_obj + def createTwoDElement(self, ctrl_obj, name, axis): + e_cfg = createElemConf(self.pool, axis, name) + elem_obj = createPoolTwoDExpChannel(self.pool, ctrl_obj, e_cfg) + ctrl_obj.add_element(elem_obj) + # TwoD elements + self.twods[name] = elem_obj + self.pool.add_element(elem_obj) + return elem_obj + def createTGElement(self, ctrl_obj, name, axis): e_cfg = createElemConf(self.pool, axis, name) elem_obj = createPoolTriggerGate(self.pool, ctrl_obj, e_cfg) @@ -104,14 +114,17 @@ def createPMElement(self, ctrl_obj, name, axis, elements=[]): def setUp(self): """Create a collection of controllers and elements. """ - self.nctctrls = self.nzerodctrls = self.ntgctrls = self.nmotctrls = 4 - self.nctelems = self.nzerodelems = self.ntgelems = self.nmotelems = 5 + self.nctctrls = self.nzerodctrls = self.ntwodctrls = self.ntgctrls = \ + self.nmotctrls = 4 + self.nctelems = self.nzerodelems = self.ntwodelems = self.ntgelems = \ + self.nmotelems = 5 self.pool = FakePool(self.POOLPATH, self.LOGLEVEL) # Use debug mode self.ctrls = {} self.cts = {} self.zerods = {} + self.twods = {} self.tgs = {} self.mots = {} self.pcs = {} @@ -136,6 +149,17 @@ def setUp(self): for axis in range(1, self.nzerodelems + 1): name = '_test_0d_%s_%s' % (ctrl, axis) self.createZeroDElement(ctrl_obj, name, axis) + # Create ntwodctrls TwoD ctrls + for ctrl in range(1, self.ntwodctrls + 1): + name = '_test_2d_ctrl_%s' % ctrl + ctrl_obj = self.createController(name, + 'DummyTwoDController', + 'DummyTwoDController.py') + # Create nelems TwoD elements for each ctrl + for axis in range(1, self.ntwodelems + 1): + name = '_test_2d_%s_%s' % (ctrl, axis) + self.createTwoDElement(ctrl_obj, name, axis) + # Create ntgctrls TG ctrls for ctrl in range(1, self.ntgctrls + 1): name = '_test_tg_ctrl_%s' % ctrl diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index e63b302614..7ba25d9afe 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -24,7 +24,8 @@ ############################################################################## __all__ = ['createPoolController', 'createPoolCounterTimer', - 'createPoolZeroDExpChannel', 'createPoolTriggerGate', + 'createPoolZeroDExpChannel', 'createPoolTwoDExpChannel', + 'createPoolTriggerGate', 'createPoolMotor', 'createPoolPseudoCounter', 'createPoolPseudoMotor', 'createPoolMeasurementGroup', 'createControllerConfiguration', @@ -39,6 +40,7 @@ PoolPseudoMotorController, PoolPseudoCounterController from sardana.pool.poolcountertimer import PoolCounterTimer from sardana.pool.poolzerodexpchannel import Pool0DExpChannel +from sardana.pool.pooltwodexpchannel import Pool2DExpChannel from sardana.pool.pooltriggergate import PoolTriggerGate from sardana.pool.poolmotor import PoolMotor from sardana.pool.poolpseudocounter import PoolPseudoCounter @@ -103,6 +105,14 @@ def createPoolZeroDExpChannel(pool, poolcontroller, conf): kwargs['ctrl'] = poolcontroller return Pool0DExpChannel(**kwargs) +def createPoolTwoDExpChannel(pool, poolcontroller, conf): + '''Method to create a ZeroDExpChannel using a configuration dictionary + ''' + kwargs = copy.deepcopy(conf) + kwargs['pool'] = pool + kwargs['ctrl'] = poolcontroller + return Pool2DExpChannel(**kwargs) + def createPoolTriggerGate(pool, poolcontroller, conf): '''Method to create a PoolTriggerGate using a configuration dictionary diff --git a/src/sardana/pool/test/test_measurementgroup.py b/src/sardana/pool/test/test_measurementgroup.py index 7c50c3ce77..5dd179571e 100644 --- a/src/sardana/pool/test/test_measurementgroup.py +++ b/src/sardana/pool/test/test_measurementgroup.py @@ -344,7 +344,13 @@ def tearDown(self): [('_test_ct_2_1', '_test_tg_1_1', AcqSynchType.Start), ('_test_ct_2_2', '_test_tg_1_1', AcqSynchType.Start)]] +doc_15 = 'Acquisition using with 1 2D channel using software synchronization' +config_15 = [[('_test_2d_1_1', 'software', AcqSynchType.Trigger)]] + +# TODO: listener is not ready to handle 2D +# @insertTest(helper_name='meas_cont_acquisition', test_method_doc=doc_15, +# config=config_15, synchronization=synchronization1) @insertTest(helper_name='meas_cont_acquisition', test_method_doc=doc_14, config=config_14, synchronization=synchronization1) @insertTest(helper_name='meas_contpos_acquisition', test_method_doc=doc_12, From aed968255f27495f8869fa91b0a5f81059fc25dd Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 7 Nov 2018 13:25:26 +0100 Subject: [PATCH 328/652] Refactor start of acquisition action --- src/sardana/pool/poolacquisition.py | 43 +++++++++++++++-------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 2bfd02df3b..5e5b16e98b 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -285,6 +285,9 @@ def prepare(self, config, acq_mode, value, synchronization=None, self._hw_acq_args = None self._synch_args = None self._prepared = False + ctrls_hw = [] + ctrls_sw = [] + ctrls_sw_start = [] for elem in self.get_elements(): elem.put_state(None) @@ -303,13 +306,12 @@ def prepare(self, config, acq_mode, value, synchronization=None, repetitions = synchronization.repetitions latency = synchronization.passive_time - # Prepare controllers synchronized by hardware acq_sync_hw = [AcqSynch.HardwareTrigger, AcqSynch.HardwareStart, AcqSynch.HardwareGate] ctrls = config.get_timerable_ctrls(acq_synch=acq_sync_hw, enabled=True) - ctrls_hw = get_hw_acq_items(ctrls, acq_mode) - if len(ctrls_hw) > 0: + if len(ctrls) > 0: + ctrls_hw = get_hw_acq_items(ctrls, acq_mode) hw_args = (ctrls_hw, value, repetitions, latency) hw_kwargs = {} hw_kwargs.update(kwargs) @@ -318,13 +320,14 @@ def prepare(self, config, acq_mode, value, synchronization=None, # Prepare controllers synchronized by software Trigger and Gate acq_sync_sw = [AcqSynch.SoftwareGate, AcqSynch.SoftwareTrigger] ctrls = config.get_timerable_ctrls(acq_synch=acq_sync_sw, enabled=True) - if acq_mode is AcqMode.Timer: - master = config.get_master_timer_software() - elif acq_mode is AcqMode.Monitor: - master = config.get_master_monitor_software() + if len(ctrls) > 0: + if acq_mode is AcqMode.Timer: + master = config.get_master_timer_software() + elif acq_mode is AcqMode.Monitor: + master = config.get_master_monitor_software() + + ctrls_sw, master_sw = get_sw_acq_items(ctrls, master, acq_mode) - ctrls_sw, master_sw = get_sw_acq_items(ctrls, master, acq_mode) - if len(ctrls_sw) > 0: sw_args = (ctrls_sw, value, master_sw) sw_kwargs = {'synch': True} sw_kwargs.update(kwargs) @@ -333,15 +336,15 @@ def prepare(self, config, acq_mode, value, synchronization=None, # Prepare controllers synchronized by software Start ctrls = config.get_timerable_ctrls(acq_synch=AcqSynch.SoftwareStart, enabled=True) - if acq_mode is AcqMode.Timer: - master = config.get_master_timer_software_start() - elif acq_mode is AcqMode.Monitor: - master = config.get_master_monitor_software_start() - - ctrls_sw_start, master_sw_start = get_sw_start_acq_items(ctrls, - master, - acq_mode) - if len(ctrls_sw_start) > 0: + if len(ctrls) > 0: + if acq_mode is AcqMode.Timer: + master = config.get_master_timer_software_start() + elif acq_mode is AcqMode.Monitor: + master = config.get_master_monitor_software_start() + + ctrls_sw_start, master_sw_start = get_sw_start_acq_items(ctrls, + master, + acq_mode) sw_start_args = (ctrls_sw_start, value, master_sw_start, repetitions, latency) sw_start_kwargs = {'synch': True} @@ -351,8 +354,8 @@ def prepare(self, config, acq_mode, value, synchronization=None, # Prepare 0D controllers ctrls = config.get_zerod_ctrls(enabled=True) - ctrls_acq_0d = get_0d_acq_items(ctrls) - if len(ctrls_acq_0d) > 0: + if len(ctrls) > 0: + ctrls_acq_0d = get_0d_acq_items(ctrls) zerod_args = (ctrls_acq_0d,) zerod_kwargs = {'synch': True} zerod_kwargs.update(kwargs) From 56a1aca1cc40408ece046028aedf63523ce998c9 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 7 Nov 2018 13:37:02 +0100 Subject: [PATCH 329/652] Fix dummy trigger/gate controller tests --- .../test/test_DummyTriggerGateController.py | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/sardana/pool/poolcontrollers/test/test_DummyTriggerGateController.py b/src/sardana/pool/poolcontrollers/test/test_DummyTriggerGateController.py index f44063b0c7..bb54e75288 100644 --- a/src/sardana/pool/poolcontrollers/test/test_DummyTriggerGateController.py +++ b/src/sardana/pool/poolcontrollers/test/test_DummyTriggerGateController.py @@ -4,10 +4,9 @@ from sardana.pool.poolsynchronization import PoolSynchronization from sardana.pool.pooldefs import SynchDomain, SynchParam -from sardana.pool.test import (FakePool, createPoolController, - createPoolTriggerGate, dummyPoolTGCtrlConf01, - dummyTriggerGateConf01, - createPoolSynchronizationConfiguration) +from sardana.pool.test import FakePool, createPoolController, \ + createPoolTriggerGate, dummyPoolTGCtrlConf01, dummyTriggerGateConf01, \ + createControllerConfiguration synchronization1 = [{SynchParam.Delay: {SynchDomain.Time: 0}, SynchParam.Active: {SynchDomain.Time: .03}, @@ -43,11 +42,8 @@ def setUp(self): # marrying the element with the controller dummy_tg_ctrl.add_element(self.dummy_tg) - self.cfg = createPoolSynchronizationConfiguration((dummy_tg_ctrl,), - ((self.dummy_tg,),)) - - # TODO: The TriggerGate should have a configuration - self.dummy_tg.configuration = self.cfg + self.ctrl_conf = createControllerConfiguration(dummy_tg_ctrl, + [self.dummy_tg]) # marrying the element with the action self.tg_action = PoolSynchronization(self.dummy_tg) @@ -56,11 +52,8 @@ def setUp(self): def generation(self, synchronization): """Verify that the created PoolTGAction start_action starts correctly the involved controller.""" - args = () - kwargs = {'config': self.cfg, - 'synchronization': synchronization - } - self.tg_action.start_action(*args, **kwargs) + args = ([self.ctrl_conf], synchronization) + self.tg_action.start_action(*args) self.tg_action.action_loop() # TODO: add asserts applicable to a dummy controller e.g. listen to # state changes and verify if the change ON->MOVING-ON was emitted From 392b34a93ef756b7a5e7252c674eece849772f22 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 7 Nov 2018 15:23:18 +0100 Subject: [PATCH 330/652] Set full_name in dummy configurations --- src/sardana/pool/test/dummyconfs.py | 52 +++++++++++------------------ 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/src/sardana/pool/test/dummyconfs.py b/src/sardana/pool/test/dummyconfs.py index 0b2e46307c..69206813a7 100644 --- a/src/sardana/pool/test/dummyconfs.py +++ b/src/sardana/pool/test/dummyconfs.py @@ -31,13 +31,12 @@ 'dummyCounterTimerConf03', 'dummyCounterTimerConf04', 'dummyTriggerGateConf01', 'dummyTriggerGateConf02', 'dummyTriggerGateConf03', 'dummyTriggerGateConf04', - 'softwarePoolTGCtrlConf01', 'dummyPoolMotorCtrlConf01', - 'dummyMotorConf01', 'dummyMotorConf02'] + 'dummyPoolMotorCtrlConf01', 'dummyMotorConf01', 'dummyMotorConf02'] # Pool Measurement Group '''Minimum configuration to create a Pool MeasurementGroup''' -dummyMeasurementGroupConf01 = {'full_name': '', +dummyMeasurementGroupConf01 = {'full_name': 'mntgrp01', 'id': None, 'name': '', 'pool': None, @@ -47,7 +46,7 @@ # Pool Ctrls '''Minimum configuration to create a Pool CounterTimer controller''' dummyPoolCTCtrlConf01 = {'class_info': None, - 'full_name': '', + 'full_name': 'dctctrl01', 'id': 1, 'klass': 'DummyCounterTimerController', 'lib_info': None, @@ -60,7 +59,7 @@ '''Second minimum configuration to create a Pool CounterTimer controller''' dummyPoolCTCtrlConf02 = {'class_info': None, - 'full_name': '', + 'full_name': 'dctctrl02', 'id': 2, 'klass': 'DummyCounterTimerController', 'lib_info': None, @@ -74,7 +73,7 @@ '''Minimum configuration to create a TangoAttributeCTcontroller''' TangoAttributeCTCtrlConf01 = {'class_info': None, 'ctrl_info': '', - 'full_name': '', + 'full_name': 'tctctrl01', 'id': 1, 'klass': 'TangoAttrCTController', 'lib_info': None, @@ -89,7 +88,7 @@ '''Second minimum configuration to create a TangoAttributeCTcontroller''' TangoAttributeCTCtrlConf02 = {'class_info': None, 'ctrl_info': '', - 'full_name': '', + 'full_name': 'tctctrl02', 'id': 2, 'klass': 'TangoAttrCTController', 'lib_info': None, @@ -103,7 +102,7 @@ '''Minimum configuration to create a Pool TriggerGate controller''' dummyPoolTGCtrlConf01 = {'class_info': None, - 'full_name': '', + 'full_name': 'dtgctrl01', 'id': 1, 'klass': 'DummyTriggerGateController', 'lib_info': None, @@ -114,22 +113,9 @@ 'role_ids': '', 'type': 'TGChannel'} -'''Minimum configuration to create a Pool Software TriggerGate controller''' -softwarePoolTGCtrlConf01 = {'class_info': None, - 'full_name': '', - 'id': 1, - 'klass': 'SoftwareTriggerGateController', - 'lib_info': None, - 'library': 'SoftwareTriggerGateController.py', - 'name': '', - 'pool': None, - 'properties': {}, - 'role_ids': '', - 'type': 'TGChannel'} - '''Minimum configuration to create a Pool TriggerGate controller''' dummyPoolTGCtrlConf02 = {'class_info': None, - 'full_name': '', + 'full_name': 'dtgctrl01', 'id': 2, 'klass': 'DummyTriggerGateController', 'lib_info': None, @@ -142,7 +128,7 @@ '''Minimum configuration to create a Pool Motor controller''' dummyPoolMotorCtrlConf01 = {'class_info': None, - 'full_name': '', + 'full_name': 'dmotctrl01', 'id': 1, 'klass': 'DummyMotorController', 'lib_info': None, @@ -157,7 +143,7 @@ '''Minimum configuration to create a Pool CounterTimer''' dummyCounterTimerConf01 = {'axis': 1, 'ctrl': None, - 'full_name': '', + 'full_name': 'dct01', 'id': 2, 'name': '', 'pool': None} @@ -165,7 +151,7 @@ '''Second minimum configuration to create a Pool CounterTimer''' dummyCounterTimerConf02 = {'axis': 2, 'ctrl': None, - 'full_name': '', + 'full_name': 'dct02', 'id': 3, 'name': '', 'pool': None} @@ -173,7 +159,7 @@ '''Third minimum configuration to create a Pool CounterTimer''' dummyCounterTimerConf03 = {'axis': 1, 'ctrl': None, - 'full_name': '', + 'full_name': 'dct03', 'id': 2, 'name': '', 'pool': None} @@ -181,7 +167,7 @@ '''Fourth minimum configuration to create a Pool CounterTimer''' dummyCounterTimerConf04 = {'axis': 2, 'ctrl': None, - 'full_name': '', + 'full_name': 'dct04', 'id': 3, 'name': '', 'pool': None} @@ -189,7 +175,7 @@ '''Minimum configuration to create a Pool TriggerGate''' dummyTriggerGateConf01 = {'axis': 1, 'ctrl': None, - 'full_name': '', + 'full_name': 'dtg01', 'id': 2, 'name': '', 'pool': None} @@ -197,7 +183,7 @@ '''Second minimum configuration to create a Pool TriggerGate''' dummyTriggerGateConf02 = {'axis': 2, 'ctrl': None, - 'full_name': '', + 'full_name': 'dtg02', 'id': 3, 'name': '', 'pool': None} @@ -205,7 +191,7 @@ '''Third minimum configuration to create a Pool TriggerGate''' dummyTriggerGateConf03 = {'axis': 3, 'ctrl': None, - 'full_name': '', + 'full_name': 'dtg03', 'id': 4, 'name': '', 'pool': None} @@ -213,7 +199,7 @@ '''Fourth minimum configuration to create a Pool TriggerGate''' dummyTriggerGateConf04 = {'axis': 4, 'ctrl': None, - 'full_name': '', + 'full_name': 'dtg04', 'id': 5, 'name': '', 'pool': None} @@ -221,7 +207,7 @@ '''Minimum configuration to create a Pool Motor''' dummyMotorConf01 = {'axis': 1, 'ctrl': None, - 'full_name': '', + 'full_name': 'dmot01', 'id': 1, 'name': '', 'pool': None} @@ -229,7 +215,7 @@ '''Minimum configuration to create a Pool Motor''' dummyMotorConf02 = {'axis': 2, 'ctrl': None, - 'full_name': '', + 'full_name': 'dmot02', 'id': 1, 'name': '', 'pool': None} From a05d354c71c3ebe12bd9b0d26391f7922f0bdd79 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 7 Nov 2018 16:23:49 +0100 Subject: [PATCH 331/652] Remove useless test --- .../test/test_DummyCounterTimerController.py | 51 ------------------- 1 file changed, 51 deletions(-) delete mode 100644 src/sardana/pool/poolcontrollers/test/test_DummyCounterTimerController.py diff --git a/src/sardana/pool/poolcontrollers/test/test_DummyCounterTimerController.py b/src/sardana/pool/poolcontrollers/test/test_DummyCounterTimerController.py deleted file mode 100644 index 1955ad1213..0000000000 --- a/src/sardana/pool/poolcontrollers/test/test_DummyCounterTimerController.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python - -############################################################################## -## -# This file is part of Sardana -## -# http://www.tango-controls.org/static/sardana/latest/doc/html/index.html -## -# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain -## -# Sardana 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. -## -# Sardana 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 Sardana. If not, see . -## -############################################################################## - -from taurus.external import unittest -from taurus.test import insertTest -from sardana.pool.poolsynchronization import PoolSynchronization -from sardana.pool.test.test_acquisition import AcquisitionTestCase -import logging - - -@insertTest(helper_name='hw_step_acquisition', repetitions=1, - integ_time=0.4) -class DummyCounterTimerControllerTestCase(AcquisitionTestCase, unittest.TestCase): - """Integration test. - """ - chn_ctrl_name = '_test_ct_ctrl_1' - chn_elem_name1 = '_test_ct_1_1' - - def setUp(self): - """#Create a Controller, TriggerGate and PoolSynchronization objects from - #Ni660XTriggerGateController and Ni660XPositionCTCtrl configurations. - """ - unittest.TestCase.setUp(self) - AcquisitionTestCase.setUp(self) - self.channel_names.append(self.chn_elem_name1) - - def tearDown(self): - AcquisitionTestCase.tearDown(self) - unittest.TestCase.tearDown(self) From b0835a01c3135178c6b054ebf6ea57724a71cabf Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 7 Nov 2018 17:06:01 +0100 Subject: [PATCH 332/652] Fix PEP8 --- src/sardana/pool/test/helper.py | 1 + src/sardana/pool/test/test_measurementgroup.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index 7ba25d9afe..7b6e09b4a9 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -105,6 +105,7 @@ def createPoolZeroDExpChannel(pool, poolcontroller, conf): kwargs['ctrl'] = poolcontroller return Pool0DExpChannel(**kwargs) + def createPoolTwoDExpChannel(pool, poolcontroller, conf): '''Method to create a ZeroDExpChannel using a configuration dictionary ''' diff --git a/src/sardana/pool/test/test_measurementgroup.py b/src/sardana/pool/test/test_measurementgroup.py index 5dd179571e..a2ea0944fa 100644 --- a/src/sardana/pool/test/test_measurementgroup.py +++ b/src/sardana/pool/test/test_measurementgroup.py @@ -348,6 +348,7 @@ def tearDown(self): config_15 = [[('_test_2d_1_1', 'software', AcqSynchType.Trigger)]] + # TODO: listener is not ready to handle 2D # @insertTest(helper_name='meas_cont_acquisition', test_method_doc=doc_15, # config=config_15, synchronization=synchronization1) From a8814eee2fcb0a285227ee4695bffbbf09e07a7c Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 9 Nov 2018 11:24:09 +0100 Subject: [PATCH 333/652] Fix ParamDecoder to treat correctly raw params in XML format --- src/sardana/macroserver/msparameter.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sardana/macroserver/msparameter.py b/src/sardana/macroserver/msparameter.py index c4de3c6328..0019b6d614 100644 --- a/src/sardana/macroserver/msparameter.py +++ b/src/sardana/macroserver/msparameter.py @@ -471,8 +471,11 @@ def decodeRepeat(self, raw_param_repeat, param_repeat_def): (len_rep, name, max_rep) raise SupernumeraryRepeat(msg) # repeat params with only one member and only one repetition value are - # allowed - encapsulate it in list and try to decode anyway - if not is_non_str_seq(raw_param_repeat): + # allowed - encapsulate it in list and try to decode anyway; + # for the moment this only works for non XML decoding but could be + # extended in the future to support XML as well + if not is_non_str_seq(raw_param_repeat)\ + and not isinstance(raw_param_repeat, etree._Element): raw_param_repeat = [raw_param_repeat] for raw_repeat in raw_param_repeat: if len(param_type) > 1: From 11c70f09e7ce6fbd2a553676a03fe47cfb09cac5 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 9 Nov 2018 11:24:54 +0100 Subject: [PATCH 334/652] Add wait time for some macro tests --- src/sardana/macroserver/macros/test/test_standard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/macroserver/macros/test/test_standard.py b/src/sardana/macroserver/macros/test/test_standard.py index 9f5278978b..b7a51006c7 100644 --- a/src/sardana/macroserver/macros/test/test_standard.py +++ b/src/sardana/macroserver/macros/test/test_standard.py @@ -81,13 +81,13 @@ def test_move(self): self.macro_runs("umvr", macro_params=[MOT_NAME1, "-1"], wait_timeout=3) -@testRun(macro_params=[MOT_NAME1]) +@testRun(macro_params=[MOT_NAME1], wait_timeout=1) class MstateTest(RunMacroTestCase, unittest.TestCase): macro_name = "mstate" -@testRun(macro_params=["blabla"]) +@testRun(macro_params=["blabla"], wait_timeout=1) class ReportTest(RunMacroTestCase, unittest.TestCase): macro_name = "report" From dbada8fd28872f4a5de038e20edbddcd6a544ceb Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 9 Nov 2018 12:14:07 +0100 Subject: [PATCH 335/652] Rename NrOfStarts to NbStarts And internal variables from nr_of_starts to nb_starts --- doc/source/sep/SEP18.md | 2 +- src/sardana/macroserver/scan/gscan.py | 2 +- src/sardana/pool/controller.py | 4 +-- src/sardana/pool/poolacquisition.py | 12 ++++----- src/sardana/pool/poolmeasurementgroup.py | 26 +++++++++---------- src/sardana/tango/pool/MeasurementGroup.py | 18 ++++++------- src/sardana/taurus/core/tango/sardana/pool.py | 16 ++++++------ 7 files changed, 40 insertions(+), 40 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 1873430483..884a13d75d 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -101,7 +101,7 @@ integration time. When it is not used number of starts of 1 will be assumed. 1. Measurement group - Tango device class * Add `Prepare` command. - * Add `NrOfStarts` (`DevLong`) attribute. + * Add `NbStarts` (`DevLong`) attribute. 2. Measurement group - core class * Add `prepare()` method. * Add `nr_of_starts` property. diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index 17d7794918..72b06e3d1f 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -1011,7 +1011,7 @@ def scan_loop(self): if hasattr(macro, "integ_time"): integ_time = macro.integ_time self.measurement_group.putIntegrationTime(integ_time) - self.measurement_group.setNrOfStarts(nr_points) + self.measurement_group.setNbStarts(nr_points) self.measurement_group.prepare() scream = True else: diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index c1daa3609c..2ebcf9b9cb 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -661,7 +661,7 @@ class Loadable(object): .. note: Do not inherit directly from Loadable.""" - def PrepareOne(self, axis, value, repetitions, latency, nr_of_starts): + def PrepareOne(self, axis, value, repetitions, latency, nb_starts): """**Controller API**. Override if necessary. Called to load the number of repetitions. Default implementation does nothing. @@ -670,7 +670,7 @@ def PrepareOne(self, axis, value, repetitions, latency, nr_of_starts): :param int repetitions: number of repetitions :param float value: integration time / monitor count :param float latency: latency time - :param int nr_of_starts: number of starts + :param int nb_starts: number of starts """ pass diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 5e5b16e98b..83357c6064 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -277,7 +277,7 @@ def event_received(self, *args, **kwargs): def prepare(self, config, acq_mode, value, synchronization=None, moveable=None, sw_synch_initial_domain=None, - nr_of_starts=1, **kwargs): + nb_starts=1, **kwargs): """Prepare measurement.""" self._sw_acq_args = None self._sw_start_acq_args = None @@ -391,22 +391,22 @@ def prepare(self, config, acq_mode, value, synchronization=None, # Call hardware and software start controllers prepare method ctrls = ctrls_hw + ctrls_sw_start self._prepare_ctrls(ctrls, value, repetitions, latency, - nr_of_starts) + nb_starts) # Call software controllers prepare method - nr_of_starts = repetitions + nb_starts = repetitions repetitions = 1 self._prepare_ctrls(ctrls_sw, value, repetitions, latency, - nr_of_starts) + nb_starts) self._prepared = True @staticmethod - def _prepare_ctrls(ctrls, value, repetitions, latency, nr_of_starts): + def _prepare_ctrls(ctrls, value, repetitions, latency, nb_starts): for ctrl in ctrls: axis = ctrl.master.axis pool_ctrl = ctrl.element pool_ctrl.ctrl.PrepareOne(axis, value, repetitions, latency, - nr_of_starts) + nb_starts) def is_running(self): return self._0d_acq.is_running() or\ diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index ba0b8f9df7..08a60ac4d9 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -660,7 +660,7 @@ class PoolMeasurementGroup(PoolGroupElement): def __init__(self, **kwargs): self._state_lock = threading.Lock() self._monitor_count = None - self._nr_of_starts = 1 + self._nb_starts = 1 self._pending_starts = 0 self._acquisition_mode = AcqMode.Timer self._config = MeasurementConfiguration(self) @@ -905,17 +905,17 @@ def set_sw_synch_initial_domain(self, domain): # number of starts # ------------------------------------------------------------------------- - def get_nr_of_starts(self): - return self._nr_of_starts + def get_nb_starts(self): + return self._nb_starts - def set_nr_of_starts(self, nr_of_starts, propagate=1): - self._nr_of_starts = nr_of_starts + def set_nb_starts(self, nb_starts, propagate=1): + self._nb_starts = nb_starts if not propagate: return - self.fire_event(EventType("nr_of_starts", priority=propagate), - nr_of_starts) + self.fire_event(EventType("nb_starts", priority=propagate), + nb_starts) - nr_of_starts = property(get_nr_of_starts, set_nr_of_starts, + nb_starts = property(get_nb_starts, set_nb_starts, doc="current number of starts") # ------------------------------------------------------------------------- @@ -924,7 +924,7 @@ def set_nr_of_starts(self, nr_of_starts, propagate=1): def prepare(self, multiple=1): value = self._get_value() - self._pending_starts = self.nr_of_starts + self._pending_starts = self.nb_starts kwargs = {'head': self, 'multiple': multiple} @@ -935,7 +935,7 @@ def prepare(self, multiple=1): self._synchronization, self._moveable_obj, self.sw_synch_initial_domain, - self.nr_of_starts, + self.nb_starts, **kwargs) def start_acquisition(self, value=None, multiple=1): @@ -944,12 +944,12 @@ def start_acquisition(self, value=None, multiple=1): "deprecated since version Jan18." self.warning(msg) self.debug("Preparing with number_of_starts equal to 1") - nr_of_starts = self.nr_of_starts - self.set_nr_of_starts(1, propagate=0) + nb_starts = self.nb_starts + self.set_nb_starts(1, propagate=0) try: self.prepare(multiple) finally: - self.set_nr_of_starts(nr_of_starts, propagate=0) + self.set_nb_starts(nb_starts, propagate=0) self._aborted = False self._pending_starts -= 1 if not self._simulation_mode: diff --git a/src/sardana/tango/pool/MeasurementGroup.py b/src/sardana/tango/pool/MeasurementGroup.py index aebfa64a49..9ced987ac6 100644 --- a/src/sardana/tango/pool/MeasurementGroup.py +++ b/src/sardana/tango/pool/MeasurementGroup.py @@ -74,7 +74,7 @@ def init_device(self): PoolGroupDevice.init_device(self) # state and status are already set by the super class detect_evts = "latencytime", "moveable", "synchronization", \ - "softwaresynchronizerinitialdomain", "nrofstarts" + "softwaresynchronizerinitialdomain", "NbStarts" non_detect_evts = "configuration", "integrationtime", "monitorcount", \ "acquisitionmode", "elementlist" self.set_change_events(detect_evts, non_detect_evts) @@ -220,14 +220,14 @@ def write_Configuration(self, attr): cfg = CodecFactory().decode(('json', data), ensure_ascii=True) self.measurement_group.set_configuration_from_user(cfg) - def read_NrOfStarts(self, attr): - nr_of_starts = self.measurement_group.nr_of_starts - if nr_of_starts is None: - nr_of_starts = int('nan') - attr.set_value(nr_of_starts) + def read_NbStarts(self, attr): + nb_starts = self.measurement_group.nb_starts + if nb_starts is None: + nb_starts = int('nan') + attr.set_value(nb_starts) - def write_NrOfStarts(self, attr): - self.measurement_group.nr_of_starts = attr.get_write_value() + def write_NbStarts(self, attr): + self.measurement_group.nb_starts = attr.get_write_value() def read_Moveable(self, attr): moveable = self.measurement_group.moveable @@ -323,7 +323,7 @@ class MeasurementGroupClass(PoolGroupDeviceClass): 'Configuration': [[DevString, SCALAR, READ_WRITE], {'Memorized': "true", 'Display level': DispLevel.EXPERT}], - 'NrOfStarts': [[DevLong, SCALAR, READ_WRITE], + 'NbStarts': [[DevLong, SCALAR, READ_WRITE], {'Memorized': "true", 'Display level': DispLevel.OPERATOR}], 'Moveable': [[DevString, SCALAR, READ_WRITE], diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 5ce37c56ba..285e8bafe5 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1670,15 +1670,15 @@ def setSynchronization(self, synchronization): self.getSynchronizationObj().write(data) self._last_integ_time = None - # NrOfStarts Methods - def getNrOfStartsObj(self): - return self._getAttrEG('NrOfStarts') + # NbStarts Methods + def getNbStartsObj(self): + return self._getAttrEG('NbStarts') - def setNrOfStarts(self, starts): - self.getNrOfStartsObj().write(starts) + def setNbStarts(self, starts): + self.getNbStartsObj().write(starts) - def getNrOfStarts(self): - return self._getAttrValue('NrOfStarts') + def getNbStarts(self): + return self._getAttrValue('NbStarts') def getMoveableObj(self): return self._getAttrEG('Moveable') @@ -1817,7 +1817,7 @@ def go(self, *args, **kwargs): return self.getStateEG().readValue(), self.getValues() self.putIntegrationTime(integration_time) self.setMoveable(None) - self.setNrOfStarts(1) + self.setNbStarts(1) self.prepare() self.count_raw(self) state = self.getStateEG().readValue() From 3910e57fb78cc9e6ac72c9411785a90d72458461 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 9 Nov 2018 12:31:51 +0100 Subject: [PATCH 336/652] Fix flake8 --- src/sardana/pool/poolmeasurementgroup.py | 2 +- src/sardana/tango/pool/MeasurementGroup.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 08a60ac4d9..6c331a09ad 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -916,7 +916,7 @@ def set_nb_starts(self, nb_starts, propagate=1): nb_starts) nb_starts = property(get_nb_starts, set_nb_starts, - doc="current number of starts") + doc="current number of starts") # ------------------------------------------------------------------------- # acquisition diff --git a/src/sardana/tango/pool/MeasurementGroup.py b/src/sardana/tango/pool/MeasurementGroup.py index 9ced987ac6..5a6a1669ff 100644 --- a/src/sardana/tango/pool/MeasurementGroup.py +++ b/src/sardana/tango/pool/MeasurementGroup.py @@ -324,8 +324,8 @@ class MeasurementGroupClass(PoolGroupDeviceClass): {'Memorized': "true", 'Display level': DispLevel.EXPERT}], 'NbStarts': [[DevLong, SCALAR, READ_WRITE], - {'Memorized': "true", - 'Display level': DispLevel.OPERATOR}], + {'Memorized': "true", + 'Display level': DispLevel.OPERATOR}], 'Moveable': [[DevString, SCALAR, READ_WRITE], {'Memorized': "true", 'Display level': DispLevel.EXPERT}], From 472180dd3bd8a1e2c44f38d93dc23042dad5a7dd Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 9 Nov 2018 14:15:57 +0100 Subject: [PATCH 337/652] Update and add documentation (SEP, docstring) --- doc/source/sep/index.md | 3 ++- src/sardana/pool/controller.py | 9 +++++---- src/sardana/pool/poolacquisition.py | 11 ++++++++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/doc/source/sep/index.md b/doc/source/sep/index.md index d888843c95..e03e73f09c 100644 --- a/doc/source/sep/index.md +++ b/doc/source/sep/index.md @@ -26,7 +26,8 @@ Proposals list [SEP13][] | REJECTED (moved to [TEP13][]) | Unified plugins support in Taurus & Sardana [SEP14][] | DRAFT | MSENV taurus schema [SEP15][] | ACCEPTED | Moving Sardana to Github - [SEP18][] | DRAFT | Extend acquisition and synchronization concepts for SEP2 needs + [SEP18][] | CANDIDATE | Extend acquisition and synchronization + concepts for SEP2 needs diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index 2ebcf9b9cb..92caa7be91 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -663,7 +663,8 @@ class Loadable(object): def PrepareOne(self, axis, value, repetitions, latency, nb_starts): """**Controller API**. Override if necessary. - Called to load the number of repetitions. + Called to prepare the master channel axis with the measurement + parameters. Default implementation does nothing. :param int axis: axis number @@ -682,15 +683,15 @@ def PreLoadAll(self): def PreLoadOne(self, axis, value, repetitions, latency): """**Controller API**. Override if necessary. - Called to prepare loading the master channel axis with the integration - time / monitor value. + Called to prepare loading the master channel axis with the + acquisition parameters. Default implementation returns True. :param int axis: axis number :param float value: integration time /monitor value :param int repetitions: number of repetitions :param float latency: latency time - :return: True means a successfull PreLoadOne or False for a failure + :return: True means a successful PreLoadOne or False for a failure :rtype: bool""" return True diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 83357c6064..48757e0bab 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -80,6 +80,16 @@ def is_value_error(value): def get_acq_ctrls(ctrls, acq_mode=None): + """Converts configuration controllers objects into acquisition + controllers objects. It takes care about converting the internals as well. + + :param ctrls: sequence of configuration controllers objects + :type ctrls: sardana.pool.poolmeasurementgroup.ControllerConfiguration + :param acq_mode: acquisition mode (timer/monitor) + :type acq_mode: sardana.pool.AcqMode + :return: sequence of acquisition controllers + :rtype: sardana.pool.poolacquisition.AcqController + """ action_ctrls = [] for ctrl in ctrls: attrs = {} @@ -97,7 +107,6 @@ def get_acq_ctrls(ctrls, acq_mode=None): def get_synch_acq_items(ctrls): ctrls = get_acq_ctrls(ctrls) - # ctrls = config.get_synch_ctrls(enabled=True) return ctrls From bdbd5ac9bdbb1d6aeabc119d4b2a13e1693471c6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 9 Nov 2018 14:16:18 +0100 Subject: [PATCH 338/652] Remove unused MeasurementActions enumeration --- src/sardana/pool/poolacquisition.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 48757e0bab..1909bbce42 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -64,14 +64,6 @@ AS.Invalid: State.Invalid, } -MeasurementActions = Enumeration("MeasurementActions", ( - "AcquisitionHardware", - "AcquisitionSoftware", - "AcquisitionSoftwareStart", - "Acquisition0D", - "Synchronization") -) - def is_value_error(value): if isinstance(value, SardanaValue) and value.error: From 16caa645e77038ef84c87cb730fa07a01ec56d7a Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 9 Nov 2018 14:39:35 +0100 Subject: [PATCH 339/652] Fix formatting of get_acq_ctrls docstring --- src/sardana/pool/poolacquisition.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 1909bbce42..2e8ebef1c6 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -73,14 +73,15 @@ def is_value_error(value): def get_acq_ctrls(ctrls, acq_mode=None): """Converts configuration controllers objects into acquisition - controllers objects. It takes care about converting the internals as well. + controllers objects. It takes care about converting their internals as + well. :param ctrls: sequence of configuration controllers objects :type ctrls: sardana.pool.poolmeasurementgroup.ControllerConfiguration :param acq_mode: acquisition mode (timer/monitor) - :type acq_mode: sardana.pool.AcqMode + :type acq_mode: :class:`sardana.pool.AcqMode` :return: sequence of acquisition controllers - :rtype: sardana.pool.poolacquisition.AcqController + :rtype: :class:`~sardana.pool.poolacquisition.AcqController` """ action_ctrls = [] for ctrl in ctrls: From 79da2b3ca776a0cdc4d8cdec3bbcb9905ac942c5 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Mon, 12 Nov 2018 11:21:25 +0100 Subject: [PATCH 340/652] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a273424bd0..69f3b78b10 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ This file follows the formats and conventions from [keepachangelog.com] ### Added - Possibility to define macros with optional parameters. These must be the last ones in the definition (#285, #876, #943, #941, #955) +- Possibility to pass values of repeat paramters with just one member without + the need to encapsulate them in square brackets (spock syntax) or list + (macro API) (#781) - Workaround for API_DeviceTimedOut errors on MeasurementGroup Start. Call Stop in case this error occured (#764). - Optional measurement group parameter to `ct` and `uct` macros (#940, #473) @@ -29,10 +32,15 @@ This file follows the formats and conventions from [keepachangelog.com] (#945) - Make cleanup (remove configuration) if spock profile creation was interrupted or failed (#791, #793) +- Spock considers passing supernumerary parameters as errors (#438, #781) +- MacroServer starts without the Qt library installed (#781, #907, #908) ### Changed +- Spock syntax and advanced spock syntax are considered as one in documentaion + (#781) - Move pre-scan and post-scan hooks out of `scan_loop` method (#920, #922, #933) +- Move `ParamParser` to `sardana.util.parser` (#781, #907, #908) ## [2.5.0] 2018-08-10 From cf58568a9d2e0915c1963c04b7809f694e59ec57 Mon Sep 17 00:00:00 2001 From: Roberto Javier Homs Puron Date: Mon, 12 Nov 2018 14:26:32 +0100 Subject: [PATCH 341/652] Fix bug on controller description reading The `Description` is an optional parameter. --- src/sardana/pool/poolmetacontroller.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolmetacontroller.py b/src/sardana/pool/poolmetacontroller.py index a6e7661643..242c737306 100644 --- a/src/sardana/pool/poolmetacontroller.py +++ b/src/sardana/pool/poolmetacontroller.py @@ -274,17 +274,17 @@ def __init__(self, **kwargs): + "sardana.pool.controller.Description constant instead.") for k, v in klass.class_prop.items(): # old member props[k] = DataInfo.toDataInfo(k, v) - try: + if Description in v: self.ctrl_properties_descriptions.append(v[Description]) - except KeyError: + elif 'Description' in v: self.warning(dep_msg) self.ctrl_properties_descriptions.append(v['Description']) for k, v in klass.ctrl_properties.items(): props[k] = DataInfo.toDataInfo(k, v) - try: + if Description in v: self.ctrl_properties_descriptions.append(v[Description]) - except KeyError: + elif 'Description' in v: self.warning(dep_msg) self.ctrl_properties_descriptions.append(v['Description']) From eeeb23df0f746917d0287470078e9cc3ada34fd9 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Mon, 12 Nov 2018 14:57:00 +0100 Subject: [PATCH 342/652] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69f3b78b10..bd912651ce 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ This file follows the formats and conventions from [keepachangelog.com] or failed (#791, #793) - Spock considers passing supernumerary parameters as errors (#438, #781) - MacroServer starts without the Qt library installed (#781, #907, #908) +- Make `Description` an optional part of controller's properties definition (#976) ### Changed - Spock syntax and advanced spock syntax are considered as one in documentaion From 5db4659776ab2516bef1c9f703c766f7b6e3339c Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 13 Nov 2018 11:30:53 +0100 Subject: [PATCH 343/652] Inform that abort is not implemented and stop is called --- .../taurus/qt/qtgui/extra_macroexecutor/macrobutton.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py index c3942c08bb..682d0ccdd4 100755 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py @@ -294,7 +294,7 @@ def runMacro(self): # For backward compatibility def abort(self): - self.warning("abort method is deprecated. Use stop instead") + self.warning("abort is not implemented, stop is being called instead") self.stop() def stop(self): @@ -309,7 +309,7 @@ def stop(self): title = 'Stopping macro' message = 'The following macro is still running:\n\n' message += '%s %s\n\n' % (self.macro_name, ' '.join(self.macro_args)) - message += 'Are you sure you want to Stop?\n' + message += 'Are you sure you want to stop?\n' buttons = Qt.QMessageBox.Ok | Qt.QMessageBox.Cancel ans = Qt.QMessageBox.warning( self, title, message, buttons, Qt.QMessageBox.Ok) From b77460a2f782fd3f6d670c3014da2db03334e4a4 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 13 Nov 2018 11:42:55 +0100 Subject: [PATCH 344/652] Fix typo in docs --- doc/source/devel/howto_macros/macros_general.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index b179dea6c8..23041beec6 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -45,7 +45,7 @@ a macro class you can benefit from all advantages of object-oriented programming. This means that, in theory: - it would reduce the amount of code you need to write - - reduce the complexity of your code y by dividing it into small, + - reduce the complexity of your code by dividing it into small, reasonably independent and re-usable components, that talk to each other using only well-defined interfaces - Improvement of productivity by using easily adaptable pre-defined From 651aaa7222eac56eb84a855152d16f7698678f1f Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 13 Nov 2018 12:12:34 +0100 Subject: [PATCH 345/652] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd912651ce..740fc73a79 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ This file follows the formats and conventions from [keepachangelog.com] - Make `Description` an optional part of controller's properties definition (#976) ### Changed +- MacroButton stops macros instead of aborting them (#931, #943) - Spock syntax and advanced spock syntax are considered as one in documentaion (#781) - Move pre-scan and post-scan hooks out of `scan_loop` method (#920, #922, From 6ce04ba4acc21a8f8b511557f45b0a82143498b6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 13 Nov 2018 17:57:27 +0100 Subject: [PATCH 346/652] Document poolacquisition --- src/sardana/pool/poolacquisition.py | 69 +++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 2e8ebef1c6..89d6dead3f 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -23,7 +23,7 @@ ## ############################################################################## -"""This module is part of the Python Pool libray. It defines the class for an +"""This module is part of the Python Pool library. It defines the class for an acquisition""" __all__ = ["get_acq_ctrls", "AcquisitionState", "AcquisitionMap", @@ -72,9 +72,9 @@ def is_value_error(value): def get_acq_ctrls(ctrls, acq_mode=None): - """Converts configuration controllers objects into acquisition - controllers objects. It takes care about converting their internals as - well. + """Converts configuration controllers into acquisition controllers. + + It takes care about converting their internals as well. :param ctrls: sequence of configuration controllers objects :type ctrls: sardana.pool.poolmeasurementgroup.ControllerConfiguration @@ -145,8 +145,19 @@ def __init__(self, args, kwargs=None): class AcqConfigurationItem(object): + """Wrapper for configuration item that will be used in an action.""" def __init__(self, configuration, attrs=None): + """Constructs action item from a configuration item. + + Eventually it can be enriched with attrs. + + :param configuration: item configuration object + :type configuration: + :class:`sardana.pool.poolmeasurementgroup.ConfigurationItem` + :param attrs: extra attributes to be inserted + :type attrs: dict + """ self._configuration = weakref.ref(configuration) self.enabled = True @@ -168,8 +179,19 @@ def set_configuration(self, configuration): class AcqController(AcqConfigurationItem): + """Wrapper for controller configuration that will be used in an action.""" def __init__(self, configuration, attrs=None): + """Constructs action controller from a configuration controller. + + Eventually it can be enriched with attrs. + + :param configuration: controller configuration object + :type configuration: + :class:`sardana.pool.poolmeasurementgroup.ControllerConfiguration` + :param attrs: extra attributes to be inserted + :type attrs: dict + """ if attrs is not None: master = attrs.get('master') self._channels = [] @@ -200,6 +222,15 @@ def get_channels(self, enabled=None): class PoolAcquisition(PoolAction): + """Acquisition action which is internally composed for sub-actions. + + Handle acquisition of experimental channels of the following types: + * timerable (C/T, 1D and 2D) synchronized by software or hardware + trigger/gate/start + * 0D + + Synchronized by T/G elements or sofware synchronizer. + """ def __init__(self, main_element, name="Acquisition"): PoolAction.__init__(self, main_element, name) @@ -223,6 +254,10 @@ def __init__(self, main_element, name="Acquisition"): self._synch = PoolSynchronization(main_element, name=synchname) def event_received(self, *args, **kwargs): + """Callback executed on event of software synchronizer. + + Reacts on start, active, passive or end type of events + """ timestamp = time.time() _, type_, index = args name = type_.name @@ -280,7 +315,11 @@ def event_received(self, *args, **kwargs): def prepare(self, config, acq_mode, value, synchronization=None, moveable=None, sw_synch_initial_domain=None, nb_starts=1, **kwargs): - """Prepare measurement.""" + """Prepare measurement process. + + Organize sub-action arguments and loads configuration parameters to + the hardware controllers. + """ self._sw_acq_args = None self._sw_start_acq_args = None self._0d_acq_args = None @@ -411,12 +450,18 @@ def _prepare_ctrls(ctrls, value, repetitions, latency, nb_starts): nb_starts) def is_running(self): - return self._0d_acq.is_running() or\ - self._sw_acq.is_running() or\ - self._hw_acq.is_running() or\ - self._synch.is_running() + """Checks if acquisition is running. + + Acquisition is runnin if any of its sub-actions is running. + """ + return self._sw_start_acq.is_running()\ + or self._0d_acq.is_running()\ + or self._sw_acq.is_running()\ + or self._hw_acq.is_running()\ + or self._synch.is_running() def run(self, *args, **kwargs): + """Runs acquisition according to previous preparation.""" if not self._prepared: raise RuntimeError('You must call first "prepare" method.') @@ -761,6 +806,9 @@ class PoolAcquisitionHardware(PoolAcquisitionBase): on a provisional basis. Backwards incompatible changes (up to and including removal of the module) may occur if deemed necessary by the core developers. + + .. todo:: Try to move the action loop logic to base class it is + basically the same as in PoolAcquisitionSoftwareStart. """ def __init__(self, main_element, name="AcquisitionHardware"): @@ -913,6 +961,9 @@ class PoolAcquisitionSoftwareStart(PoolAcquisitionBase): on a provisional basis. Backwards incompatible changes (up to and including removal of the module) may occur if deemed necessary by the core developers. + + .. todo:: Try to move the action loop logic to base class it is + basically the same as in PoolAcquisitionHardware. """ def __init__(self, main_element, name="AcquisitionSoftwareStart"): From 60c74ecb15dc36d75bae82c75398853fa9badc74 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 13 Nov 2018 18:40:10 +0100 Subject: [PATCH 347/652] Document AcqSynchType and AcqSynch Be more explicit what software and hardware means. --- .../devel/api/sardana/pool/pooldefs.rst | 15 +++++++- src/sardana/pool/pooldefs.py | 37 ++++++++++++++----- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/doc/source/devel/api/sardana/pool/pooldefs.rst b/doc/source/devel/api/sardana/pool/pooldefs.rst index 93f3a85a5d..97bd25699c 100644 --- a/doc/source/devel/api/sardana/pool/pooldefs.rst +++ b/doc/source/devel/api/sardana/pool/pooldefs.rst @@ -15,11 +15,12 @@ :columns: 3 * :class:`~AcqSynch` + * :class:`~AcqSynchType` * :class:`~SynchParam` * :class:`~SynchDomain` AcqSynch ----------- +-------- .. inheritance-diagram:: AcqSynch :parts: 1 @@ -30,6 +31,18 @@ AcqSynch :undoc-members: +AcqSynchType +------------ + +.. inheritance-diagram:: AcqSynchType + :parts: 1 + +.. autoclass:: AcqSynchType + :show-inheritance: + :members: + :undoc-members: + + SynchParam ---------- diff --git a/src/sardana/pool/pooldefs.py b/src/sardana/pool/pooldefs.py index e8bbe4ebae..eba5b39b4a 100644 --- a/src/sardana/pool/pooldefs.py +++ b/src/sardana/pool/pooldefs.py @@ -110,26 +110,45 @@ class SynchParam(SynchEnum): Repeats = 3 Initial = 4 -# TODO: convert to to python enums, but having in ming problems with -# JSON serialization: https://bugs.python.org/issue18264 -# class AcqSynchType(Enumeration): -# -# Trigger = 0 -# Gate = 1 +class AcqSynchType(Enumeration): + """Enumeration of synchronization types. -AcqSynchType = Enumeration("AcqSynchType", ["Trigger", "Gate", "Start"]) + .. todo:: convert to python enums, but having in mind problems with + JSON serialization: https://bugs.python.org/issue18264 + """ + #: Start each acquisition (experimental channel will decide on + #: itself when to end - based on integration time / monitor count) + Trigger = 0 + #: Start and end each acquisition + Gate = 1 + #: Start only the first acquisition (experimental channel will drive + #: the acquisition based on integration time / monitor count, latency + #: time and number of repetitions) + Start = 2 -# TODO: convert to to python enums, but having in ming problems with -# JSON serialization: https://bugs.python.org/issue18264 class AcqSynch(Enumeration): + """Enumeration of synchronization options. + + Uses software/hardware naming to refer to internal (software + synchronizer) or external (hardware synchronization device) + synchronization modes + .. todo:: convert to python enums, but having in mind problems with + JSON serialization: https://bugs.python.org/issue18264 + """ + #: Internal (software) trigger SoftwareTrigger = 0 + #: External (hardware) trigger HardwareTrigger = 1 + #: Internal (software) gate SoftwareGate = 2 + #: External (hardware) gate HardwareGate = 3 + #: Internal (software) start (triggers just the first acquisition) SoftwareStart = 4 + #: External (hardware) start (triggers just the first acquisition) HardwareStart = 5 @classmethod From 00a31ab3227113242d6f278b0c399685ce481bea Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 14 Nov 2018 18:21:17 +0100 Subject: [PATCH 348/652] Add license header to tests of macro and scanct --- .../macroserver/macros/test/test_macro.py | 25 +++++++++++++++++++ .../macroserver/macros/test/test_scanct.py | 24 ++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/sardana/macroserver/macros/test/test_macro.py b/src/sardana/macroserver/macros/test/test_macro.py index 861d37c6dc..cca43cd648 100644 --- a/src/sardana/macroserver/macros/test/test_macro.py +++ b/src/sardana/macroserver/macros/test/test_macro.py @@ -1,3 +1,28 @@ +#!/usr/bin/env python + +############################################################################## +## +# This file is part of Sardana +## +# http://www.sardana-controls.org/ +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Sardana 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. +## +# Sardana 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 Sardana. If not, see . +## +############################################################################## + import os from taurus.external import unittest diff --git a/src/sardana/macroserver/macros/test/test_scanct.py b/src/sardana/macroserver/macros/test/test_scanct.py index dc2a551bbc..3cf83777bb 100644 --- a/src/sardana/macroserver/macros/test/test_scanct.py +++ b/src/sardana/macroserver/macros/test/test_scanct.py @@ -1,4 +1,28 @@ #!/usr/bin/env python + +############################################################################## +## +# This file is part of Sardana +## +# http://www.sardana-controls.org/ +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Sardana 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. +## +# Sardana 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 Sardana. If not, see . +## +############################################################################## + """Tests for continuous scans (ct-like)""" import time import PyTango From dbef114bdbd9c9c57ff661fe28eb2210154b6e2f Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 14 Nov 2018 18:21:34 +0100 Subject: [PATCH 349/652] Add tests for general hooks --- .../macroserver/macros/test/test_gh.py | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/sardana/macroserver/macros/test/test_gh.py diff --git a/src/sardana/macroserver/macros/test/test_gh.py b/src/sardana/macroserver/macros/test/test_gh.py new file mode 100644 index 0000000000..ff824c9ec4 --- /dev/null +++ b/src/sardana/macroserver/macros/test/test_gh.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +############################################################################## +## +# This file is part of Sardana +## +# http://www.sardana-controls.org/ +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Sardana 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. +## +# Sardana 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 Sardana. If not, see . +## +############################################################################## + +from taurus.external import unittest + +from sardana.macroserver.macros.test import RunMacroTestCase, testRun +from sardana.tango.macroserver.test import BaseMacroServerTestCase + + +@testRun(macro_name="lsgh", wait_timeout=1) +@testRun(macro_name="defgh", macro_params=["lsm", "pre-acq"], wait_timeout=1) +@testRun(macro_name="udefgh", wait_timeout=1) +class GeneralHooksTest(BaseMacroServerTestCase, RunMacroTestCase, + unittest.TestCase): + + def setUp(self): + unittest.TestCase.setUp(self) + BaseMacroServerTestCase.setUp(self) + RunMacroTestCase.setUp(self) + + def test_gh(self): + self.macro_runs(macro_name="defgh", macro_params=["lsm", "pre-acq"], + wait_timeout=1) + self.macro_runs(macro_name="ct", macro_params=[".1"], wait_timeout=1) + self.macro_runs(macro_name="udefgh", macro_params=["lsm", "pre-acq"], + wait_timeout=1) + + def tearDown(self): + BaseMacroServerTestCase.tearDown(self) + RunMacroTestCase.tearDown(self) + unittest.TestCase.tearDown(self) From 176db7d995dbf69591b22ff2a7e28d9278b3216c Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 14 Nov 2018 18:23:30 +0100 Subject: [PATCH 350/652] Fix general hooks - param parser usage ParamParser was enriched and now knows a parameters definition (#781). Adapt general hooks preparation to the new API. --- src/sardana/macroserver/msmacromanager.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sardana/macroserver/msmacromanager.py b/src/sardana/macroserver/msmacromanager.py index fbae7c25b6..c84668998e 100644 --- a/src/sardana/macroserver/msmacromanager.py +++ b/src/sardana/macroserver/msmacromanager.py @@ -1198,7 +1198,16 @@ def _prepareGeneralHooks(self, macro_obj): if len(general_hooks) == 0: return for hook_info_raw, hook_places in general_hooks: - hook_info = ParamParser().parse(hook_info_raw) + hook_info_tokens = hook_info_raw.split(" ", 1) + hook_name = hook_info_tokens[0] + hook_info = [hook_name] + if len(hook_info_tokens) == 2: + hook_params_raw = hook_info_tokens[1] + hook_param_def = self.macro_manager.getMacro( + hook_name).get_parameter() + param_parser = ParamParser(hook_param_def) + hook_params = param_parser.parse(hook_params_raw) + hook_info += hook_params hook = ExecMacroHook(macro_obj, hook_info) macro_obj.appendHook((hook, hook_places)) From e4a7eb4d35fa712281418ec8268a66cae87f4dcc Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 15 Nov 2018 13:50:36 +0100 Subject: [PATCH 351/652] Add new test for defgh --- src/sardana/macroserver/macros/test/test_gh.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sardana/macroserver/macros/test/test_gh.py b/src/sardana/macroserver/macros/test/test_gh.py index ff824c9ec4..2c15a873c1 100644 --- a/src/sardana/macroserver/macros/test/test_gh.py +++ b/src/sardana/macroserver/macros/test/test_gh.py @@ -31,6 +31,8 @@ @testRun(macro_name="lsgh", wait_timeout=1) @testRun(macro_name="defgh", macro_params=["lsm", "pre-acq"], wait_timeout=1) +@testRun(macro_name="defgh", macro_params=["lsm mot.*", "pre-acq"], + wait_timeout=1) @testRun(macro_name="udefgh", wait_timeout=1) class GeneralHooksTest(BaseMacroServerTestCase, RunMacroTestCase, unittest.TestCase): From 6fd2d502c9b0424e9019c28c5530f88ee59b7d10 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 15 Nov 2018 13:52:06 +0100 Subject: [PATCH 352/652] Fix flake8 --- src/sardana/macroserver/macros/test/test_gh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/macroserver/macros/test/test_gh.py b/src/sardana/macroserver/macros/test/test_gh.py index 2c15a873c1..8b7be8d720 100644 --- a/src/sardana/macroserver/macros/test/test_gh.py +++ b/src/sardana/macroserver/macros/test/test_gh.py @@ -35,7 +35,7 @@ wait_timeout=1) @testRun(macro_name="udefgh", wait_timeout=1) class GeneralHooksTest(BaseMacroServerTestCase, RunMacroTestCase, - unittest.TestCase): + unittest.TestCase): def setUp(self): unittest.TestCase.setUp(self) From cd4320f72f5032d141258365c60a48b0d0ad2b30 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 15 Nov 2018 15:38:58 +0100 Subject: [PATCH 353/652] Change macro button text from Abort to Start --- src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py index 682d0ccdd4..06717297a2 100755 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py @@ -214,7 +214,7 @@ def setButtonText(self, text): '''same as :meth:`setText` ''' # SHOULD ALSO BE POSSIBLE TO SET AN ICON - self.ui.button.setText("Run/Abort:\n" + text) + self.ui.button.setText("Run/Stop:\n" + text) def setMacroName(self, name): '''set the name of the macro to be executed From abc4bd6212de7c0405bb5158f12b8cb6e2ae142d Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 15 Nov 2018 15:40:05 +0100 Subject: [PATCH 354/652] Fix typo in macro development howto --- doc/source/devel/howto_macros/macros_general.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index b179dea6c8..23041beec6 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -45,7 +45,7 @@ a macro class you can benefit from all advantages of object-oriented programming. This means that, in theory: - it would reduce the amount of code you need to write - - reduce the complexity of your code y by dividing it into small, + - reduce the complexity of your code by dividing it into small, reasonably independent and re-usable components, that talk to each other using only well-defined interfaces - Improvement of productivity by using easily adaptable pre-defined From 462b53583e5a871542b9f2542a61ff36400055db Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 15 Nov 2018 17:19:18 +0100 Subject: [PATCH 355/652] Increase wait_timeout for ct to 3 seconds ct with lsm general hooks may take more time to execute than 1 second. Increase wait_timeout to 3. --- src/sardana/macroserver/macros/test/test_gh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/macroserver/macros/test/test_gh.py b/src/sardana/macroserver/macros/test/test_gh.py index 8b7be8d720..96134a311c 100644 --- a/src/sardana/macroserver/macros/test/test_gh.py +++ b/src/sardana/macroserver/macros/test/test_gh.py @@ -45,7 +45,7 @@ def setUp(self): def test_gh(self): self.macro_runs(macro_name="defgh", macro_params=["lsm", "pre-acq"], wait_timeout=1) - self.macro_runs(macro_name="ct", macro_params=[".1"], wait_timeout=1) + self.macro_runs(macro_name="ct", macro_params=[".1"], wait_timeout=3) self.macro_runs(macro_name="udefgh", macro_params=["lsm", "pre-acq"], wait_timeout=1) From 8a55c6e5b7a9229a2ea2b88ab74076b72fcf265b Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 15 Nov 2018 19:54:30 +0100 Subject: [PATCH 356/652] Fix test_gh to use a measurement group to count --- .../macroserver/macros/test/test_gh.py | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/sardana/macroserver/macros/test/test_gh.py b/src/sardana/macroserver/macros/test/test_gh.py index 96134a311c..63e4493963 100644 --- a/src/sardana/macroserver/macros/test/test_gh.py +++ b/src/sardana/macroserver/macros/test/test_gh.py @@ -27,6 +27,8 @@ from sardana.macroserver.macros.test import RunMacroTestCase, testRun from sardana.tango.macroserver.test import BaseMacroServerTestCase +from sardana.tango.pool.test.test_measurementgroup import MeasSarTestTestCase +from sardana.macroserver.macros.test.test_scanct import mg_config4 @testRun(macro_name="lsgh", wait_timeout=1) @@ -34,22 +36,32 @@ @testRun(macro_name="defgh", macro_params=["lsm mot.*", "pre-acq"], wait_timeout=1) @testRun(macro_name="udefgh", wait_timeout=1) -class GeneralHooksTest(BaseMacroServerTestCase, RunMacroTestCase, - unittest.TestCase): +class GeneralHooksTest(MeasSarTestTestCase, BaseMacroServerTestCase, + RunMacroTestCase, unittest.TestCase): def setUp(self): - unittest.TestCase.setUp(self) + MeasSarTestTestCase.setUp(self) BaseMacroServerTestCase.setUp(self) RunMacroTestCase.setUp(self) + unittest.TestCase.setUp(self) + + def create_meas(self, config): + MeasSarTestTestCase.create_meas(self, config) + self.macro_executor.run(macro_name='senv', + macro_params=['ActiveMntGrp', '_test_mg_1'], + sync=True, timeout=1.) def test_gh(self): self.macro_runs(macro_name="defgh", macro_params=["lsm", "pre-acq"], wait_timeout=1) - self.macro_runs(macro_name="ct", macro_params=[".1"], wait_timeout=3) + self.create_meas(mg_config4) + self.macro_runs(macro_name="ct", macro_params=[".1"], wait_timeout=1) self.macro_runs(macro_name="udefgh", macro_params=["lsm", "pre-acq"], wait_timeout=1) def tearDown(self): - BaseMacroServerTestCase.tearDown(self) - RunMacroTestCase.tearDown(self) unittest.TestCase.tearDown(self) + RunMacroTestCase.tearDown(self) + BaseMacroServerTestCase.tearDown(self) + MeasSarTestTestCase.tearDown(self) + From f685ec7719d5bfae1e436a91e1a5247f717e2bac Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 15 Nov 2018 19:54:56 +0100 Subject: [PATCH 357/652] Cleanup macroserver.properties in base MS test class --- src/sardana/tango/macroserver/test/base.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/sardana/tango/macroserver/test/base.py b/src/sardana/tango/macroserver/test/base.py index 621582964a..12efbaa72d 100755 --- a/src/sardana/tango/macroserver/test/base.py +++ b/src/sardana/tango/macroserver/test/base.py @@ -27,11 +27,15 @@ __all__ = ['BaseMacroServerTestCase'] +import os + import PyTango +from taurus.core.util import whichexecutable from taurus.core.tango.starter import ProcessStarter + from sardana import sardanacustomsettings from sardana.tango.core.util import (get_free_server, get_free_device) -from taurus.core.util import whichexecutable +from sardana.tango.macroserver.MacroServer import MacroServerClass class BaseMacroServerTestCase(object): @@ -56,9 +60,9 @@ def setUp(self, properties=None): # Discover the MS launcher script msExec = whichexecutable.whichfile("MacroServer") # register MS server - ms_ds_name = "MacroServer/" + self.ms_ds_name - ms_free_ds_name = get_free_server(db, ms_ds_name) - self._msstarter = ProcessStarter(msExec, ms_free_ds_name) + ms_ds_name_base = "MacroServer/" + self.ms_ds_name + self.ms_ds_name = get_free_server(db, ms_ds_name_base) + self._msstarter = ProcessStarter(msExec, self.ms_ds_name) # register MS device dev_name_parts = self.ms_name.split('/') prefix = '/'.join(dev_name_parts[0:2]) @@ -88,11 +92,18 @@ def setUp(self, properties=None): def tearDown(self): """Remove the Pool instance. """ + dft_ms_properties = os.path.join(MacroServerClass.DefaultEnvBaseDir, + MacroServerClass.DefaultEnvRelDir) + ds_inst_name = self.ms_ds_name.split("/")[1] + ms_properties = dft_ms_properties % {"ds_exec_name": "MacroServer", + "ds_inst_name": ds_inst_name} + os.remove(ms_properties) self._msstarter.cleanDb(force=True) self._msstarter = None self.macroserver = None self.door = None + if __name__ == '__main__': bms = BaseMacroServerTestCase() bms.setUp() From 9900cfe3f2ea6cca94cf1b8b47043d08b9af3fd9 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 15 Nov 2018 20:15:37 +0100 Subject: [PATCH 358/652] Fix flake8 --- src/sardana/macroserver/macros/test/test_gh.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sardana/macroserver/macros/test/test_gh.py b/src/sardana/macroserver/macros/test/test_gh.py index 63e4493963..31bd9c8a68 100644 --- a/src/sardana/macroserver/macros/test/test_gh.py +++ b/src/sardana/macroserver/macros/test/test_gh.py @@ -64,4 +64,3 @@ def tearDown(self): RunMacroTestCase.tearDown(self) BaseMacroServerTestCase.tearDown(self) MeasSarTestTestCase.tearDown(self) - From 1ec90a4c943178ed19488e73c3763cf9e2770c9e Mon Sep 17 00:00:00 2001 From: reszelaz Date: Fri, 16 Nov 2018 09:41:12 +0100 Subject: [PATCH 359/652] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 740fc73a79..2fd5a75d2e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ This file follows the formats and conventions from [keepachangelog.com] ones in the definition (#285, #876, #943, #941, #955) - Possibility to pass values of repeat paramters with just one member without the need to encapsulate them in square brackets (spock syntax) or list - (macro API) (#781) + (macro API) (#781, #983) - Workaround for API_DeviceTimedOut errors on MeasurementGroup Start. Call Stop in case this error occured (#764). - Optional measurement group parameter to `ct` and `uct` macros (#940, #473) From a6917e0232af372e32a44f911d4b2e8dd366665f Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 19 Nov 2018 10:50:42 +0100 Subject: [PATCH 360/652] Document that pseudo counters can be based on any exp. channel --- .../devel/overview/overview_pseudocounter.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/source/devel/overview/overview_pseudocounter.rst b/doc/source/devel/overview/overview_pseudocounter.rst index a9ac88663f..a036e5966b 100644 --- a/doc/source/devel/overview/overview_pseudocounter.rst +++ b/doc/source/devel/overview/overview_pseudocounter.rst @@ -6,24 +6,26 @@ Pseudo counter overview ======================= -Pseudo counter acts like an abstraction layer for a counter or a set of -counters allowing the user to see the experiment results by means of an -interface which is more meaningful to him. +Pseudo counter acts like an abstraction layer for an experimental channel +(counter/timer, 0D, 1D or 2D) or a set of them allowing the user to see the +experiment results by means of an interface which is more meaningful to him. +Pseudo counters can be even build on top of another pseudo counters. One example of a pseudo counter is :class:`~sardana.pool.poolcontrollers.IoverI0` useful for normalizing the measurement results in order to make them comparable. -In order to translate the counter values into the pseudo counter values, -calculations have to be performed. The device pool provides +In order to translate the experimental channel values into the pseudo counter +values, calculations have to be performed. The device pool provides :class:`~sardana.pool.controller.PseudoCounterController` class that can be overwritten to provide new calculations. The pseudo counter value gets updated automatically every time one of its -counters value gets updated e.g. when the acquisition is in progress. +experimental channel values gets updated e.g. when the acquisition is in +progress. -Each pseudo counter is represented by a Tango_ device whose interface allows to -obtain a calculation result (scalar value). +Each pseudo counter is represented by a Tango_ device whose interface allows +to obtain a calculation result (scalar value). .. seealso:: From 2ce5041edb422e68702e71365bfff8a17ee4784c Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 19 Nov 2018 16:12:06 +0100 Subject: [PATCH 361/652] Document RConsolePort --- .../users/configuration/macroserver.rst | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/doc/source/users/configuration/macroserver.rst b/doc/source/users/configuration/macroserver.rst index 3ce5a6142b..fc988d835c 100644 --- a/doc/source/users/configuration/macroserver.rst +++ b/doc/source/users/configuration/macroserver.rst @@ -50,5 +50,22 @@ instance. In case Sardana is used with Tango this configuration is accessible via the ``LogstashHost`` and ``LogstashPort`` :class:`~sardana.tango.macroserver.MacroServer.MacroServer` device properties. -.. todo:: - Document RConsolePort +You can debug the MacroServer at runtime using the Python remote +console - ``rconsole`` (part of the `rfoo `_ +project). First, you need to specify at which port the MacroServer will +accept connections. For that, simply set the ``RConsolePort`` +:class:`~sardana.tango.macroserver.MacroServer.MacroServer` property. +Second, in order to open a connection to a MacroServer just type:: + + $> rconsole -p + +The most convenient way to debug the MacroServer internals is to use the +`Tango Util `_ singleton object. It is used to store Tango device server +process data and to provide the user with a set of utilities method. +For example, to access the MacroServer Sardana core object, in the a rconsole +session, just type:: + + >>> import tango + >>> util = tango.Util.instance() + >>> ms = util.get_device_by_name("").macro_server From f6b33d4514c0c933f58d9e5be927831f798296b5 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Tue, 20 Nov 2018 13:22:40 +0100 Subject: [PATCH 362/652] fix typos --- doc/source/users/configuration/macroserver.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/users/configuration/macroserver.rst b/doc/source/users/configuration/macroserver.rst index fc988d835c..6bad6b21e2 100644 --- a/doc/source/users/configuration/macroserver.rst +++ b/doc/source/users/configuration/macroserver.rst @@ -62,8 +62,8 @@ Second, in order to open a connection to a MacroServer just type:: The most convenient way to debug the MacroServer internals is to use the `Tango Util `_ singleton object. It is used to store Tango device server -process data and to provide the user with a set of utilities method. -For example, to access the MacroServer Sardana core object, in the a rconsole +process data and to provide the user with a set of utility methods. +For example, to access the MacroServer Sardana core object, in the rconsole session, just type:: >>> import tango From 809686028af49d127a8dc55d60234be8dda739f2 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 20 Nov 2018 13:53:42 +0100 Subject: [PATCH 363/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd5a75d2e..e5e974882b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ This file follows the formats and conventions from [keepachangelog.com] - Support to "PETRA3 P23 6C" and "PETRA3 P23 4C" diffractometers by means of new controller classes and necessary adaptation to macros (#923, #921) - Top LICENSE file that applies to the whole project (#938) +- Document remote connection to MacroServer Python process (RConsolePort Tango + property) (#984) ### Fixed - Make `expconf` react on events of environment, measurement groups and their From b7fa6e6605c55ec9f212c391d7c63e5ffe730339 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 23 Nov 2018 11:03:29 +0100 Subject: [PATCH 364/652] Refactor PoolElementDevice.get_dynamic_attributes Refactor get_dynamic_attributes to separate the attributes info generation from the caching mechanism. So it is easier to specialize this class with optional caching. --- src/sardana/tango/pool/PoolDevice.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sardana/tango/pool/PoolDevice.py b/src/sardana/tango/pool/PoolDevice.py index 5a0d315f22..436d43d95a 100644 --- a/src/sardana/tango/pool/PoolDevice.py +++ b/src/sardana/tango/pool/PoolDevice.py @@ -647,7 +647,14 @@ def get_dynamic_attributes(self): """ if hasattr(self, "_dynamic_attributes_cache"): - return self._standard_attributes_cache, self._dynamic_attributes_cache + return self._standard_attributes_cache, \ + self._dynamic_attributes_cache + std_attrs, dyn_attrs = self._get_dynamic_attributes() + self._standard_attributes_cache = std_attrs + self._dynamic_attributes_cache = dyn_attrs + return std_attrs, dyn_attrs + + def _get_dynamic_attributes(self): ctrl = self.ctrl if ctrl is None: self.warning("no controller: dynamic attributes NOT created") @@ -656,8 +663,8 @@ def get_dynamic_attributes(self): self.warning("controller offline: dynamic attributes NOT created") return PoolDevice.get_dynamic_attributes(self) - self._dynamic_attributes_cache = dyn_attrs = CaselessDict() - self._standard_attributes_cache = std_attrs = CaselessDict() + dyn_attrs = CaselessDict() + std_attrs = CaselessDict() dev_class = self.get_device_class() axis_attrs = ctrl.get_axis_attributes(self.element.axis) From 0a2ca1941b9eaeecc0faa049405a43a524bfdd04 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 23 Nov 2018 15:14:59 +0100 Subject: [PATCH 365/652] Allow changes of data format (0D, 1D or 2D) of pseudo counters Respect what pseudo counter controller says about Value's Type and MaxDimSize in GetAxisAttributes. --- src/sardana/tango/pool/PseudoCounter.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/sardana/tango/pool/PseudoCounter.py b/src/sardana/tango/pool/PseudoCounter.py index 694a9df5ed..2774bccdd9 100644 --- a/src/sardana/tango/pool/PseudoCounter.py +++ b/src/sardana/tango/pool/PseudoCounter.py @@ -32,7 +32,7 @@ import sys import time -from PyTango import Except, READ, SCALAR, DevDouble, \ +from PyTango import Except, READ, SCALAR, SPECTRUM, IMAGE, DevDouble, \ DevVarStringArray, DevVarDoubleArray, DevState, AttrQuality, DevFailed from taurus.core.util.log import DebugIt @@ -175,13 +175,23 @@ def get_dynamic_attributes(self): PoolExpChannelDevice.get_dynamic_attributes(self) if not cache_built: - # For value attribute, listen to what the controller says for data - # type (between long and float) + # For value attribute, listen to what the controller says for data + # type (between long and float) and data format (scalar, spectrum or + # image) value = std_attrs.get('value') if value is not None: _, data_info, attr_info = value - ttype, _ = to_tango_type_format(attr_info.dtype) + ttype, tformat = to_tango_type_format(attr_info.dtype, + attr_info.dformat) data_info[0][0] = ttype + data_info[0][1] = tformat + if tformat == SPECTRUM: + shape = attr_info.maxdimsize + data_info[0].append(shape[0]) + elif tformat == IMAGE: + shape = attr_info.maxdimsize + data_info[0].append(shape[0]) + data_info[0].append(shape[1]) return std_attrs, dyn_attrs def initialize_dynamic_attributes(self): From 6af64a5c7de7410f052a2731cd7f04a71b169702 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 23 Nov 2018 15:16:13 +0100 Subject: [PATCH 366/652] Fix bug when reading pseudo counter's value --- src/sardana/tango/pool/PseudoCounter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/tango/pool/PseudoCounter.py b/src/sardana/tango/pool/PseudoCounter.py index 2774bccdd9..2cd8c71078 100644 --- a/src/sardana/tango/pool/PseudoCounter.py +++ b/src/sardana/tango/pool/PseudoCounter.py @@ -224,7 +224,7 @@ def read_Value(self, attr): state = pseudo_counter.get_state(cache=use_cache, propagate=0) if state == State.Moving: quality = AttrQuality.ATTR_CHANGING - timestamp = value_attr.value + timestamp = value_attr.timestamp self.set_attribute(attr, value=value, quality=quality, priority=0, timestamp=timestamp) From 386403fc152a0f96075a6c24428ab6f60d36b3ae Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 23 Nov 2018 15:51:52 +0100 Subject: [PATCH 367/652] Document how to change elements default interface --- .../howto_controllers/howto_controller.rst | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/doc/source/devel/howto_controllers/howto_controller.rst b/doc/source/devel/howto_controllers/howto_controller.rst index 499a288e1c..83b499fe8d 100644 --- a/doc/source/devel/howto_controllers/howto_controller.rst +++ b/doc/source/devel/howto_controllers/howto_controller.rst @@ -404,6 +404,33 @@ spock), sardana assignes the default value has no default value, if it is not specified by the user, sardana will complain and fail to create and instance of SpringfieldMotorController. +.. _sardana-controller-howto-change-default-interface: + +Changing default interface +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Elements instantiated from your controller will have a default interface +corresponding to the controller's type. For example a moveable will have a +*position* attribute or an experimental channel will have a *value* +attribute. However this default interface can be changed if necessary. + +For example, the default type of a moveable's *position* attribute ``float`` +can be changed to ``long`` if the given axis only allows discrete positions. +To do that simple override the +:class:`~sardana.pool.controller.Controller.GetAxisAttributes` where you can +apply the necessary changes. + +Here is an example of how to change motor's *position* attribute to ``long``: + +.. code-block:: python + + def GetAxisAttributes(self, axis): + axis_attrs = MotorController.GetAxisAttributes(self, axis) + axis_attrs = dict(axis_attrs) + axis_attrs['Position']['type'] = float + return axis_attrs + + .. _sardana-controller-howto-error-handling: Error handling From ddf62b0c6b043412435f0295de57b6cf0a97daab Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 23 Nov 2018 16:29:05 +0100 Subject: [PATCH 368/652] Add ROI to glossary --- doc/source/glossary.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/source/glossary.rst b/doc/source/glossary.rst index a44d300aba..fb0a9faa37 100644 --- a/doc/source/glossary.rst +++ b/doc/source/glossary.rst @@ -420,6 +420,10 @@ Glossary dial See :term:`dial position` + + ROI + *Region of interest* are samples within a data set identified for a + particular purpose. .. _plug-in: http://en.wikipedia.org/wiki/Plug-in_(computing) .. _CCD: http://en.wikipedia.org/wiki/Charge-coupled_device From e9df81516fb24aef022be341e0872da81adfe321 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 23 Nov 2018 16:29:32 +0100 Subject: [PATCH 369/652] Document how to change pseudo counter's value attribute --- .../howto_pseudocountercontroller.rst | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst index 8a19f91cf4..55d49a29b8 100644 --- a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst +++ b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst @@ -66,6 +66,31 @@ negative. The value close to the zero indicates the beam centered in the middle. Similarly behaves the horizontal pseudo counter. The total pseudo counter is the mean value of all the four sensors and indicates the beam intensity. +Changing default interface +-------------------------- + +Pseudo counters instantiated from your controller will have a default +interface, which among others, comprises the *value* attribute. This attribute +is feed with the result of the +:meth:`~sardana.pool.controller.PseudoCounterController.calc` method and by +default it expects values of ``float`` type and scalar shape. You can easily +:ref:`change the default interface `. +This way you could program a pseudo counter to obtain an image :term:`ROI` +of a :ref:`2D experimental channel `. + +Here is an example of how to change *value* attribute's shape to an image +and specify its maximum dimension of 1024 x 1024 pixels: + +.. code-block:: python + + def GetAxisAttributes(self, axis): + axis_attrs = PseudoCounterController.GetAxisAttributes(self, axis) + axis_attrs = dict(axis_attrs) + axis_attrs['Value'][Type] = (float, float) + axis_attrs['Value'][MaxDimSize] = (1024, 1024) + return axis_attrs + + Including external variables in the calculation ----------------------------------------------- From 0c55e81752c9917116668eaa8d335b9a6af094a1 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 23 Nov 2018 16:33:34 +0100 Subject: [PATCH 370/652] Fix PEP8 --- src/sardana/tango/pool/PseudoCounter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/tango/pool/PseudoCounter.py b/src/sardana/tango/pool/PseudoCounter.py index 2cd8c71078..1fe70eb200 100644 --- a/src/sardana/tango/pool/PseudoCounter.py +++ b/src/sardana/tango/pool/PseudoCounter.py @@ -175,9 +175,9 @@ def get_dynamic_attributes(self): PoolExpChannelDevice.get_dynamic_attributes(self) if not cache_built: - # For value attribute, listen to what the controller says for data - # type (between long and float) and data format (scalar, spectrum or - # image) + # For value attribute, listen to what the controller says for data + # type (between long and float) and data format (scalar, spectrum + # or image) value = std_attrs.get('value') if value is not None: _, data_info, attr_info = value From 8c851bc95f9f107b93f1a2ae4592ef52f960fd47 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 23 Nov 2018 21:51:59 +0100 Subject: [PATCH 371/652] Fix sphinx warning --- .../devel/howto_controllers/howto_pseudocountercontroller.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst index 55d49a29b8..f275d77dfd 100644 --- a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst +++ b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst @@ -76,7 +76,7 @@ is feed with the result of the default it expects values of ``float`` type and scalar shape. You can easily :ref:`change the default interface `. This way you could program a pseudo counter to obtain an image :term:`ROI` -of a :ref:`2D experimental channel `. +of a :ref:`2D experimental channel `. Here is an example of how to change *value* attribute's shape to an image and specify its maximum dimension of 1024 x 1024 pixels: From 3f1bed03bc5d69ce51cc2b3fe37bcc63b36771ba Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 27 Nov 2018 16:08:08 +0100 Subject: [PATCH 372/652] Fix bug in documentation in setting 2D shape of pseudocounter --- .../devel/howto_controllers/howto_pseudocountercontroller.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst index f275d77dfd..7eebe55d1b 100644 --- a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst +++ b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst @@ -86,7 +86,7 @@ and specify its maximum dimension of 1024 x 1024 pixels: def GetAxisAttributes(self, axis): axis_attrs = PseudoCounterController.GetAxisAttributes(self, axis) axis_attrs = dict(axis_attrs) - axis_attrs['Value'][Type] = (float, float) + axis_attrs['Value'][Type] = ((float, ), ) axis_attrs['Value'][MaxDimSize] = (1024, 1024) return axis_attrs From 23798d8e5a5bc1547fa80dcf073223968524248f Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 27 Nov 2018 16:35:39 +0100 Subject: [PATCH 373/652] Doc: possibility to omit pseudo_counter_roles --- .../howto_controllers/howto_pseudocountercontroller.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst index 8a19f91cf4..0392e3d4ca 100644 --- a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst +++ b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst @@ -37,6 +37,13 @@ These names are used when creating the controller instance and their order is important when writing the controller itself. Each controller will define its own roles. +.. note:: + + It is possible to omit the + :obj:`~sardana.pool.controller.PseudoCounterController.pseudo_counter_roles` + definition if the controller provides only one axis. The controller class + name will be assumed as the pseudo counter role. + The constructor does nothing apart of calling the parent class constructor but could be used to implement any necessary initialization. From b8df884eecc13196cba6d5a456b059b241308998 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 28 Nov 2018 14:18:16 +0100 Subject: [PATCH 374/652] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5e974882b..df17171800 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This file follows the formats and conventions from [keepachangelog.com] - Possibility to pass values of repeat paramters with just one member without the need to encapsulate them in square brackets (spock syntax) or list (macro API) (#781, #983) +- Possibility to change data format (shape) of of pseudo counter values (#986) - Workaround for API_DeviceTimedOut errors on MeasurementGroup Start. Call Stop in case this error occured (#764). - Optional measurement group parameter to `ct` and `uct` macros (#940, #473) From 71f601174e6f052f927299febc0d84b3c94098ac Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 28 Nov 2018 14:22:09 +0100 Subject: [PATCH 375/652] Fix expconf for PyQt4.4 (signal style compatibility) --- .../taurus/qt/qtgui/extra_sardana/expdescription.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 9911a52b94..bb397cb00e 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -172,6 +172,12 @@ class ExpDescriptionEditor(Qt.QWidget, TaurusBaseWidget): using the `ExperimentConfiguration` environmental variable for that Door. ''' + try: + #TODO: For Taurus 4 compatibility + createExpConfChangedDialog = Qt.pyqtSignal() + except AttributeError: + pass + def __init__(self, parent=None, door=None, plotsButton=True, autoUpdate=False): Qt.QWidget.__init__(self, parent) @@ -205,7 +211,7 @@ def __init__(self, parent=None, door=None, plotsButton=True, # Pending event variables self._expConfChangedDialog = None - self.createExpConfChangedDialog = Qt.pyqtSignal() + self.connect(self, Qt.SIGNAL('createExpConfChangedDialog'), self._createExpConfChangedDialog) @@ -351,6 +357,9 @@ def _experimentConfigurationChanged(self): else: if self._expConfChangedDialog is None: self.emit(Qt.SIGNAL('createExpConfChangedDialog')) + # TODO: For Taurus 4 compatibility + if hasattr(self, 'createExpConfChangedDialog'): + self.createExpConfChangedDialog.emit() else: msg_details = self._getDetialsText() msg_info = self._getResumeText() From 70533ec334d9b0d29afbdc824937463481ae4bbb Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 28 Nov 2018 15:18:42 +0100 Subject: [PATCH 376/652] Fix flake8 --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index bb397cb00e..32ae56f1d1 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -173,7 +173,7 @@ class ExpDescriptionEditor(Qt.QWidget, TaurusBaseWidget): ''' try: - #TODO: For Taurus 4 compatibility + # TODO: For Taurus 4 compatibility createExpConfChangedDialog = Qt.pyqtSignal() except AttributeError: pass From 32cc8d33ce9de35679cc3f953872ccf8ed278ef2 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 28 Nov 2018 18:01:13 +0100 Subject: [PATCH 377/652] Fix limits protection in ascanct when Taurus 4 is used Taurus 4 uses quantities as attribute values, range, etc. Sardana for the moment does not support them, for example it is not possible to pass macro parameters as quantities. In the continuous scan, when motor limits are checked, it is better to use the position attribute limit magnitudes. --- src/sardana/macroserver/scan/gscan.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index a61da2bee4..c2c6224c6a 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -1481,6 +1481,12 @@ def get_min_pos(self, motor): ''' pos_obj = motor.getPositionObj() min_pos, _ = pos_obj.getRange() + try: + # Taurus 4 uses quantities however Sardana does not support them + # yet - use magnitude for the moment. + min_pos = min_pos.magnitude + except AttributeError: + pass try: min_pos = float(min_pos) except ValueError: @@ -1494,6 +1500,12 @@ def get_max_pos(self, motor): ''' pos_obj = motor.getPositionObj() _, max_pos = pos_obj.getRange() + try: + # Taurus 4 uses quantities however Sardana does not support them + # yet - use magnitude for the moment. + max_pos = max_pos.magnitude + except AttributeError: + pass try: max_pos = float(max_pos) except ValueError: From ee68eb2e7985d87957990f7cb17c8c0d25985bf6 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 29 Nov 2018 11:18:35 +0100 Subject: [PATCH 378/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df17171800..67421fd462 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ This file follows the formats and conventions from [keepachangelog.com] configuration (#806, #882) - Reload macro library overriding another library (#927, #946) - Avoid final padding in timescan when it was stopped by user (#869, #935) +- Moveables limits check in continuous scans when moveables position attribute + has unit configured and Taurus 4 is used (quantities) (#989, #990) - Hook places advertised by continuous scans so the `allowHooks` hint and the code are coherent (#936) - Macro/controller module description when module does not have a docstring From 1d844c063aa414f97a0d04d702a8c0c30227f8d5 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 29 Nov 2018 12:04:46 +0100 Subject: [PATCH 379/652] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67421fd462..ed30be3b43 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ This file follows the formats and conventions from [keepachangelog.com] configurations. An event offers an option to reload the whole experiment configuration or keep the local changes. `expconf` started with `--auto-update` option will automatically reload the whole experiment - configuration (#806, #882) + configuration (#806, #882, #988) - Reload macro library overriding another library (#927, #946) - Avoid final padding in timescan when it was stopped by user (#869, #935) - Moveables limits check in continuous scans when moveables position attribute From ce1d50438607892c80ebe97b28582c6bfd9f7060 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Fri, 30 Nov 2018 16:18:30 +0100 Subject: [PATCH 380/652] use Taurus facilities to get moveable limits --- src/sardana/macroserver/scan/gscan.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index 0962248fa1..c9fe07bb56 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -373,14 +373,19 @@ def __init__(self, macro, generator=None, moveables=[], env={}, def _check_moveables_limits(self): for m in self._moveables: - config = PyTango.AttributeProxy( - m.moveable.getName() + '/position').get_config() + pos_range = m.moveable.getAttribute("Position").range try: - high = float(config.max_value) + if type(pos_range[1]) == str: + high = float(pos_range[1]) # Taurus 3 + else: + high = float(pos_range[1].magnitude) # Taurus 4 except ValueError: high = None try: - low = float(config.min_value) + if type(pos_range[0]) == str: + low = float(pos_range[0]) # Taurus 3 + else: + low = float(pos_range[0].magnitude) # Taurus 4 except ValueError: low = None From 09413b746f7fc34dd58b51423ff18671b66864ad Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 10 Dec 2018 13:16:34 +0100 Subject: [PATCH 381/652] Add ref to AcqSynchType when documenting AcqSynch --- src/sardana/pool/pooldefs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sardana/pool/pooldefs.py b/src/sardana/pool/pooldefs.py index eba5b39b4a..edb5f21ace 100644 --- a/src/sardana/pool/pooldefs.py +++ b/src/sardana/pool/pooldefs.py @@ -133,7 +133,9 @@ class AcqSynch(Enumeration): Uses software/hardware naming to refer to internal (software synchronizer) or external (hardware synchronization device) - synchronization modes + synchronization modes. See :class:`~sardana.pool.pooldefs.AcqSynchType` + to get more details about the synchronization type e.g. trigger, gate or + start. .. todo:: convert to python enums, but having in mind problems with JSON serialization: https://bugs.python.org/issue18264 From f2a178ec535509a561fd856a9063240d36be1d55 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 10 Dec 2018 14:44:26 +0100 Subject: [PATCH 382/652] Document poolsynchronization module --- doc/source/devel/api/sardana/pool.rst | 1 + .../api/sardana/pool/poolsynchronization.rst | 36 +++++++++++++ src/sardana/pool/poolacquisition.py | 5 +- src/sardana/pool/poolsynchronization.py | 50 +++++++++++-------- 4 files changed, 67 insertions(+), 25 deletions(-) create mode 100755 doc/source/devel/api/sardana/pool/poolsynchronization.rst diff --git a/doc/source/devel/api/sardana/pool.rst b/doc/source/devel/api/sardana/pool.rst index 6465378d7f..e286d2cd6b 100644 --- a/doc/source/devel/api/sardana/pool.rst +++ b/doc/source/devel/api/sardana/pool.rst @@ -38,6 +38,7 @@ poolonedexpchannel poolpseudocounter poolpseudomotor + poolsynchronization pooltwodexpchannel poolutil poolzerodexpchannel diff --git a/doc/source/devel/api/sardana/pool/poolsynchronization.rst b/doc/source/devel/api/sardana/pool/poolsynchronization.rst new file mode 100755 index 0000000000..35e600de2f --- /dev/null +++ b/doc/source/devel/api/sardana/pool/poolsynchronization.rst @@ -0,0 +1,36 @@ +.. currentmodule:: sardana.pool.poolsynchronization + +:mod:`~sardana.pool.poolsynchronization` +======================================== + +.. automodule:: sardana.pool.poolsynchronization + +.. rubric:: Classes + +.. hlist:: + :columns: 3 + + * :class:`SynchronizationDescription` + * :class:`PoolSynchronization` + +PoolSynchronization +------------------- + +.. inheritance-diagram:: PoolSynchronization + :parts: 1 + +.. autoclass:: PoolSynchronization + :show-inheritance: + :members: + :undoc-members: + +SynchronizationDescription +-------------------------- + +.. inheritance-diagram:: SynchronizationDescription + :parts: 1 + +.. autoclass:: SynchronizationDescription + :show-inheritance: + :members: + :undoc-members: diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 89d6dead3f..2287de313f 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -405,9 +405,8 @@ def prepare(self, config, acq_mode, value, synchronization=None, # Prepare synchronizer controllers ctrls = config.get_synch_ctrls(enabled=True) ctrls_synch = get_synch_acq_items(ctrls) - synch_args = (ctrls_synch,) - synch_kwargs = {'synchronization': synchronization, - 'moveable': moveable, + synch_args = (ctrls_synch, synchronization) + synch_kwargs = {'moveable': moveable, 'sw_synch_initial_domain': sw_synch_initial_domain} synch_kwargs.update(kwargs) self._synch_args = ActionArgs(synch_args, synch_kwargs) diff --git a/src/sardana/pool/poolsynchronization.py b/src/sardana/pool/poolsynchronization.py index c9d6d4d7fd..aaf81832bc 100644 --- a/src/sardana/pool/poolsynchronization.py +++ b/src/sardana/pool/poolsynchronization.py @@ -24,8 +24,8 @@ ############################################################################## -"""This module is part of the Python Pool libray. It defines the class for the -trigger/gate generation""" +"""This module is part of the Python Pool library. It defines the classes +for the synchronization""" __all__ = ["PoolSynchronization", "SynchronizationDescription", "TGChannel"] @@ -113,8 +113,10 @@ def _get_param(self, param, domain=SynchDomain.Time): class PoolSynchronization(PoolAction): - '''Action class responsible for trigger/gate generation - ''' + """Synchronization action. + + It coordinates trigger/gate elements and software synchronizer. + """ def __init__(self, main_element, name="Synchronization"): PoolAction.__init__(self, main_element, name) @@ -133,18 +135,22 @@ def add_listener(self, listener): def start_action(self, ctrls, synchronization, moveable=None, sw_synch_initial_domain=None, *args, **kwargs): - '''Start action method. Expects the following kwargs: - - - ctrls - dictionary containing measurement group configuration - - synchronization - list of dictionaries containing information about - the expected synchronization - - moveable (optional)- moveable object used as the synchronization - source in the Position domain - - monitor (optional) - counter/timer object used as the synchronization - source in the Monitor domain - - sw_synch_initial_domain (optional) - initial domain for software - synchronizer, can be either SynchDomain.Time or SynchDomain.Position - ''' + """Start synchronization action. + + :param ctrls: list of enabled trigger/gate controllers + :type ctrls: list + :param synchronization: synchronization description + :type synchronization: + :class:`~sardana.pool.poolsynchronization.SynchronizationDescription` + :param moveable: (optional) moveable object used as the + synchronization source in the Position domain + :type moveable: :class:`~sardna.pool.poolmotor.PoolMotor` or + :class:`~sardana.pool.poolpseudomotor.PoolPseudoMotor` + :param sw_synch_initial_domain: (optional) - initial domain for + software synchronizer, can be either + :obj:`~sardana.pool.pooldefs.SynchDomain.Time` or + :obj:`~sardana.pool.pooldefs.SynchDomain.Position` + """ with ActionContext(self): # loads synchronization description @@ -219,15 +225,15 @@ def start_action(self, ctrls, synchronization, moveable=None, pool_ctrl.ctrl.StartAll() def is_triggering(self, states): - """Determines if we are triggering or if the triggering has ended - based on the states returned by the controller(s) and the software - TG generation. + """Determines if we are synchronizing or not based on the states + returned by the controller(s) and the software synchronizer. :param states: a map containing state information as returned by read_state_info: ((state, status), exception_error) :type states: dict Date: Mon, 10 Dec 2018 14:44:55 +0100 Subject: [PATCH 383/652] (minor) cast to lowercase NbStarts attribute name --- src/sardana/tango/pool/MeasurementGroup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/tango/pool/MeasurementGroup.py b/src/sardana/tango/pool/MeasurementGroup.py index 5a6a1669ff..f9c449067b 100644 --- a/src/sardana/tango/pool/MeasurementGroup.py +++ b/src/sardana/tango/pool/MeasurementGroup.py @@ -74,7 +74,7 @@ def init_device(self): PoolGroupDevice.init_device(self) # state and status are already set by the super class detect_evts = "latencytime", "moveable", "synchronization", \ - "softwaresynchronizerinitialdomain", "NbStarts" + "softwaresynchronizerinitialdomain", "nbstarts" non_detect_evts = "configuration", "integrationtime", "monitorcount", \ "acquisitionmode", "elementlist" self.set_change_events(detect_evts, non_detect_evts) From 7abd78a13a4e5096e90b31391c86d01869215ce0 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 10 Dec 2018 16:08:19 +0100 Subject: [PATCH 384/652] Document measurement configuration classes --- .../api/sardana/pool/poolmeasurementgroup.rst | 77 ++++++++++++++- src/sardana/pool/poolmeasurementgroup.py | 97 ++++++++++++++++++- 2 files changed, 168 insertions(+), 6 deletions(-) diff --git a/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst b/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst index 7f5c2ed0b1..7dedf2e8ed 100644 --- a/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst +++ b/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst @@ -11,16 +11,87 @@ :columns: 3 * :class:`PoolMeasurementGroup` + * :class:`ConfigurationItem` + * :class:`ControllerConfiguration` + * :class:`TimerableControllerConfiguration` + * :class:`ExternalControllerConfiguration` + * :class:`ChannelConfiguration` + * :class:`SynchronizerConfiguration` -PoolInstrument --------------- +PoolMeasurementGroup +-------------------- .. inheritance-diagram:: PoolMeasurementGroup :parts: 1 - + .. autoclass:: PoolMeasurementGroup :show-inheritance: :members: :undoc-members: +ConfigurationItem +----------------- + +.. inheritance-diagram:: ConfigurationItem + :parts: 1 + +.. autoclass:: ConfigurationItem + :show-inheritance: + :members: + :undoc-members: + +ControllerConfiguration +----------------------- + +.. inheritance-diagram:: ControllerConfiguration + :parts: 1 + +.. autoclass:: ControllerConfiguration + :show-inheritance: + :members: + :undoc-members: + +TimerableControllerConfiguration +-------------------------------- + +.. inheritance-diagram:: TimerableControllerConfiguration + :parts: 1 + +.. autoclass:: TimerableControllerConfiguration + :show-inheritance: + :members: + :undoc-members: + +ExternalControllerConfiguration +------------------------------- + +.. inheritance-diagram:: ExternalControllerConfiguration + :parts: 1 + +.. autoclass:: ExternalControllerConfiguration + :show-inheritance: + :members: + :undoc-members: + +ChannelConfiguration +-------------------- + +.. inheritance-diagram:: ChannelConfiguration + :parts: 1 + +.. autoclass:: ChannelConfiguration + :show-inheritance: + :members: + :undoc-members: + +SynchronizerConfiguration +------------------------- + +.. inheritance-diagram:: SynchronizerConfiguration + :parts: 1 + +.. autoclass:: SynchronizerConfiguration + :show-inheritance: + :members: + :undoc-members: diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 6c331a09ad..5b9fd37eb0 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -129,8 +129,28 @@ def _to_fqdn(name, logger=None): class ConfigurationItem(object): + """Container of configuration attributes related to a given element. + + Wrap an element to pretend its API. + Manage the element's configuration. + Hold an information whether the element is enabled. + By default it is enabled. + + .. note:: + The ConfigurationItem class has been included in Sardana + on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. + """ def __init__(self, element, attrs=None): + """Construct a wrapper around the element + + :param element: element to wrap + :type element: obj + :param: attrs: configuration attributes and their values + :type attrs: dict + """ self._element = weakref.ref(element) self.enabled = True @@ -152,7 +172,19 @@ def set_element(self, element): class ControllerConfiguration(ConfigurationItem): - """Configuration: 'timer', 'monitor', 'synchronization', 'channels'""" + """Container of configuration attributes related to a given controller. + + Inherit behavior from + :class:`~sardana.pool.poolmeasurementgroup.ConfigurationItem` + and additionally hold information about its enabled/disabled channels. + By default it is disabled. + + .. note:: + The ControllerConfiguration class has been included in Sardana + on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. + """ def __init__(self, element, attrs=None): ConfigurationItem.__init__(self, element, attrs) @@ -162,6 +194,7 @@ def __init__(self, element, attrs=None): self._channels_disabled = [] def add_channel(self, channel_item): + """Aggregate a channel configuration item.""" self._channels.append(channel_item) if channel_item.enabled: self.enabled = True @@ -174,6 +207,7 @@ def add_channel(self, channel_item): self._channels_disabled.append(channel_item) def update_state(self): + """Update internal state based on the aggregated channels.""" self.enabled = False self._channels_enabled = [] self._channels_disabled = [] @@ -185,6 +219,15 @@ def update_state(self): self._channels_disabled.append(channel_item) def get_channels(self, enabled=None): + """Return aggregated channels. + + :param enabled: which channels to return + - True - only enabled + - False - only disabled + - None - all + + :type enabled: bool or None + """ if enabled is None: return list(self._channels) elif enabled: @@ -197,6 +240,19 @@ def validate(self): class TimerableControllerConfiguration(ControllerConfiguration): + """Container of configuration attributes related to a given + timerable controller. + + Inherit behavior from + :class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration` + and additionally validate *timer* and *monitor* configuration. + + .. note:: + The TimerableControllerConfiguration class has been included in + Sardana on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. + """ def update_timer(self): self._update_master("timer") @@ -233,6 +289,18 @@ def validate(self): class ExternalControllerConfiguration(ControllerConfiguration): + """Container of configuration attributes related to a given + external controller. + + Inherit behavior from + :class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`. + + .. note:: + The ExternalControllerConfiguration class has been included in + Sardana on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. + """ def __init__(self, element, attrs=None): ControllerConfiguration.__init__(self, self, attrs) @@ -240,11 +308,34 @@ def __init__(self, element, attrs=None): class ChannelConfiguration(ConfigurationItem): - """Configuration: 'index', 'enabled', 'output', 'plot_type', 'plot_axes', - 'label', 'scale', 'plot_color'""" + """Container of configuration attributes related to a given + experimental channel. + + Inherit behavior from + :class:`~sardana.pool.poolmeasurementgroup.ConfigurationItem`. + + .. note:: + The ChannelConfiguration class has been included in + Sardana on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. + """ class SynchronizerConfiguration(ConfigurationItem): + """Container of configuration attributes related to a given + synchronizer element. + + Inherit behavior from + :class:`~sardana.pool.poolmeasurementgroup.ConfigurationItem`. + By default it is disabled. + + .. note:: + The ChannelConfiguration class has been included in + Sardana on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. + """ def __init__(self, element, attrs=None): ConfigurationItem.__init__(self, element, attrs) From f3ce37cccb3063d0c72423bbcdb441f672ffa4e6 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Tue, 11 Dec 2018 17:18:10 +0100 Subject: [PATCH 385/652] disable cache db by default --- src/sardana/tango/core/util.py | 7 +------ src/sardana/tango/macroserver/MacroServer.py | 5 +++-- src/sardana/tango/pool/Pool.py | 5 +++-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/sardana/tango/core/util.py b/src/sardana/tango/core/util.py index e2631eca6e..6f6e2bbe20 100644 --- a/src/sardana/tango/core/util.py +++ b/src/sardana/tango/core/util.py @@ -936,12 +936,7 @@ def get_logstash_conf(dev_name, class_name=None): props = db.get_device_property(dev_name, "LogstashCacheDbPath") cache_db_path = props["LogstashCacheDbPath"][0] except IndexError: - if class_name == "Pool": - cache_db_path = "/tmp/sardana-pool-logstash-cache.db" - elif class_name == "MacroServer": - cache_db_path = "/tmp/sardana-ms-logstash-cache.db" - else: - cache_db_path = "/tmp/sardana-logstash-cache.db" + cache_db_path = None return host, port, cache_db_path db = Database() diff --git a/src/sardana/tango/macroserver/MacroServer.py b/src/sardana/tango/macroserver/MacroServer.py index 7a0e73ed3f..57b3cf1674 100644 --- a/src/sardana/tango/macroserver/MacroServer.py +++ b/src/sardana/tango/macroserver/MacroServer.py @@ -400,8 +400,9 @@ class MacroServerClass(SardanaDeviceClass): None], 'LogstashCacheDbPath': [DevString, - "Path to the Logstash cache database [default: " - "/tmp/sardana-ms-logstash-cache.db]. " + "Path to the Logstash cache database [default: None]. " + "It is advised not to use the database cache, as it may " + "have negative effects on logging performance. See #895. " "This property has been included in Sardana on a provisional " "basis. Backwards incompatible changes (up to and including " "its removal) may occur if deemed necessary by the " diff --git a/src/sardana/tango/pool/Pool.py b/src/sardana/tango/pool/Pool.py index eda5ec3a33..6969e14b38 100644 --- a/src/sardana/tango/pool/Pool.py +++ b/src/sardana/tango/pool/Pool.py @@ -1383,8 +1383,9 @@ class PoolClass(PyTango.DeviceClass): None], 'LogstashCacheDbPath': [PyTango.DevString, - "Path to the Logstash cache database [default: " - "/tmp/sardana-pool-logstash-cache.db]. " + "Path to the Logstash cache database [default: None]. " + "It is advised not to use the database cache, as it may " + "have negative effects on logging performance. See #895. " "This property has been included in Sardana on a provisional " "basis. Backwards incompatible changes (up to and including " "its removal) may occur if deemed necessary by the " From d17b5dae2d43c9d68586b3a86d40237a4d040e21 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Tue, 11 Dec 2018 17:28:13 +0100 Subject: [PATCH 386/652] don't rely on limit value type --- src/sardana/macroserver/scan/gscan.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py index c9fe07bb56..94cd2fc422 100644 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -375,19 +375,19 @@ def _check_moveables_limits(self): for m in self._moveables: pos_range = m.moveable.getAttribute("Position").range try: - if type(pos_range[1]) == str: - high = float(pos_range[1]) # Taurus 3 - else: - high = float(pos_range[1].magnitude) # Taurus 4 - except ValueError: - high = None + high = float(pos_range[1].magnitude) # Taurus 4 + except AttributeError: + try: + high = float(pos_range[1]) # Taurus 3 + except ValueError: + high = None try: - if type(pos_range[0]) == str: - low = float(pos_range[0]) # Taurus 3 - else: - low = float(pos_range[0].magnitude) # Taurus 4 - except ValueError: - low = None + low = float(pos_range[0].magnitude) # Taurus 4 + except AttributeError: + try: + low = float(pos_range[0]) # Taurus 3 + except ValueError: + low = None if any((high, low)) and not any((m.min_value, m.max_value)): self._macro.info("Scan range is not defined for %s and could " From c880d2f0bab4eb7c413ae823ba59bdd873641c9f Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 12 Dec 2018 17:33:08 +0100 Subject: [PATCH 387/652] Correct import error message --- src/sardana/tango/core/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/tango/core/util.py b/src/sardana/tango/core/util.py index 6f6e2bbe20..b97cd24508 100644 --- a/src/sardana/tango/core/util.py +++ b/src/sardana/tango/core/util.py @@ -916,7 +916,7 @@ def prepare_logstash(args): try: from logstash_async.handler import AsynchronousLogstashHandler except ImportError: - msg = ("Unable to import logstash. Skipping logstash " + msg = ("Unable to import logstash_async. Skipping logstash " + "configuration...", ) log_messages.append(msg,) return log_messages From 25c7cb3fcb92f89e1802023dd291edf7d475f36d Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Wed, 12 Dec 2018 17:53:13 +0100 Subject: [PATCH 388/652] remove default values for LogstashCacheDbPath --- src/sardana/tango/macroserver/MacroServer.py | 2 +- src/sardana/tango/pool/Pool.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/tango/macroserver/MacroServer.py b/src/sardana/tango/macroserver/MacroServer.py index 57b3cf1674..474f6bc5ef 100644 --- a/src/sardana/tango/macroserver/MacroServer.py +++ b/src/sardana/tango/macroserver/MacroServer.py @@ -407,7 +407,7 @@ class MacroServerClass(SardanaDeviceClass): "basis. Backwards incompatible changes (up to and including " "its removal) may occur if deemed necessary by the " "core developers.", - "/tmp/sardana-ms-logstash-cache.db"] + None] } # Command definitions diff --git a/src/sardana/tango/pool/Pool.py b/src/sardana/tango/pool/Pool.py index 6969e14b38..30829634b1 100644 --- a/src/sardana/tango/pool/Pool.py +++ b/src/sardana/tango/pool/Pool.py @@ -1390,7 +1390,7 @@ class PoolClass(PyTango.DeviceClass): "basis. Backwards incompatible changes (up to and including " "its removal) may occur if deemed necessary by the " "core developers.", - "/tmp/sardana-pool-logstash-cache.db"] + None] } # Command definitions From 9dc4bd4508413e985c8107935fdea354618f5241 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Wed, 12 Dec 2018 17:58:56 +0100 Subject: [PATCH 389/652] add default value for LogstashPort --- src/sardana/tango/core/util.py | 2 +- src/sardana/tango/macroserver/MacroServer.py | 4 ++-- src/sardana/tango/pool/Pool.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sardana/tango/core/util.py b/src/sardana/tango/core/util.py index b97cd24508..1102a46cb0 100644 --- a/src/sardana/tango/core/util.py +++ b/src/sardana/tango/core/util.py @@ -931,7 +931,7 @@ def get_logstash_conf(dev_name, class_name=None): props = db.get_device_property(dev_name, "LogstashPort") port = int(props["LogstashPort"][0]) except IndexError: - port = 12345 + port = None try: props = db.get_device_property(dev_name, "LogstashCacheDbPath") cache_db_path = props["LogstashCacheDbPath"][0] diff --git a/src/sardana/tango/macroserver/MacroServer.py b/src/sardana/tango/macroserver/MacroServer.py index 474f6bc5ef..a47481a4be 100644 --- a/src/sardana/tango/macroserver/MacroServer.py +++ b/src/sardana/tango/macroserver/MacroServer.py @@ -392,12 +392,12 @@ class MacroServerClass(SardanaDeviceClass): None], 'LogstashPort': [DevLong, - "Port on which Logstash will listen on events. " + "Port on which Logstash will listen on events [default: 12345]. " "This property has been included in Sardana on a provisional " "basis. Backwards incompatible changes (up to and including " "its removal) may occur if deemed necessary by the " "core developers.", - None], + 12345], 'LogstashCacheDbPath': [DevString, "Path to the Logstash cache database [default: None]. " diff --git a/src/sardana/tango/pool/Pool.py b/src/sardana/tango/pool/Pool.py index 30829634b1..671a4f7aa7 100644 --- a/src/sardana/tango/pool/Pool.py +++ b/src/sardana/tango/pool/Pool.py @@ -1375,12 +1375,12 @@ class PoolClass(PyTango.DeviceClass): None], 'LogstashPort': [PyTango.DevLong, - "Port on which Logstash will listen on events. " + "Port on which Logstash will listen on events [default: 12345]. " "This property has been included in Sardana on a provisional " "basis. Backwards incompatible changes (up to and including " "its removal) may occur if deemed necessary by the " "core developers.", - None], + 12345], 'LogstashCacheDbPath': [PyTango.DevString, "Path to the Logstash cache database [default: None]. " From 9a6f791b926abc677f40a1a9606db9984fc2cbc4 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Wed, 12 Dec 2018 18:10:10 +0100 Subject: [PATCH 390/652] update Logstash integration documentation --- doc/source/users/configuration/macroserver.rst | 3 +++ doc/source/users/configuration/pool.rst | 3 +++ 2 files changed, 6 insertions(+) diff --git a/doc/source/users/configuration/macroserver.rst b/doc/source/users/configuration/macroserver.rst index 3ce5a6142b..d7412dbb10 100644 --- a/doc/source/users/configuration/macroserver.rst +++ b/doc/source/users/configuration/macroserver.rst @@ -49,6 +49,9 @@ MacroServer integrates natively with the instance. In case Sardana is used with Tango this configuration is accessible via the ``LogstashHost`` and ``LogstashPort`` :class:`~sardana.tango.macroserver.MacroServer.MacroServer` device properties. +You can use the intermediate SQLite cache database configured with +``LogstashCacheDbPath`` property, however this is discouraged due to logging +performance problems. .. todo:: Document RConsolePort diff --git a/doc/source/users/configuration/pool.rst b/doc/source/users/configuration/pool.rst index c4f8ffba7b..1c86f59e00 100644 --- a/doc/source/users/configuration/pool.rst +++ b/doc/source/users/configuration/pool.rst @@ -20,6 +20,9 @@ Device Pool integrates natively with the instance. In case Sardana is used with Tango this configuration is accessible via the ``LogstashHost`` and ``LogstashPort`` :class:`~sardana.tango.pool.Pool.Pool` device properties. +You can use the intermediate SQLite cache database configured with +``LogstashCacheDbPath`` property, however this is discouraged due to logging +performance problems. .. todo:: From 5e806f96b47eb2f945b186780732ec094f10bc5c Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 12 Dec 2018 19:08:53 +0100 Subject: [PATCH 391/652] Document build_measurement_configuration function --- .../api/sardana/pool/poolmeasurementgroup.rst | 8 +++++ src/sardana/pool/poolmeasurementgroup.py | 31 ++++++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst b/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst index 7dedf2e8ed..5f8a5b12de 100644 --- a/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst +++ b/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst @@ -5,6 +5,13 @@ .. automodule:: sardana.pool.poolmeasurementgroup +.. rubric:: Functions + +.. hlist:: + :columns: 3 + + * :func:`build_measurement_configuration` + .. rubric:: Classes .. hlist:: @@ -18,6 +25,7 @@ * :class:`ChannelConfiguration` * :class:`SynchronizerConfiguration` +.. autofunction:: build_measurement_configuration PoolMeasurementGroup -------------------- diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 5b9fd37eb0..92726a3ad1 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -28,7 +28,7 @@ __all__ = ["PoolMeasurementGroup", "MeasurementConfiguration", "ControllerConfiguration", "ChannelConfiguration", - "SynchronizerConfiguration"] + "SynchronizerConfiguration", "build_measurement_configuration"] __docformat__ = 'restructuredtext' @@ -343,6 +343,30 @@ def __init__(self, element, attrs=None): def build_measurement_configuration(user_elements): + """Create a minimal measurement configuration data structure from the + user_elements list. + + .. highlight:: none + + Minimal configuration data structure:: + + dict with keys: + - 'controllers' : where value is a dict where: + - key: controller's full name + - value: dict with keys: + - 'channels' where value is a dict where: + - key: channel's full name + - value: dict with keys: + - 'index' : where value is the channel's index + + .. highlight:: default + + .. note:: + The build_measurement_configuration function has been included in + Sardana on a provisional basis. Backwards incompatible changes + (up to and including removal of the function) may occur if + deemed necessary by the core developers. + """ user_config = {} external_user_elements = [] user_config["controllers"] = controllers = {} @@ -374,9 +398,8 @@ def build_measurement_configuration(user_elements): class MeasurementConfiguration(object): - """ - .. todo: Reject configuration with errors: - * Controllers with timer and monitor disable + """Configuration of measurement group. + """ DFT_DESC = 'General purpose measurement group' From 28c04d68a6134282c600e27142e5cccf68da62fa Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Thu, 13 Dec 2018 11:03:57 +0100 Subject: [PATCH 392/652] remove unnecessary parameter --- src/sardana/tango/core/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/tango/core/util.py b/src/sardana/tango/core/util.py index 1102a46cb0..43d7f5fcf9 100644 --- a/src/sardana/tango/core/util.py +++ b/src/sardana/tango/core/util.py @@ -921,7 +921,7 @@ def prepare_logstash(args): log_messages.append(msg,) return log_messages - def get_logstash_conf(dev_name, class_name=None): + def get_logstash_conf(dev_name): try: props = db.get_device_property(dev_name, "LogstashHost") host = props["LogstashHost"][0] From 30cb86e3df04aa322cbcf1ba46e01f515edd9231 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 13 Dec 2018 17:34:44 +0100 Subject: [PATCH 393/652] Document measurement configuration --- .../api/sardana/pool/poolmeasurementgroup.rst | 12 ++ src/sardana/pool/poolmeasurementgroup.py | 124 ++++++++++++++++-- 2 files changed, 124 insertions(+), 12 deletions(-) diff --git a/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst b/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst index 5f8a5b12de..4a40633c65 100644 --- a/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst +++ b/doc/source/devel/api/sardana/pool/poolmeasurementgroup.rst @@ -24,6 +24,7 @@ * :class:`ExternalControllerConfiguration` * :class:`ChannelConfiguration` * :class:`SynchronizerConfiguration` + * :class:`MeasurementConfiguration` .. autofunction:: build_measurement_configuration @@ -103,3 +104,14 @@ SynchronizerConfiguration :show-inheritance: :members: :undoc-members: + +MeasurementConfiguration +------------------------ + +.. inheritance-diagram:: MeasurementConfiguration + :parts: 1 + +.. autoclass:: MeasurementConfiguration + :show-inheritance: + :members: + :undoc-members: diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 92726a3ad1..28c522ad0f 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -398,13 +398,29 @@ def build_measurement_configuration(user_elements): class MeasurementConfiguration(object): - """Configuration of measurement group. + """Configuration of a measurement. + Accepts import and export from/to a serializable data structure (based on + dictionaries/lists and strings). + Provides getter methods that facilitate extracting of information e.g. + controllers of different types, master timers/monitors, etc. + + .. note:: + The build_measurement_configuration function has been included in + Sardana on a provisional basis. Backwards incompatible changes + (up to and including removal of the function) may occur if + deemed necessary by the core developers. """ - DFT_DESC = 'General purpose measurement group' + DFT_DESC = 'General purpose measurement configuration' def __init__(self, parent=None): + """Initialize measurement configuration object + + :param parent: (optional) object that this measurement configuration + refers to (usually + :class:`~sardana.pool.poolmeasurementgroup.PoolMeasurementGroup)` + """ self._parent = None if parent is not None: self._parent = weakref.proxy(parent) @@ -428,14 +444,30 @@ def __init__(self, parent=None): self._ctrl_acq_synch = {} self.changed = False - def get_acq_synch_by_channel(self, element): - if isinstance(element, ConfigurationItem): - element = element.element + def get_acq_synch_by_channel(self, channel): + """Return acquisition synchronization configured for this element. + + :param channel: element to look for its acquisition synchronization + :type channel: :class:`~sardana.pool.poolbasechannel.PoolBaseChannel` + or :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` + :return: acquisition synchronization + :rtype: :obj:`~sardana.pool.pooldefs.AcqSynch` + """ + if isinstance(channel, ChannelConfiguration): + element = channel.element return self._channel_acq_synch[element] - def get_acq_synch_by_controller(self, element): - if isinstance(element, ConfigurationItem): - element = element.element + def get_acq_synch_by_controller(self, controller): + """Return acquisition synchronization configured for this controller. + + :param controller: element to look for its acquisition synchronization + :type controller: :class:`~sardana.pool.poolcontroller.PoolController` + or :class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration` + :return: acquisition synchronization + :rtype: :obj:`~sardana.pool.pooldefs.AcqSynch` + """ + if isinstance(controller, ConfigurationItem): + element = controller.element return self._ctrl_acq_synch[element] def _filter_ctrls(self, ctrls, enabled): @@ -449,6 +481,25 @@ def _filter_ctrls(self, ctrls, enabled): return filtered_ctrls def get_timerable_ctrls(self, acq_synch=None, enabled=None): + """Return timerable controllers. + + Allow to filter controllers based on acquisition synchronization or + whether these are enabled/disabled. + + :param acq_synch: (optional) filter controller based on acquisition + synchronization + :type acq_synch: :class:`~sardana.pool.pooldefs.AcqSynch` + :param enabled: (optional) filter controllers whether these are + enabled/disabled: + + - :obj:`True` - enabled only + - :obj:`False` - disabled only + - :obj:`None` - all + + :type enabled: :obj:`bool` or :obj:`None` + :return: timerable controllers that fulfils the filtering criteria + :rtype: list<:class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`> + """ timerable_ctrls = [] if acq_synch is None: for ctrls in self._timerable_ctrls.values(): @@ -463,27 +514,79 @@ def get_timerable_ctrls(self, acq_synch=None, enabled=None): return self._filter_ctrls(timerable_ctrls, enabled) def get_zerod_ctrls(self, enabled=None): + """Return 0D controllers. + + Allow to filter controllers whether these are enabled/disabled. + + :param enabled: (optional) filter controllers whether these are + enabled/disabled: + + - :obj:`True` - enabled only + - :obj:`False` - disabled only + - :obj:`None` - all + + :type enabled: :obj:`bool` or :obj:`None` + :return: 0D controllers that fulfils the filtering criteria + :rtype: list<:class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`> + """ return self._filter_ctrls(self._zerod_ctrls, enabled) def get_synch_ctrls(self, enabled=None): + """Return synchronizer (currently only trigger/gate) controllers. + + Allow to filter controllers whether these are enabled/disabled. + + :param enabled: (optional) filter controllers whether these are + enabled/disabled: + + - :obj:`True` - enabled only + - :obj:`False` - disabled only + - :obj:`None` - all + + :type enabled: :obj:`bool` or :obj:`None` + :return: synchronizer controllers that fulfils the filtering criteria + :rtype: list<:class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`> + """ return self._filter_ctrls(self._synch_ctrls, enabled) def get_master_timer_software(self): + """Return master timer in software acquisition. + + :return: master timer in software acquisition + :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` + """ return self._master_timer_sw def get_master_monitor_software(self): + """Return master monitor in software acquisition. + + :return: master monitor in software acquisition + :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` + """ return self._master_monitor_sw def get_master_timer_software_start(self): + """Return master timer in software start acquisition. + + :return: master timer in software start acquisition + :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` + """ return self._master_monitor_sw_start def get_master_monitor_software_start(self): + """Return master monitor in software start acquisition. + + :return: master monitor in software start acquisition + :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` + """ return self._master_timer_sw_start def get_configuration_for_user(self): + """Return measurement configuration serializable data structure.""" return self._user_confg def set_configuration_from_user(self, cfg, to_fqdn=True): + """Load measurement configuration from serializable data structure.""" user_elements = self._parent.get_user_elements() if len(user_elements) == 0: # All channels were disabled @@ -713,9 +816,7 @@ def set_configuration_from_user(self, cfg, to_fqdn=True): self.changed = True def _fill_channel_data(self, channel, channel_data): - """ - Fills the channel default values for the given channel dictionary - """ + """Fill channel default values for the given channel dictionary""" name = channel.name full_name = channel.full_name source = channel.get_source() @@ -898,7 +999,6 @@ def set_integration_time(self, integration_time, propagate=1): SynchParam.Total: {SynchDomain.Time: total_time}, SynchParam.Repeats: 1}] self.set_synchronization(synch) - self._integration_time = integration_time if not propagate: return self.fire_event(EventType("integration_time", priority=propagate), From 038681f9def5ad26463408a6e9d6412b447177ab Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 13 Dec 2018 17:58:05 +0100 Subject: [PATCH 394/652] Fix flake8 --- src/sardana/pool/poolmeasurementgroup.py | 27 ++++++++++++------------ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 28c522ad0f..c71b0facf7 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -447,28 +447,29 @@ def __init__(self, parent=None): def get_acq_synch_by_channel(self, channel): """Return acquisition synchronization configured for this element. - :param channel: element to look for its acquisition synchronization + :param channel: channel to look for its acquisition synchronization :type channel: :class:`~sardana.pool.poolbasechannel.PoolBaseChannel` or :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` :return: acquisition synchronization :rtype: :obj:`~sardana.pool.pooldefs.AcqSynch` """ if isinstance(channel, ChannelConfiguration): - element = channel.element - return self._channel_acq_synch[element] + channel = channel.element + return self._channel_acq_synch[channel] def get_acq_synch_by_controller(self, controller): """Return acquisition synchronization configured for this controller. - :param controller: element to look for its acquisition synchronization + :param controller: controller to look for its acquisition + synchronization :type controller: :class:`~sardana.pool.poolcontroller.PoolController` or :class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration` :return: acquisition synchronization :rtype: :obj:`~sardana.pool.pooldefs.AcqSynch` """ if isinstance(controller, ConfigurationItem): - element = controller.element - return self._ctrl_acq_synch[element] + controller = controller.element + return self._ctrl_acq_synch[controller] def _filter_ctrls(self, ctrls, enabled): if enabled is None: @@ -498,7 +499,7 @@ def get_timerable_ctrls(self, acq_synch=None, enabled=None): :type enabled: :obj:`bool` or :obj:`None` :return: timerable controllers that fulfils the filtering criteria - :rtype: list<:class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`> + :rtype: list<:class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`> # noqa """ timerable_ctrls = [] if acq_synch is None: @@ -527,7 +528,7 @@ def get_zerod_ctrls(self, enabled=None): :type enabled: :obj:`bool` or :obj:`None` :return: 0D controllers that fulfils the filtering criteria - :rtype: list<:class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`> + :rtype: list<:class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`> # noqa """ return self._filter_ctrls(self._zerod_ctrls, enabled) @@ -545,7 +546,7 @@ def get_synch_ctrls(self, enabled=None): :type enabled: :obj:`bool` or :obj:`None` :return: synchronizer controllers that fulfils the filtering criteria - :rtype: list<:class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`> + :rtype: list<:class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`> # noqa """ return self._filter_ctrls(self._synch_ctrls, enabled) @@ -553,7 +554,7 @@ def get_master_timer_software(self): """Return master timer in software acquisition. :return: master timer in software acquisition - :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` + :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` # noqa """ return self._master_timer_sw @@ -561,7 +562,7 @@ def get_master_monitor_software(self): """Return master monitor in software acquisition. :return: master monitor in software acquisition - :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` + :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` # noqa """ return self._master_monitor_sw @@ -569,7 +570,7 @@ def get_master_timer_software_start(self): """Return master timer in software start acquisition. :return: master timer in software start acquisition - :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` + :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` # noqa """ return self._master_monitor_sw_start @@ -577,7 +578,7 @@ def get_master_monitor_software_start(self): """Return master monitor in software start acquisition. :return: master monitor in software start acquisition - :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` + :rtype: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` # noqa """ return self._master_timer_sw_start From 3568bbfb05d9276e91ed932a8742ce44478993c5 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 13 Dec 2018 18:10:36 +0100 Subject: [PATCH 395/652] Document new methods in PoolMeasurementGroup --- src/sardana/pool/poolmeasurementgroup.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index c71b0facf7..1fa363dd9f 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -1138,6 +1138,12 @@ def set_nb_starts(self, nb_starts, propagate=1): # ------------------------------------------------------------------------- def prepare(self, multiple=1): + """Prepare for measurement. + + Delegate measurement preparation to the acquisition action. + + ..todo:: remove multiple argument + """ value = self._get_value() self._pending_starts = self.nb_starts @@ -1154,6 +1160,13 @@ def prepare(self, multiple=1): **kwargs) def start_acquisition(self, value=None, multiple=1): + """Start measurement. + + Delegate start measurement to the acquisition action. + Provide backwards compatibility for starts without previous prepare. + + ..todo:: remove value and multiple arguments. + """ if self._pending_starts == 0: msg = "starting acquisition without prior preparing is " \ "deprecated since version Jan18." From 540a58bc5447bb64e6595f5498c12821fc23d9f5 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 13 Dec 2018 18:25:56 +0100 Subject: [PATCH 396/652] Add links to SEP18 when documentation is missing --- doc/source/devel/api/api_measurementgroup.rst | 9 ++++++++- .../howto_controllers/howto_countertimercontroller.rst | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/doc/source/devel/api/api_measurementgroup.rst b/doc/source/devel/api/api_measurementgroup.rst index 0085f726db..f1355afbb1 100644 --- a/doc/source/devel/api/api_measurementgroup.rst +++ b/doc/source/devel/api/api_measurementgroup.rst @@ -6,6 +6,12 @@ Measurement group API reference ================================ +.. important:: + Measurement group :term:`API` was extended in SEP18_ but this is still + not documented in this chapter. Please check the said SEP for more + information about the additional :term:`API` or eventual changes. + + The measurement group is a group element. It aggregates other elements like experimental channels (counter/timer, 0D, 1D and 2D or external attribute e.g. Tango_) and trigger/gates. The measurement group role is to execute acquisitions @@ -92,4 +98,5 @@ start acquisition() .. :class:`~sardana.pool.poolmeasurementgroup.PoolMeasurementGroup` .. the measurement group class :term:`API` -.. _Tango: http://www.tango-controls.org \ No newline at end of file +.. _Tango: http://www.tango-controls.org +.. _SEP18: http://www.sardana-controls.org/sep/?SEP18.md \ No newline at end of file diff --git a/doc/source/devel/howto_controllers/howto_countertimercontroller.rst b/doc/source/devel/howto_controllers/howto_countertimercontroller.rst index 8914262808..996b3149ab 100644 --- a/doc/source/devel/howto_controllers/howto_countertimercontroller.rst +++ b/doc/source/devel/howto_controllers/howto_countertimercontroller.rst @@ -6,6 +6,12 @@ How to write a counter/timer controller ======================================= +.. important:: + Counter/timer controller :term:`API` was extended in SEP18_ but this is + still not documented in this chapter. Please check the said SEP for more + information about the additional :term:`API` or eventual changes. + + The basics ---------- @@ -512,3 +518,4 @@ and that there are no gaps in between them. .. _numpy: http://numpy.scipy.org/ .. _SPEC: http://www.certif.com/ .. _EPICS: http://www.aps.anl.gov/epics/ +.. _SEP18: http://www.sardana-controls.org/sep/?SEP18.md From f99c3d0229ecdae4f9faf5095f4423900df1ce40 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 13 Dec 2018 19:06:17 +0100 Subject: [PATCH 397/652] Add TODOs section and Appendixes to SEP18 --- doc/source/sep/SEP18.md | 44 ++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 884a13d75d..796d64a9f3 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -138,23 +138,18 @@ event and end is emitted after the last `passive` event. * Add `PoolAcquisitionSoftwareStart` action that will start channels on software synchronizer `start` event. * `PoolAcquisitionSoftware` will stop channels on software synchronizer -`end` event. TODO: decide if we wait for the acquisition in progress -until it finishes or we stop immediately (finish hook could be used if -we choose to wait). +`end` event. ### Controllers -C/T, 1D and 2D controllers (plugins) API is extended. TODO: Choose between -the following options: - -#### Option 1 +C/T, 1D and 2D controllers (plugins) API is extended as follows: * Add `PrepareOne(axis, value, repeats, latency, starts)` to the Loadable interface * Add extra argument to `LoadOne`, etc. methods of the `Loadable` interface `latency_time`: `LoadOne(axis, value, repeats, latency)` -This option maintains backwards compatibility. +This maintains backwards compatibility. The following examples demonstrates the sequence of calls (only the ones relevant to the SEP18) of one channel (axis 1) involved in the given @@ -217,7 +212,32 @@ LoadOne(1, 0.1, 5, 0.05) StartOne(1) ``` -#### Option 2 +See *Appendix 1* and *Appendix 2* for alternative options which were finally +**not selected** for additional controllers API. + +### Dummy C/T controller +Implement `SoftwareStart` and `HardwareStart` in the +`DummyCounterTimerController` - minimal implementation. + +## Follow-up actions (TODOs) + +* **Stop channels using software trigger/gate on software synchronizer's `end` +event.** This is necessary since we introduced the preparation of channels, +and they may be aware in how many software trigger/gates they will +participates. Sardana does not guarantee to acquire on all triggers/gates, +for example if the previous acquisition is still in progress and a new +trigger/gate should be issued, and some channels may be waiting for them - +this is the case of Lima. + +* **Documentation**: + * Update [Measurement group API reference](https://sardana-controls.org/devel/api/api_measurementgroup.html#sardana-measurementgroup-api) + * Update [How to write a counter/timer controller](https://sardana-controls.org/devel/howto_controllers/howto_countertimercontroller.html) + or any other timerable controller + +* **Remove `StartMultiple` Tango command** and its underneath core +implementation. + +## Appendix 1 - alternative option 2 for extending controllers API * Add extra arguments to `LoadOne`, etc. methods of the `Loadable` interface `latency` and `nr_of_starts` and switch the order of arguments so the API is: @@ -277,7 +297,7 @@ LoadOne(1, 0.1, 0.05, 5, 1) StartOne(1) ``` -#### Option 3 +## Appendix 2 - alternative option 3 for extending controllers API The same as option 2 but maintaining the backwards compatibility in the following way: @@ -285,7 +305,3 @@ following way: controllers implementations (more precisely using the `inspect.getargspec` and counting the number of arguments). This will require much more complicated acquisition actions. - -### Dummy C/T controller -Implement `SoftwareStart` and `HardwareStart` in the -`DummyCounterTimerController` - minimal implementation. From b9cc49101b3a6ecf47acd1b14ed5c268b4d3f343 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Fri, 14 Dec 2018 13:42:23 +0100 Subject: [PATCH 398/652] remove unnecesary parameter also from function call --- src/sardana/tango/core/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/tango/core/util.py b/src/sardana/tango/core/util.py index 43d7f5fcf9..8dbe0d2f04 100644 --- a/src/sardana/tango/core/util.py +++ b/src/sardana/tango/core/util.py @@ -947,7 +947,7 @@ def get_logstash_conf(dev_name): if bin_name in ["Pool", "MacroServer"]: class_name = bin_name dev_name = get_dev_from_class_server(db, class_name, server_name)[0] - host, port, cache = get_logstash_conf(dev_name, class_name) + host, port, cache = get_logstash_conf(dev_name) else: dev_name = get_dev_from_class_server(db, "Pool", server_name)[0] host, port, cache = get_logstash_conf(dev_name) From 65f33dadbf9c5a8d614fe59f1eda4f7c17779852 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 14 Dec 2018 15:53:39 +0100 Subject: [PATCH 399/652] Split get_acq_ctrls to have timerable logic separately --- src/sardana/pool/poolacquisition.py | 114 +++++++++++++++++++--------- 1 file changed, 79 insertions(+), 35 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 2287de313f..f318678bb2 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -71,10 +71,10 @@ def is_value_error(value): return False -def get_acq_ctrls(ctrls, acq_mode=None): +def get_acq_ctrls(ctrls): """Converts configuration controllers into acquisition controllers. - It takes care about converting their internals as well. + Takes care about converting their internals as well. :param ctrls: sequence of configuration controllers objects :type ctrls: sardana.pool.poolmeasurementgroup.ControllerConfiguration @@ -82,6 +82,39 @@ def get_acq_ctrls(ctrls, acq_mode=None): :type acq_mode: :class:`sardana.pool.AcqMode` :return: sequence of acquisition controllers :rtype: :class:`~sardana.pool.poolacquisition.AcqController` + + .. note:: + The get_acq_ctrls function has been included in Sardana + on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. + """ + action_ctrls = [] + for ctrl in ctrls: + action_ctrl = AcqController(ctrl) + action_ctrls.append(action_ctrl) + return action_ctrls + + +def _get_timerable_ctrls(ctrls, acq_mode): + """Converts timerable configuration controllers into acquisition + controllers. + + Take care about converting their internals as well. + Take care about assigning master according to acq_mode. + + :param ctrls: sequence of configuration controllers objects + :type ctrls: sardana.pool.poolmeasurementgroup.ControllerConfiguration + :param acq_mode: acquisition mode (timer/monitor) + :type acq_mode: :class:`sardana.pool.AcqMode` + :return: sequence of acquisition controllers + :rtype: :class:`~sardana.pool.poolacquisition.AcqController` + + .. note:: + The get_timerable_ctrls function has been included in Sardana + on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. """ action_ctrls = [] for ctrl in ctrls: @@ -98,29 +131,31 @@ def get_acq_ctrls(ctrls, acq_mode=None): return action_ctrls -def get_synch_acq_items(ctrls): - ctrls = get_acq_ctrls(ctrls) - return ctrls - +def get_timerable_items(ctrls, master, acq_mode=AcqMode.Timer): + """Converts timerable configuration items into acquisition items. -def get_0d_acq_items(ctrls): - ctrls = get_acq_ctrls(ctrls) - return ctrls + The timerable items are controllers and master. Convert these into + the corresponding acquisition items. + Take care about converting their internals as well. + Take care about assigning master according to acq_mode. -def get_sw_acq_items(ctrls, master, acq_mode=AcqMode.Timer): - ctrls = get_acq_ctrls(ctrls, acq_mode) - # Search master AcqConfigurationItem obj - for ctrl in ctrls: - for channel in ctrl.get_channels(): - if channel.configuration == master: - master = channel - break - return ctrls, master - + :param ctrls: sequence of configuration controllers objects + :type ctrls: :obj:list<:class:`~sardana.pool.poolmeasurementgroup.ControllerConfiguration`> # noqa + :param master: master configuration object + :type master: :class:`~sardana.pool.poolmeasurementgroup.ChannelConfiguration` # noqa + :param acq_mode: acquisition mode (timer/monitor) + :type acq_mode: :class:`sardana.pool.AcqMode` + :return: sequence of acquisition controllers + :rtype: :class:`~sardana.pool.poolacquisition.AcqController` -def get_sw_start_acq_items(ctrls, master, acq_mode=AcqMode.Timer): - ctrls = get_acq_ctrls(ctrls, acq_mode) + .. note:: + The get_timerable_ctrls function has been included in Sardana + on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. + """ + ctrls = _get_timerable_ctrls(ctrls, acq_mode) # Search master AcqConfigurationItem obj for ctrl in ctrls: for channel in ctrl.get_channels(): @@ -130,11 +165,6 @@ def get_sw_start_acq_items(ctrls, master, acq_mode=AcqMode.Timer): return ctrls, master -def get_hw_acq_items(ctrls, acq_mode=AcqMode.Timer): - ctrls = get_acq_ctrls(ctrls, acq_mode) - return ctrls - - class ActionArgs(object): def __init__(self, args, kwargs=None): @@ -145,7 +175,14 @@ def __init__(self, args, kwargs=None): class AcqConfigurationItem(object): - """Wrapper for configuration item that will be used in an action.""" + """Wrapper for configuration item that will be used in an action. + + .. note:: + The AcqConfigurationItem function has been included in Sardana + on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. + """ def __init__(self, configuration, attrs=None): """Constructs action item from a configuration item. @@ -179,7 +216,14 @@ def set_configuration(self, configuration): class AcqController(AcqConfigurationItem): - """Wrapper for controller configuration that will be used in an action.""" + """Wrapper for controller configuration that will be used in an action. + + .. note:: + The AcqController function has been included in Sardana + on a provisional basis. Backwards incompatible changes + (up to and including removal of the class) may occur if + deemed necessary by the core developers. + """ def __init__(self, configuration, attrs=None): """Constructs action controller from a configuration controller. @@ -352,7 +396,7 @@ def prepare(self, config, acq_mode, value, synchronization=None, AcqSynch.HardwareGate] ctrls = config.get_timerable_ctrls(acq_synch=acq_sync_hw, enabled=True) if len(ctrls) > 0: - ctrls_hw = get_hw_acq_items(ctrls, acq_mode) + ctrls_hw = get_acq_ctrls(ctrls, acq_mode) hw_args = (ctrls_hw, value, repetitions, latency) hw_kwargs = {} hw_kwargs.update(kwargs) @@ -367,7 +411,7 @@ def prepare(self, config, acq_mode, value, synchronization=None, elif acq_mode is AcqMode.Monitor: master = config.get_master_monitor_software() - ctrls_sw, master_sw = get_sw_acq_items(ctrls, master, acq_mode) + ctrls_sw, master_sw = get_timerable_items(ctrls, master, acq_mode) sw_args = (ctrls_sw, value, master_sw) sw_kwargs = {'synch': True} @@ -383,9 +427,9 @@ def prepare(self, config, acq_mode, value, synchronization=None, elif acq_mode is AcqMode.Monitor: master = config.get_master_monitor_software_start() - ctrls_sw_start, master_sw_start = get_sw_start_acq_items(ctrls, - master, - acq_mode) + ctrls_sw_start, master_sw_start = get_timerable_items(ctrls, + master, + acq_mode) sw_start_args = (ctrls_sw_start, value, master_sw_start, repetitions, latency) sw_start_kwargs = {'synch': True} @@ -396,7 +440,7 @@ def prepare(self, config, acq_mode, value, synchronization=None, # Prepare 0D controllers ctrls = config.get_zerod_ctrls(enabled=True) if len(ctrls) > 0: - ctrls_acq_0d = get_0d_acq_items(ctrls) + ctrls_acq_0d = get_acq_ctrls(ctrls) zerod_args = (ctrls_acq_0d,) zerod_kwargs = {'synch': True} zerod_kwargs.update(kwargs) @@ -404,7 +448,7 @@ def prepare(self, config, acq_mode, value, synchronization=None, # Prepare synchronizer controllers ctrls = config.get_synch_ctrls(enabled=True) - ctrls_synch = get_synch_acq_items(ctrls) + ctrls_synch = get_acq_ctrls(ctrls) synch_args = (ctrls_synch, synchronization) synch_kwargs = {'moveable': moveable, 'sw_synch_initial_domain': sw_synch_initial_domain} From a0c8a1260dc04e423e6a06535a29178852406a3e Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 14 Dec 2018 15:54:06 +0100 Subject: [PATCH 400/652] Use public API of ConfigurationController class --- src/sardana/pool/poolacquisition.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index f318678bb2..0d484146c6 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -242,12 +242,12 @@ def __init__(self, configuration, attrs=None): self._channels_enabled = [] self._channels_disabled = [] ch_attrs = {'controller': self} - for conf_channel in configuration._channels: + for conf_channel in configuration.get_channels(): action_channel = AcqConfigurationItem(conf_channel, ch_attrs) self._channels.append(action_channel) - if conf_channel in configuration._channels_enabled: + if conf_channel in configuration.get_channels(enabled=True): self._channels_enabled.append(action_channel) - if conf_channel in configuration._channels_disabled: + if conf_channel in configuration.get_channels(enabled=False): self._channels_disabled.append(action_channel) if master is None: continue From 6e0e572fdbd24cd12fafcfdf4cc9a821311d71ac Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 14 Dec 2018 15:54:26 +0100 Subject: [PATCH 401/652] Revert "Allow the dynamic attribute creation on PoolActionItem" This reverts commit d4fceb0da350b7abc8bd193b95e4cc7a0a9dd62f. --- src/sardana/pool/poolaction.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/sardana/pool/poolaction.py b/src/sardana/pool/poolaction.py index 432a9ada9a..2a20c406e3 100644 --- a/src/sardana/pool/poolaction.py +++ b/src/sardana/pool/poolaction.py @@ -52,13 +52,8 @@ class PoolActionItem(object): """The base class for an atomic action item""" - def __init__(self, element, config=None): + def __init__(self, element): self._element = weakref.ref(element) - if config is not None: - self.__dict__.update(config) - - def __getattr__(self, item): - return getattr(self.element, item) def get_element(self): """Returns the element associated with this item""" From 07f28286a87fa04806312a0e5b7a2f6bea908fe1 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Fri, 14 Dec 2018 16:11:27 +0100 Subject: [PATCH 402/652] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed30be3b43..fc6bc91dfe 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ This file follows the formats and conventions from [keepachangelog.com] (#781) - Move pre-scan and post-scan hooks out of `scan_loop` method (#920, #922, #933) +- Logstash handler from python-logstash to python-logstash-async (#895) - Move `ParamParser` to `sardana.util.parser` (#781, #907, #908) ## [2.5.0] 2018-08-10 From 1d5192e566375a8616906667e08326ccabe5d902 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 14 Dec 2018 16:23:24 +0100 Subject: [PATCH 403/652] Fix get_timerable_ctrls --- src/sardana/pool/poolacquisition.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 0d484146c6..483b7fed6a 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -78,8 +78,6 @@ def get_acq_ctrls(ctrls): :param ctrls: sequence of configuration controllers objects :type ctrls: sardana.pool.poolmeasurementgroup.ControllerConfiguration - :param acq_mode: acquisition mode (timer/monitor) - :type acq_mode: :class:`sardana.pool.AcqMode` :return: sequence of acquisition controllers :rtype: :class:`~sardana.pool.poolacquisition.AcqController` @@ -96,7 +94,7 @@ def get_acq_ctrls(ctrls): return action_ctrls -def _get_timerable_ctrls(ctrls, acq_mode): +def get_timerable_ctrls(ctrls, acq_mode): """Converts timerable configuration controllers into acquisition controllers. @@ -155,7 +153,7 @@ def get_timerable_items(ctrls, master, acq_mode=AcqMode.Timer): (up to and including removal of the class) may occur if deemed necessary by the core developers. """ - ctrls = _get_timerable_ctrls(ctrls, acq_mode) + ctrls = get_timerable_ctrls(ctrls, acq_mode) # Search master AcqConfigurationItem obj for ctrl in ctrls: for channel in ctrl.get_channels(): @@ -236,6 +234,7 @@ def __init__(self, configuration, attrs=None): :param attrs: extra attributes to be inserted :type attrs: dict """ + master = None if attrs is not None: master = attrs.get('master') self._channels = [] @@ -396,7 +395,7 @@ def prepare(self, config, acq_mode, value, synchronization=None, AcqSynch.HardwareGate] ctrls = config.get_timerable_ctrls(acq_synch=acq_sync_hw, enabled=True) if len(ctrls) > 0: - ctrls_hw = get_acq_ctrls(ctrls, acq_mode) + ctrls_hw = get_timerable_ctrls(ctrls, acq_mode) hw_args = (ctrls_hw, value, repetitions, latency) hw_kwargs = {} hw_kwargs.update(kwargs) From 06278689563c8e75b40d91ee7415eceb14a0b9e0 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 14 Dec 2018 17:12:13 +0100 Subject: [PATCH 404/652] Fix use of get_acq_ctrls and get_timerable_ctrls in tests --- src/sardana/pool/test/test_acquisition.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index 3e94916862..660291796c 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -32,7 +32,8 @@ from sardana.pool.pooldefs import SynchDomain, SynchParam from sardana.pool.poolsynchronization import PoolSynchronization from sardana.pool.poolacquisition import PoolAcquisitionHardware, \ - PoolAcquisitionSoftware, PoolAcquisitionSoftwareStart, get_acq_ctrls + PoolAcquisitionSoftware, PoolAcquisitionSoftwareStart, \ + get_acq_ctrls, get_timerable_ctrls from sardana.sardanathreadpool import get_thread_pool from sardana.pool.test import createControllerConfiguration, \ createTimerableControllerConfiguration, BasePoolTestCase, FakeElement, \ @@ -165,8 +166,8 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, [ct_1_1]) conf_ct_ctrl_2 = createTimerableControllerConfiguration(ct_ctrl_2, [ct_2_1]) - hw_ctrls = get_acq_ctrls([conf_ct_ctrl_1], acq_mode=AcqMode.Timer) - sw_ctrls = get_acq_ctrls([conf_ct_ctrl_2], acq_mode=AcqMode.Timer) + hw_ctrls = get_timerable_ctrls([conf_ct_ctrl_1], acq_mode=AcqMode.Timer) + sw_ctrls = get_timerable_ctrls([conf_ct_ctrl_2], acq_mode=AcqMode.Timer) sw_master = sw_ctrls[0].master conf_tg_ctrl_1 = createControllerConfiguration(tg_ctrl_1, [tg_1_1]) synch_ctrls = get_acq_ctrls([conf_tg_ctrl_1]) @@ -243,7 +244,7 @@ def acquire(self, integ_time, repetitions, latency_time): conf_ct_ctrl_1 = createTimerableControllerConfiguration(self.ct_ctrl_1, [self.ct_1_1]) - ctrls = get_acq_ctrls([conf_ct_ctrl_1], AcqMode.Timer) + ctrls = get_timerable_ctrls([conf_ct_ctrl_1], AcqMode.Timer) master = ctrls[0].master # creating synchronization action self.synchronization = self.create_action(PoolSynchronization, @@ -293,7 +294,7 @@ def acquire(self, integ_time, repetitions, latency_time): self.ct_ctrl_1.set_ctrl_par("synchronization", AcqSynch.HardwareStart) conf_ct_ctrl_1 = createTimerableControllerConfiguration( self.ct_ctrl_1, [self.ct_1_1]) - ctrls = get_acq_ctrls([conf_ct_ctrl_1], AcqMode.Timer) + ctrls = get_timerable_ctrls([conf_ct_ctrl_1], AcqMode.Timer) conf_tg_ctrl_1 = createControllerConfiguration(self.tg_ctrl_1, [self.tg_1_1]) synch_ctrls = get_acq_ctrls([conf_tg_ctrl_1]) From 38d08b9faacedaffdadb32c9931faec8dff49266 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 14 Dec 2018 17:28:00 +0100 Subject: [PATCH 405/652] Fix flake8 --- src/sardana/pool/test/test_acquisition.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/test/test_acquisition.py b/src/sardana/pool/test/test_acquisition.py index 660291796c..be681a13ab 100644 --- a/src/sardana/pool/test/test_acquisition.py +++ b/src/sardana/pool/test/test_acquisition.py @@ -166,8 +166,10 @@ def continuous_acquisition(self, offset, active_interval, passive_interval, [ct_1_1]) conf_ct_ctrl_2 = createTimerableControllerConfiguration(ct_ctrl_2, [ct_2_1]) - hw_ctrls = get_timerable_ctrls([conf_ct_ctrl_1], acq_mode=AcqMode.Timer) - sw_ctrls = get_timerable_ctrls([conf_ct_ctrl_2], acq_mode=AcqMode.Timer) + hw_ctrls = get_timerable_ctrls([conf_ct_ctrl_1], + acq_mode=AcqMode.Timer) + sw_ctrls = get_timerable_ctrls([conf_ct_ctrl_2], + acq_mode=AcqMode.Timer) sw_master = sw_ctrls[0].master conf_tg_ctrl_1 = createControllerConfiguration(tg_ctrl_1, [tg_1_1]) synch_ctrls = get_acq_ctrls([conf_tg_ctrl_1]) From c47286138604c4bd6379b8f8ceef6c0a151e3d81 Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 17 Dec 2018 09:22:53 +0100 Subject: [PATCH 406/652] Fixing #967 --- CHANGELOG.md | 2 ++ src/sardana/pool/poolacquisition.py | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc6bc91dfe..1c8d9e577f 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ This file follows the formats and conventions from [keepachangelog.com] property) (#984) ### Fixed +- Do not read 1D and 2D experimental channels during software acquisition loop + (#967) - Make `expconf` react on events of environment, measurement groups and their configurations. An event offers an option to reload the whole experiment configuration or keep the local changes. `expconf` started with diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 3d5719ed6c..5445a11e38 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -759,6 +759,9 @@ def __init__(self, main_element, name="AcquisitionSoftware", slaves=None): slaves = () self._slaves = slaves + def get_read_value_loop_ctrls(self): + return self._pool_ctrl_dict_loop + @DebugIt() def start_action(self, *args, **kwargs): """Prepares everything for acquisition and starts it. @@ -782,7 +785,6 @@ def action_loop(self): states, values = {}, {} for element in self._channels: states[element] = None - values[element] = None nap = self._acq_sleep_time nb_states_per_value = self._nb_states_per_value @@ -812,7 +814,7 @@ def action_loop(self): with ActionContext(self): self.raw_read_state_info(ret=states) - self.raw_read_value_loop(ret=values) + self.raw_read_value(ret=values) for acquirable, state_info in states.items(): # first update the element state so that value calculation From 737366c9c0e9132c65bff82ae93f0153b05d344d Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Mon, 17 Dec 2018 15:51:50 +0100 Subject: [PATCH 407/652] (m) Add TODO to prepare for Py3+Qt5 mimeData API should use bytes for I/O when in py3. Add a TODO here and use literal byte arrays for concatenation (no effect in py2). --- src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index 1cf64a959f..d87f4fa154 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -142,11 +142,11 @@ class LabelWidgetDragsDeviceAndAttribute(DefaultLabelWidget): """ Offer richer mime data with taurus-device, taurus-attribute, and plain-text. """ def mouseMoveEvent(self, event): - model = self.taurusValueBuddy().getModelName() + model = self.taurusValueBuddy().getModelName() # TODO: use bytes mimeData = Qt.QMimeData() mimeData.setText(self.text()) attr_name = model - dev_name = model.rpartition('/')[0] + dev_name = model.rpartition(b'/')[0] mimeData.setData(TAURUS_DEV_MIME_TYPE, dev_name) mimeData.setData(TAURUS_ATTR_MIME_TYPE, attr_name) @@ -959,8 +959,8 @@ def mouseMoveEvent(self, event): model = self.taurusValueBuddy().getModelObj() mimeData = Qt.QMimeData() mimeData.setText(self.lbl_alias.text()) - dev_name = model.getFullName() - attr_name = dev_name + '/Position' + dev_name = model.getFullName() # TODO: Use bytes + attr_name = dev_name + b'/Position' mimeData.setData(TAURUS_DEV_MIME_TYPE, dev_name) mimeData.setData(TAURUS_ATTR_MIME_TYPE, attr_name) From 4c94bc0a1ad867863f6bd0dd8b5bd1846d731d2a Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 17 Dec 2018 16:06:02 +0100 Subject: [PATCH 408/652] Fix flake8 --- src/sardana/pool/poolacquisition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 79b93630af..b0f2b1fc98 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -937,7 +937,7 @@ def __init__(self, main_element, name="AcquisitionSoftware", slaves=None): def get_read_value_loop_ctrls(self): return self._pool_ctrl_dict_loop - + def start_action(self, ctrls, value, master, index, acq_sleep_time=None, nb_states_per_value=None, **kwargs): PoolAcquisitionBase.start_action(self, ctrls, value, master, 1, 0, From 9d2893ab96ea5821e8c24b7eecf1e8131aa635b4 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 17 Dec 2018 16:49:03 +0100 Subject: [PATCH 409/652] SEP18 -> ACCEPTED --- doc/source/sep/SEP18.md | 6 +++++- doc/source/sep/index.md | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/source/sep/SEP18.md b/doc/source/sep/SEP18.md index 796d64a9f3..3defa7c21e 100644 --- a/doc/source/sep/SEP18.md +++ b/doc/source/sep/SEP18.md @@ -1,6 +1,6 @@ Title: Extend acquisition and synchronization concepts for SEP2 needs. SEP: 18 - State: CANDIDATE + State: ACCEPTED Reason: New acquisition and synchronization concepts are necessary in order to properly integrate 1D and 2D experimental channels in Sardana (SEP2). @@ -305,3 +305,7 @@ following way: controllers implementations (more precisely using the `inspect.getargspec` and counting the number of arguments). This will require much more complicated acquisition actions. + +## Changes + +- 2018-12-17 [reszelaz][]. CANDIDATE -> ACCEPTED diff --git a/doc/source/sep/index.md b/doc/source/sep/index.md index e03e73f09c..cf2ce181e8 100644 --- a/doc/source/sep/index.md +++ b/doc/source/sep/index.md @@ -26,7 +26,7 @@ Proposals list [SEP13][] | REJECTED (moved to [TEP13][]) | Unified plugins support in Taurus & Sardana [SEP14][] | DRAFT | MSENV taurus schema [SEP15][] | ACCEPTED | Moving Sardana to Github - [SEP18][] | CANDIDATE | Extend acquisition and synchronization + [SEP18][] | ACCEPTED | Extend acquisition and synchronization concepts for SEP2 needs @@ -48,7 +48,7 @@ Proposals list [SEP13]: http://www.sardana-controls.org/sep/?SEP13.md [SEP14]: http://www.sardana-controls.org/sep/?SEP14.md [SEP15]: http://www.sardana-controls.org/sep/?SEP15.md -[SEP18]: https://github.com/reszelaz/sardana/blob/sep18/doc/source/sep/SEP18.md +[SEP18]: http://www.sardana-controls.org/sep/?SEP18.md [TEP3]: http://www.taurus-scada.org/tep/?TEP3.md From add80828d26eef676ad8f6d552657830e72a7844 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Mon, 17 Dec 2018 18:05:01 +0100 Subject: [PATCH 410/652] Add SEP18 to changelog --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c8d9e577f..c5687859ac 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,19 @@ This file follows the formats and conventions from [keepachangelog.com] ## [Unreleased] ### Added +- New acquisition and synchronization concepts (SEP18, #773): + - Preparation of measurement group for a group of acquisitions is mandatory + (`Prepare` Tango command and `prepare` core method; `NbStarts` Tango + attribute and `nb_starts` core attribute; `count`, `count_raw` and + `count_continuous` methods in Taurus extension) + - Preparation of timerable controllers is optional (`PrepareOne` method) + - `SoftwareStart` and `HardwareStart` options in `AcqSynch` enumeration and + `Start` in `AcqSynchType` enumeration (the second one is available in + the `expconf` as synchronization option) + - `start` and `end` events in software synchronizer + - `PoolAcquisitionSoftwareStart` acquisition action + - `SoftwareStart` and `HardwareStart` synchronization in + `DummyCounterTimerController` - Possibility to define macros with optional parameters. These must be the last ones in the definition (#285, #876, #943, #941, #955) - Possibility to pass values of repeat paramters with just one member without @@ -52,6 +65,10 @@ This file follows the formats and conventions from [keepachangelog.com] - Logstash handler from python-logstash to python-logstash-async (#895) - Move `ParamParser` to `sardana.util.parser` (#781, #907, #908) +### Deprecated +- Measurement group start without prior preparation (SEP18, #773) + + ## [2.5.0] 2018-08-10 ### Added From aed8eebe0a140963037633534e7d21627f443e49 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 18 Dec 2018 11:23:12 +0100 Subject: [PATCH 411/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5687859ac..ac6ba9f616 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,8 @@ This file follows the formats and conventions from [keepachangelog.com] ### Deprecated - Measurement group start without prior preparation (SEP18, #773) +- Loadable controller's API: `LoadOne(axis, value, repeats)` + in favor of `LoadOne(axis, value, repeats, latency)` (SEP18, #773) ## [2.5.0] 2018-08-10 From 8d05cafb32756dc4c79543e69376064b9237ad74 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 19 Dec 2018 11:40:04 +0100 Subject: [PATCH 412/652] Document adding new controller libraries to Sardana --- doc/source/users/adding_elements.rst | 18 +++++++++++++++--- src/sardana/macroserver/macros/expert.py | 10 ++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/doc/source/users/adding_elements.rst b/doc/source/users/adding_elements.rst index 2d677d2d45..dc9aff1b4d 100644 --- a/doc/source/users/adding_elements.rst +++ b/doc/source/users/adding_elements.rst @@ -14,9 +14,21 @@ If not, you can :ref:`write the plugin yourself `. Controllers =========== -The controller is a Sardana object that handles the communication with the hardware. -To create the controller you can use :class:`~sardana.macroserver.macros.expert.defctrl` -macro:: +The controller is a Sardana object that handles the communication with the +hardware (physical controller) or provides an abstraction layer (pseudo +controller). + +Before creating the controller instance you need to load the controller +plugin class into the Sardana. To check if it is already loaded use the +:class:`~sardana.macroserver.macros.lists.lsctrl` macro. If it is not, you will +need to configure the :ref:`controller plugin discovery path ` +(``PoolPath`` property) and either restart the Sardana server or call the +:class:`~sardana.macroserver.macros.expert.addctrllib` macro. After that +check again with the list macro if the controller class is present and if +yes let's continue... + +To create a controller instance you can use +:class:`~sardana.macroserver.macros.expert.defctrl` macro:: defctrl diff --git a/src/sardana/macroserver/macros/expert.py b/src/sardana/macroserver/macros/expert.py index d5cd2dc960..2ef69de29f 100644 --- a/src/sardana/macroserver/macros/expert.py +++ b/src/sardana/macroserver/macros/expert.py @@ -25,13 +25,13 @@ from __future__ import print_function -__docformat__ = 'restructuredtext' - __all__ = ["addctrllib", "addmaclib", "commit_ctrllib", "defctrl", "defelem", "defm", "defmeas", "edctrlcls", "edctrllib", "prdef", "relctrlcls", "relctrllib", "rellib", "relmac", "relmaclib", "send2ctrl", "udefctrl", "udefelem", "udefmeas", "sar_info"] +__docformat__ = 'restructuredtext' + import sys import traceback import array @@ -339,6 +339,12 @@ def run(self, ctrl_library): class addctrllib(Macro): """Adds the given controller library code to the pool server filesystem. + + .. note:: Currently this macro does not report eventual errors, + for example Python syntax errors, in the controller plugin + module. So if it silently exits but the controller library is + not correctly loaded please check the server logs for more + information. """ param_def = [["ctrl_library_name", Type.String, None, From 89c6ade307fcc37967ebc5e0f9c465bad87a78b7 Mon Sep 17 00:00:00 2001 From: teresa Date: Wed, 19 Dec 2018 12:37:14 +0100 Subject: [PATCH 413/652] Adding needed attributes and variables --- src/sardana/pool/poolbasechannel.py | 36 +++++++++++++++++- src/sardana/pool/poolcountertimer.py | 32 ++++++++++++++++ src/sardana/pool/poolonedexpchannel.py | 32 ++++++++++++++++ src/sardana/pool/pooltwodexpchannel.py | 32 ++++++++++++++++ src/sardana/tango/pool/CTExpChannel.py | 23 ++++++++++-- src/sardana/tango/pool/OneDExpChannel.py | 17 ++++++++- src/sardana/tango/pool/PoolDevice.py | 28 +++++++++++++- src/sardana/tango/pool/TwoDExpChannel.py | 48 +++++++++++++++--------- 8 files changed, 223 insertions(+), 25 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 9cebdaa2d9..10ce4a6e5d 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -33,7 +33,7 @@ from sardana.sardanaattribute import SardanaAttribute from sardana.sardanabuffer import SardanaBuffer from sardana.pool.poolelement import PoolElement -from sardana.pool.poolacquisition import PoolCTAcquisition +from sardana.pool.poolacquisition import PoolAcquisitionSoftware class ValueBuffer(SardanaBuffer): @@ -68,7 +68,7 @@ class PoolBaseChannel(PoolElement): ValueAttributeClass = Value ValueBufferClass = ValueBuffer - AcquisitionClass = PoolCTAcquisition + AcquisitionClass = PoolAcquisitionSoftware def __init__(self, **kwargs): PoolElement.__init__(self, **kwargs) @@ -79,6 +79,7 @@ def __init__(self, **kwargs): if not self.AcquisitionClass is None: acq_name = "%s.Acquisition" % self._name self.set_action_cache(self.AcquisitionClass(self, name=acq_name)) + self._integration_time = False def has_pseudo_elements(self): """Informs whether this channel forms part of any pseudo element @@ -228,6 +229,37 @@ def _set_value(self, value): value = property(get_value, set_value, doc="channel value") + # -------------------------------------------------------------------------- + # integration time + # -------------------------------------------------------------------------- + + def get_integration_time(self, cache=True, propagate=1): + """Returns the integration time for this object. + + :param cache: not used [default: True] + :type cache: bool + :param propagate: [default: 1] + :type propagate: int + :return: the current integration time + :rtype: bool""" + return self._integration_time + + def set_integration_time(self, integration_time, propagate=1): + self._integration_time = integration_time + if not propagate: + return + if integration_time == self._integration_time: + # current state is equal to last state_event. Skip event + return + self.fire_event(EventType("integration_time", priority=propagate), + integration_time) + + def put_integration_time(self, integration_time): + self._integration_time = integration_time + + integration_time = property(get_integration_time, set_integration_time, + doc="channel integration time") + def extend_value_buffer(self, values, idx=None, propagate=1): """Extend value buffer with new values assigning them consecutive indexes starting with idx. If idx is omitted, then the new values will diff --git a/src/sardana/pool/poolcountertimer.py b/src/sardana/pool/poolcountertimer.py index 8f1fa8a416..f26e2a581d 100644 --- a/src/sardana/pool/poolcountertimer.py +++ b/src/sardana/pool/poolcountertimer.py @@ -38,6 +38,7 @@ class PoolCounterTimer(PoolBaseChannel): def __init__(self, **kwargs): + self._timer = None kwargs['elem_type'] = ElementType.CTExpChannel PoolBaseChannel.__init__(self, **kwargs) @@ -58,3 +59,34 @@ def set_write_value(self, w_value, timestamp=None, propagate=1): int""" self._value.set_write_value(w_value, timestamp=timestamp, propagate=propagate) + + # ------------------------------------------------------------------------- + # timer + # ------------------------------------------------------------------------- + + def get_timer(self, cache=True, propagate=1): + """Returns the integration time for this object. + + :param cache: not used [default: True] + :type cache: bool + :param propagate: [default: 1] + :type propagate: int + :return: the current integration time + :rtype: bool""" + return self._timer + + def set_timer(self, timer, propagate=1): + self._timer = timer + if not propagate: + return + if timer == self._timer: + # current state is equal to last state_event. Skip event + return + self.fire_event(EventType("timer", priority=propagate), + timer) + + def put_timer(self, timer): + self._timer = timers + + timer = property(get_timer, set_timer, + doc="timer for the counter/timer channel") diff --git a/src/sardana/pool/poolonedexpchannel.py b/src/sardana/pool/poolonedexpchannel.py index b40c53e625..4369789f92 100644 --- a/src/sardana/pool/poolonedexpchannel.py +++ b/src/sardana/pool/poolonedexpchannel.py @@ -40,6 +40,7 @@ class Pool1DExpChannel(PoolBaseChannel): def __init__(self, **kwargs): self._data_source = None + self._timer = None kwargs['elem_type'] = ElementType.OneDExpChannel PoolBaseChannel.__init__(self, **kwargs) @@ -66,3 +67,34 @@ def read_data_source(self): data_source = property(get_data_source, doc="source identifier for the 1D data") + + # ------------------------------------------------------------------------- + # timer + # ------------------------------------------------------------------------- + + def get_timer(self, cache=True, propagate=1): + """Returns the integration time for this object. + + :param cache: not used [default: True] + :type cache: bool + :param propagate: [default: 1] + :type propagate: int + :return: the current integration time + :rtype: bool""" + return self._timer + + def set_timer(self, timer, propagate=1): + self._timer = timer + if not propagate: + return + if timer == self._timer: + # current state is equal to last state_event. Skip event + return + self.fire_event(EventType("timer", priority=propagate), + timer) + + def put_timer(self, timer): + self._timer = timers + + timer = property(get_timer, set_timer, + doc="timer for the 1D channel") diff --git a/src/sardana/pool/pooltwodexpchannel.py b/src/sardana/pool/pooltwodexpchannel.py index 416f20f593..ebd19b569e 100644 --- a/src/sardana/pool/pooltwodexpchannel.py +++ b/src/sardana/pool/pooltwodexpchannel.py @@ -40,6 +40,7 @@ class Pool2DExpChannel(PoolBaseChannel): def __init__(self, **kwargs): self._data_source = None + self._timer = None kwargs['elem_type'] = ElementType.TwoDExpChannel PoolBaseChannel.__init__(self, **kwargs) @@ -66,3 +67,34 @@ def read_data_source(self): data_source = property( get_data_source, doc="source identifier for the 2D data") + + # ------------------------------------------------------------------------- + # timer + # ------------------------------------------------------------------------- + + def get_timer(self, cache=True, propagate=1): + """Returns the integration time for this object. + + :param cache: not used [default: True] + :type cache: bool + :param propagate: [default: 1] + :type propagate: int + :return: the current integration time + :rtype: bool""" + return self._timer + + def set_timer(self, timer, propagate=1): + self._timer = timer + if not propagate: + return + if timer == self._timer: + # current state is equal to last state_event. Skip event + return + self.fire_event(EventType("timer", priority=propagate), + timer) + + def put_timer(self, timer): + self._timer = timers + + timer = property(get_timer, set_timer, + doc="timer for the 2D channel") diff --git a/src/sardana/tango/pool/CTExpChannel.py b/src/sardana/tango/pool/CTExpChannel.py index 654a7b296c..9cbb94e604 100644 --- a/src/sardana/tango/pool/CTExpChannel.py +++ b/src/sardana/tango/pool/CTExpChannel.py @@ -33,7 +33,7 @@ import time from PyTango import DevFailed, DevVoid, DevDouble, DevState, AttrQuality, \ - DevString, Except, READ, SCALAR + DevString, Except, READ, SCALAR, READ_WRITE from taurus.core.util.log import DebugIt @@ -215,6 +215,20 @@ def is_Value_allowed(self, req_type): return False return True + def read_Timer(self, attr): + """Reads the timer for this channel. + + :param attr: tango attribute + :type attr: :class:`~PyTango.Attribute`""" + attr.set_value(self.element.timer) + + def write_Timer(self, attr): + """Sets the timer for this channel. + + :param attr: tango attribute + :type attr: :class:`~PyTango.Attribute`""" + self.element.timer = attr.get_write_value() + def Start(self): self.ct.start_acquisition() @@ -235,13 +249,16 @@ class CTExpChannelClass(PoolExpChannelDeviceClass): cmd_list.update(PoolExpChannelDeviceClass.cmd_list) # Attribute definitions - attr_list = {} + attr_list = { + 'Timer': [[DevString, SCALAR, READ_WRITE]] + } attr_list.update(PoolExpChannelDeviceClass.attr_list) - + standard_attr_list = { 'Value': [[DevDouble, SCALAR, READ], {'abs_change': '1.0', }] } + standard_attr_list.update(PoolExpChannelDeviceClass.standard_attr_list) def _get_class_properties(self): diff --git a/src/sardana/tango/pool/OneDExpChannel.py b/src/sardana/tango/pool/OneDExpChannel.py index f4c879f8d6..ee56a2ae08 100644 --- a/src/sardana/tango/pool/OneDExpChannel.py +++ b/src/sardana/tango/pool/OneDExpChannel.py @@ -33,7 +33,7 @@ import time from PyTango import DevFailed, DevVoid, DevString, DevState, AttrQuality, \ - Except, READ, SCALAR + Except, READ, SCALAR, READ_WRITE from taurus.core.util.log import DebugIt @@ -223,6 +223,20 @@ def read_DataSource(self, attr): data_source = "{0}/value".format(full_name) attr.set_value(data_source) + def read_Timer(self, attr): + """Reads the timer for this channel. + + :param attr: tango attribute + :type attr: :class:`~PyTango.Attribute`""" + attr.set_value(self.element.timer) + + def write_Timer(self, attr): + """Sets the timer for this channel. + + :param attr: tango attribute + :type attr: :class:`~PyTango.Attribute`""" + self.element.timer = attr.get_write_value() + def Start(self): self.oned.start_acquisition() @@ -253,6 +267,7 @@ class OneDExpChannelClass(PoolExpChannelDeviceClass): # Attribute definitions attr_list = { 'DataSource': [[DevString, SCALAR, READ]], + 'Timer': [[DevString, SCALAR, READ_WRITE]] } attr_list.update(PoolExpChannelDeviceClass.attr_list) diff --git a/src/sardana/tango/pool/PoolDevice.py b/src/sardana/tango/pool/PoolDevice.py index 436d43d95a..f037a5cccc 100644 --- a/src/sardana/tango/pool/PoolDevice.py +++ b/src/sardana/tango/pool/PoolDevice.py @@ -35,7 +35,7 @@ import time import numpy as np -from PyTango import Util, DevVoid, DevLong64, DevBoolean, DevString, \ +from PyTango import Util, DevVoid, DevLong64, DevBoolean, DevString, DevDouble, \ DevVarStringArray, DispLevel, DevState, SCALAR, SPECTRUM, \ IMAGE, READ_WRITE, READ, AttrData, CmdArgType, DevFailed, seqStr_2_obj, \ Except, ErrSeverity @@ -873,11 +873,35 @@ def read_Data(self, attr): desc, "PoolExpChannelDevice.read_Data", ErrSeverity.WARN) + + def read_IntegrationTime(self, attr): + """Reads the integration time. + + :param attr: tango attribute + :type attr: :class:`~PyTango.Attribute`""" + attr.set_value(self.element.integration_time) + + def write_IntegrationTime(self, attr): + """Sets the integration time. + + :param attr: tango attribute + :type attr: :class:`~PyTango.Attribute`""" + self.element.integration_time = attr.get_write_value() class PoolExpChannelDeviceClass(PoolElementDeviceClass): + #: + #: Sardana device attribute definition + #: + #: .. seealso:: :ref:`server` + #: + attr_list = { + 'IntegrationTime': [[DevDouble, SCALAR, READ_WRITE]] + } + attr_list.update(PoolElementDeviceClass.attr_list) + standard_attr_list = { - 'Data': [[DevString, SCALAR, READ]] # TODO: think about DevEncoded + 'Data': [[DevString, SCALAR, READ]], # TODO: think about DevEncoded } standard_attr_list.update(PoolElementDeviceClass.standard_attr_list) diff --git a/src/sardana/tango/pool/TwoDExpChannel.py b/src/sardana/tango/pool/TwoDExpChannel.py index 8fdd54b29d..a8764b50bf 100644 --- a/src/sardana/tango/pool/TwoDExpChannel.py +++ b/src/sardana/tango/pool/TwoDExpChannel.py @@ -33,7 +33,7 @@ import time from PyTango import DevFailed, DevVoid, DevString, DevState, AttrQuality, \ - Except, READ, SCALAR + Except, READ, SCALAR, READ_WRITE from taurus.core.util.log import DebugIt @@ -42,17 +42,16 @@ from sardana.pool.controller import TwoDController, MaxDimSize, Type from sardana.tango.core.util import to_tango_type_format, exception_str -from sardana.tango.pool.PoolDevice import PoolElementDevice, \ - PoolElementDeviceClass +from sardana.tango.pool.PoolDevice import PoolExpChannelDevice, \ + PoolExpChannelDeviceClass - -class TwoDExpChannel(PoolElementDevice): +class TwoDExpChannel(PoolExpChannelDevice): def __init__(self, dclass, name): - PoolElementDevice.__init__(self, dclass, name) + PoolExpChannelDevice.__init__(self, dclass, name) def init(self, name): - PoolElementDevice.init(self, name) + PoolExpChannelDevice.init(self, name) def get_twod(self): return self.element @@ -64,14 +63,14 @@ def set_twod(self, twod): @DebugIt() def delete_device(self): - PoolElementDevice.delete_device(self) + PoolExpChannelDevice.delete_device(self) twod = self.twod if twod is not None: twod.remove_listener(self.on_twod_changed) @DebugIt() def init_device(self): - PoolElementDevice.init_device(self) + PoolExpChannelDevice.init_device(self) twod = self.twod if twod is None: full_name = self.get_full_name() @@ -147,7 +146,7 @@ def get_dynamic_attributes(self): cache_built = hasattr(self, "_dynamic_attributes_cache") std_attrs, dyn_attrs = \ - PoolElementDevice.get_dynamic_attributes(self) + PoolExpChannelDevice.get_dynamic_attributes(self) if not cache_built: # For value attribute, listen to what the controller says for data @@ -194,6 +193,20 @@ def read_DataSource(self, attr): data_source = "{0}/value".format(full_name) attr.set_value(data_source) + def read_Timer(self, attr): + """Reads the timer for this channel. + + :param attr: tango attribute + :type attr: :class:`~PyTango.Attribute`""" + attr.set_value(self.element.timer) + + def write_Timer(self, attr): + """Sets the timer for this channel. + + :param attr: tango attribute + :type attr: :class:`~PyTango.Attribute`""" + self.element.timer = attr.get_write_value() + def Start(self): self.twod.start_acquisition() @@ -204,7 +217,7 @@ def Start(self): _DFT_VALUE_INFO[Type], DataFormat.TwoD) -class TwoDExpChannelClass(PoolElementDeviceClass): +class TwoDExpChannelClass(PoolExpChannelDeviceClass): # Class Properties class_property_list = { @@ -213,29 +226,30 @@ class TwoDExpChannelClass(PoolElementDeviceClass): # Device Properties device_property_list = { } - device_property_list.update(PoolElementDeviceClass.device_property_list) + device_property_list.update(PoolExpChannelDeviceClass.device_property_list) # Command definitions cmd_list = { 'Start': [[DevVoid, ""], [DevVoid, ""]], } - cmd_list.update(PoolElementDeviceClass.cmd_list) + cmd_list.update(PoolExpChannelDeviceClass.cmd_list) # Attribute definitions attr_list = { 'DataSource': [[DevString, SCALAR, READ]], + 'Timer': [[DevString, SCALAR, READ_WRITE]] } - attr_list.update(PoolElementDeviceClass.attr_list) + attr_list.update(PoolExpChannelDeviceClass.attr_list) standard_attr_list = { 'Value': [[_DFT_VALUE_TYPE, _DFT_VALUE_FORMAT, READ, _DFT_VALUE_MAX_SHAPE[0], _DFT_VALUE_MAX_SHAPE[1]], {'abs_change': '1.0', }], } - standard_attr_list.update(PoolElementDeviceClass.standard_attr_list) + standard_attr_list.update(PoolExpChannelDeviceClass.standard_attr_list) def _get_class_properties(self): - ret = PoolElementDeviceClass._get_class_properties(self) + ret = PoolExpChannelDeviceClass._get_class_properties(self) ret['Description'] = "2D device class" - ret['InheritedFrom'].insert(0, 'PoolElementDevice') + ret['InheritedFrom'].insert(0, 'PoolExpChannelDevice') return ret From 23bf0a2110c101646f07e2e9ea7b46f8959548da Mon Sep 17 00:00:00 2001 From: teresa Date: Thu, 20 Dec 2018 09:17:52 +0100 Subject: [PATCH 414/652] Correcting the integration_time implementation. Starting remove integration_time as action argument --- src/sardana/pool/poolbasechannel.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 10ce4a6e5d..7958c2fc21 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -34,7 +34,7 @@ from sardana.sardanabuffer import SardanaBuffer from sardana.pool.poolelement import PoolElement from sardana.pool.poolacquisition import PoolAcquisitionSoftware - +from sardana.sardanaevent import EventType class ValueBuffer(SardanaBuffer): @@ -245,18 +245,15 @@ def get_integration_time(self, cache=True, propagate=1): return self._integration_time def set_integration_time(self, integration_time, propagate=1): + if integration_time == self._integration_time: + # integration time is not changed. Do nothing + return self._integration_time = integration_time if not propagate: return - if integration_time == self._integration_time: - # current state is equal to last state_event. Skip event - return self.fire_event(EventType("integration_time", priority=propagate), integration_time) - def put_integration_time(self, integration_time): - self._integration_time = integration_time - integration_time = property(get_integration_time, set_integration_time, doc="channel integration time") @@ -310,13 +307,8 @@ def clear_value_buffer(self): val_attr = self._value_buffer val_attr.clear() - def start_acquisition(self, value=None): + def start_acquisition(self): self._aborted = False self._stopped = False - if value is None: - value = self.get_write_value() - if value is None: - raise Exception( - "Invalid integration_time '%s'. Hint set a new value for 'value' first" % value) if not self._simulation_mode: - acq = self.acquisition.run(integ_time=value) + acq = self.acquisition.run(integ_time=self._integration_time) From dda8c51cb36fd33a57752446fbab34b0116e9d9a Mon Sep 17 00:00:00 2001 From: teresa Date: Thu, 20 Dec 2018 09:36:08 +0100 Subject: [PATCH 415/652] Adding PoolTimerableChannel class --- src/sardana/pool/poolbasechannel.py | 34 +++++++++++++++++++++++ src/sardana/pool/poolcountertimer.py | 36 +++---------------------- src/sardana/pool/poolonedexpchannel.py | 37 +++----------------------- src/sardana/pool/pooltwodexpchannel.py | 37 +++----------------------- 4 files changed, 43 insertions(+), 101 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 7958c2fc21..ffe3f5330c 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -312,3 +312,37 @@ def start_acquisition(self): self._stopped = False if not self._simulation_mode: acq = self.acquisition.run(integ_time=self._integration_time) + +class PoolTimerableChannel(PoolBaseChannel): + + def __init__(self, **kwargs): + PoolBaseChannel.__init__(self, **kwargs) + + # ------------------------------------------------------------------------- + # timer + # ------------------------------------------------------------------------- + + def get_timer(self, cache=True, propagate=1): + """Returns the timer for this object. + + :param cache: not used [default: True] + :type cache: bool + :param propagate: [default: 1] + :type propagate: int + :return: the current timer + :rtype: bool""" + return self._timer + + def set_timer(self, timer, propagate=1): + if timer == self._timer: + # timer is not changed. Do nothing + return + self._timer = timer + if not propagate: + return + self.fire_event(EventType("timer", priority=propagate), + timer) + + + timer = property(get_timer, set_timer, + doc="timer for the timerable channel") diff --git a/src/sardana/pool/poolcountertimer.py b/src/sardana/pool/poolcountertimer.py index f26e2a581d..c73b53f7bb 100644 --- a/src/sardana/pool/poolcountertimer.py +++ b/src/sardana/pool/poolcountertimer.py @@ -32,15 +32,15 @@ from sardana import ElementType -from sardana.pool.poolbasechannel import PoolBaseChannel +from sardana.pool.poolbasechannel import PoolTimerableChannel -class PoolCounterTimer(PoolBaseChannel): +class PoolCounterTimer(PoolTimerableChannel): def __init__(self, **kwargs): self._timer = None kwargs['elem_type'] = ElementType.CTExpChannel - PoolBaseChannel.__init__(self, **kwargs) + PoolTimerableChannel.__init__(self, **kwargs) # ------------------------------------------------------------------------- # value @@ -60,33 +60,3 @@ def set_write_value(self, w_value, timestamp=None, propagate=1): self._value.set_write_value(w_value, timestamp=timestamp, propagate=propagate) - # ------------------------------------------------------------------------- - # timer - # ------------------------------------------------------------------------- - - def get_timer(self, cache=True, propagate=1): - """Returns the integration time for this object. - - :param cache: not used [default: True] - :type cache: bool - :param propagate: [default: 1] - :type propagate: int - :return: the current integration time - :rtype: bool""" - return self._timer - - def set_timer(self, timer, propagate=1): - self._timer = timer - if not propagate: - return - if timer == self._timer: - # current state is equal to last state_event. Skip event - return - self.fire_event(EventType("timer", priority=propagate), - timer) - - def put_timer(self, timer): - self._timer = timers - - timer = property(get_timer, set_timer, - doc="timer for the counter/timer channel") diff --git a/src/sardana/pool/poolonedexpchannel.py b/src/sardana/pool/poolonedexpchannel.py index 4369789f92..e715fc4965 100644 --- a/src/sardana/pool/poolonedexpchannel.py +++ b/src/sardana/pool/poolonedexpchannel.py @@ -33,16 +33,16 @@ from sardana import ElementType from sardana.sardanaevent import EventType -from sardana.pool.poolbasechannel import PoolBaseChannel +from sardana.pool.poolbasechannel import PoolTimerableChannel -class Pool1DExpChannel(PoolBaseChannel): +class Pool1DExpChannel(PoolTimerableChannel): def __init__(self, **kwargs): self._data_source = None self._timer = None kwargs['elem_type'] = ElementType.OneDExpChannel - PoolBaseChannel.__init__(self, **kwargs) + PoolTimerableChannel.__init__(self, **kwargs) # ------------------------------------------------------------------------- # data source @@ -67,34 +67,3 @@ def read_data_source(self): data_source = property(get_data_source, doc="source identifier for the 1D data") - - # ------------------------------------------------------------------------- - # timer - # ------------------------------------------------------------------------- - - def get_timer(self, cache=True, propagate=1): - """Returns the integration time for this object. - - :param cache: not used [default: True] - :type cache: bool - :param propagate: [default: 1] - :type propagate: int - :return: the current integration time - :rtype: bool""" - return self._timer - - def set_timer(self, timer, propagate=1): - self._timer = timer - if not propagate: - return - if timer == self._timer: - # current state is equal to last state_event. Skip event - return - self.fire_event(EventType("timer", priority=propagate), - timer) - - def put_timer(self, timer): - self._timer = timers - - timer = property(get_timer, set_timer, - doc="timer for the 1D channel") diff --git a/src/sardana/pool/pooltwodexpchannel.py b/src/sardana/pool/pooltwodexpchannel.py index ebd19b569e..ec39f0ec58 100644 --- a/src/sardana/pool/pooltwodexpchannel.py +++ b/src/sardana/pool/pooltwodexpchannel.py @@ -33,16 +33,16 @@ from sardana import ElementType from sardana.sardanaevent import EventType -from sardana.pool.poolbasechannel import PoolBaseChannel +from sardana.pool.poolbasechannel import PoolTimerableChannel -class Pool2DExpChannel(PoolBaseChannel): +class Pool2DExpChannel(PoolTimerableChannel): def __init__(self, **kwargs): self._data_source = None self._timer = None kwargs['elem_type'] = ElementType.TwoDExpChannel - PoolBaseChannel.__init__(self, **kwargs) + PoolTimerableChannel.__init__(self, **kwargs) # -------------------------------------------------------------------------- # data source @@ -67,34 +67,3 @@ def read_data_source(self): data_source = property( get_data_source, doc="source identifier for the 2D data") - - # ------------------------------------------------------------------------- - # timer - # ------------------------------------------------------------------------- - - def get_timer(self, cache=True, propagate=1): - """Returns the integration time for this object. - - :param cache: not used [default: True] - :type cache: bool - :param propagate: [default: 1] - :type propagate: int - :return: the current integration time - :rtype: bool""" - return self._timer - - def set_timer(self, timer, propagate=1): - self._timer = timer - if not propagate: - return - if timer == self._timer: - # current state is equal to last state_event. Skip event - return - self.fire_event(EventType("timer", priority=propagate), - timer) - - def put_timer(self, timer): - self._timer = timers - - timer = property(get_timer, set_timer, - doc="timer for the 2D channel") From 464aafb228ce899ce8403e59c7d3ebfefa62d0c4 Mon Sep 17 00:00:00 2001 From: teresa Date: Thu, 20 Dec 2018 09:58:00 +0100 Subject: [PATCH 416/652] Adding PoolTimerableDevice class --- src/sardana/tango/pool/CTExpChannel.py | 50 ++++++++---------------- src/sardana/tango/pool/OneDExpChannel.py | 47 ++++++++-------------- src/sardana/tango/pool/PoolDevice.py | 38 ++++++++++++++++++ src/sardana/tango/pool/TwoDExpChannel.py | 45 +++++++-------------- 4 files changed, 86 insertions(+), 94 deletions(-) diff --git a/src/sardana/tango/pool/CTExpChannel.py b/src/sardana/tango/pool/CTExpChannel.py index 9cbb94e604..18d8bb5002 100644 --- a/src/sardana/tango/pool/CTExpChannel.py +++ b/src/sardana/tango/pool/CTExpChannel.py @@ -41,18 +41,18 @@ from sardana.sardanaattribute import SardanaAttribute from sardana.tango.core.util import to_tango_type_format, exception_str -from sardana.tango.pool.PoolDevice import PoolExpChannelDevice, \ - PoolExpChannelDeviceClass +from sardana.tango.pool.PoolDevice import PoolTimerableDevice, \ + PoolTimerableDeviceClass -class CTExpChannel(PoolExpChannelDevice): +class CTExpChannel(PoolTimerableDevice): def __init__(self, dclass, name): - PoolExpChannelDevice.__init__(self, dclass, name) + PoolTimerableDevice.__init__(self, dclass, name) self._first_read_cache = False def init(self, name): - PoolExpChannelDevice.init(self, name) + PoolTimerableDevice.init(self, name) def get_ct(self): return self.element @@ -64,14 +64,14 @@ def set_ct(self, ct): @DebugIt() def delete_device(self): - PoolExpChannelDevice.delete_device(self) + PoolTimerableDevice.delete_device(self) ct = self.ct if ct is not None: ct.remove_listener(self.on_ct_changed) @DebugIt() def init_device(self): - PoolExpChannelDevice.init_device(self) + PoolTimerableDevice.init_device(self) ct = self.ct if ct is None: @@ -159,7 +159,7 @@ def get_dynamic_attributes(self): cache_built = hasattr(self, "_dynamic_attributes_cache") std_attrs, dyn_attrs = \ - PoolExpChannelDevice.get_dynamic_attributes(self) + PoolTimerableDevice.get_dynamic_attributes(self) if not cache_built: # For value attribute, listen to what the controller says for data @@ -172,7 +172,7 @@ def get_dynamic_attributes(self): return std_attrs, dyn_attrs def initialize_dynamic_attributes(self): - attrs = PoolExpChannelDevice.initialize_dynamic_attributes(self) + attrs = PoolTimerableDevice.initialize_dynamic_attributes(self) detect_evts = "value", non_detect_evts = "data", @@ -214,55 +214,39 @@ def is_Value_allowed(self, req_type): if self.get_state() in [DevState.FAULT, DevState.UNKNOWN]: return False return True - - def read_Timer(self, attr): - """Reads the timer for this channel. - - :param attr: tango attribute - :type attr: :class:`~PyTango.Attribute`""" - attr.set_value(self.element.timer) - - def write_Timer(self, attr): - """Sets the timer for this channel. - - :param attr: tango attribute - :type attr: :class:`~PyTango.Attribute`""" - self.element.timer = attr.get_write_value() def Start(self): self.ct.start_acquisition() -class CTExpChannelClass(PoolExpChannelDeviceClass): +class CTExpChannelClass(PoolTimerableDeviceClass): # Class Properties class_property_list = {} # Device Properties device_property_list = {} - device_property_list.update(PoolExpChannelDeviceClass.device_property_list) + device_property_list.update(PoolTimerableDeviceClass.device_property_list) # Command definitions cmd_list = { 'Start': [[DevVoid, ""], [DevVoid, ""]], } - cmd_list.update(PoolExpChannelDeviceClass.cmd_list) + cmd_list.update(PoolTimerableDeviceClass.cmd_list) # Attribute definitions - attr_list = { - 'Timer': [[DevString, SCALAR, READ_WRITE]] - } - attr_list.update(PoolExpChannelDeviceClass.attr_list) + attr_list = {} + attr_list.update(PoolTimerableDeviceClass.attr_list) standard_attr_list = { 'Value': [[DevDouble, SCALAR, READ], {'abs_change': '1.0', }] } - standard_attr_list.update(PoolExpChannelDeviceClass.standard_attr_list) + standard_attr_list.update(PoolTimerableDeviceClass.standard_attr_list) def _get_class_properties(self): - ret = PoolExpChannelDeviceClass._get_class_properties(self) + ret = PoolTimerableDeviceClass._get_class_properties(self) ret['Description'] = "Counter/Timer device class" - ret['InheritedFrom'].insert(0, 'PoolExpChannelDevice') + ret['InheritedFrom'].insert(0, 'PoolTimerableDevice') return ret diff --git a/src/sardana/tango/pool/OneDExpChannel.py b/src/sardana/tango/pool/OneDExpChannel.py index ee56a2ae08..35def07e0f 100644 --- a/src/sardana/tango/pool/OneDExpChannel.py +++ b/src/sardana/tango/pool/OneDExpChannel.py @@ -42,18 +42,18 @@ from sardana.pool.controller import OneDController, MaxDimSize, Type from sardana.tango.core.util import to_tango_type_format, exception_str -from sardana.tango.pool.PoolDevice import PoolExpChannelDevice, \ - PoolExpChannelDeviceClass +from sardana.tango.pool.PoolDevice import PoolTimerableDevice, \ + PoolTimerableDeviceClass -class OneDExpChannel(PoolExpChannelDevice): +class OneDExpChannel(PoolTimerableDevice): def __init__(self, dclass, name): - PoolExpChannelDevice.__init__(self, dclass, name) + PoolTimerableDevice.__init__(self, dclass, name) self._first_read_cache = False def init(self, name): - PoolExpChannelDevice.init(self, name) + PoolTimerableDevice.init(self, name) def get_oned(self): return self.element @@ -65,14 +65,14 @@ def set_oned(self, oned): @DebugIt() def delete_device(self): - PoolExpChannelDevice.delete_device(self) + PoolTimerableDevice.delete_device(self) oned = self.oned if oned is not None: oned.remove_listener(self.on_oned_changed) @DebugIt() def init_device(self): - PoolExpChannelDevice.init_device(self) + PoolTimerableDevice.init_device(self) oned = self.oned if oned is None: full_name = self.get_full_name() @@ -159,7 +159,7 @@ def get_dynamic_attributes(self): cache_built = hasattr(self, "_dynamic_attributes_cache") std_attrs, dyn_attrs = \ - PoolExpChannelDevice.get_dynamic_attributes(self) + PoolTimerableDevice.get_dynamic_attributes(self) if not cache_built: # For value attribute, listen to what the controller says for data @@ -174,7 +174,7 @@ def get_dynamic_attributes(self): return std_attrs, dyn_attrs def initialize_dynamic_attributes(self): - attrs = PoolExpChannelDevice.initialize_dynamic_attributes(self) + attrs = PoolTimerableDevice.initialize_dynamic_attributes(self) non_detect_evts = "data", @@ -223,20 +223,6 @@ def read_DataSource(self, attr): data_source = "{0}/value".format(full_name) attr.set_value(data_source) - def read_Timer(self, attr): - """Reads the timer for this channel. - - :param attr: tango attribute - :type attr: :class:`~PyTango.Attribute`""" - attr.set_value(self.element.timer) - - def write_Timer(self, attr): - """Sets the timer for this channel. - - :param attr: tango attribute - :type attr: :class:`~PyTango.Attribute`""" - self.element.timer = attr.get_write_value() - def Start(self): self.oned.start_acquisition() @@ -247,7 +233,7 @@ def Start(self): _DFT_VALUE_INFO[Type], DataFormat.OneD) -class OneDExpChannelClass(PoolExpChannelDeviceClass): +class OneDExpChannelClass(PoolTimerableDeviceClass): # Class Properties class_property_list = { @@ -256,30 +242,29 @@ class OneDExpChannelClass(PoolExpChannelDeviceClass): # Device Properties device_property_list = { } - device_property_list.update(PoolExpChannelDeviceClass.device_property_list) + device_property_list.update(PoolTimerableDeviceClass.device_property_list) # Command definitions cmd_list = { 'Start': [[DevVoid, ""], [DevVoid, ""]], } - cmd_list.update(PoolExpChannelDeviceClass.cmd_list) + cmd_list.update(PoolTimerableDeviceClass.cmd_list) # Attribute definitions attr_list = { 'DataSource': [[DevString, SCALAR, READ]], - 'Timer': [[DevString, SCALAR, READ_WRITE]] } - attr_list.update(PoolExpChannelDeviceClass.attr_list) + attr_list.update(PoolTimerableDeviceClass.attr_list) standard_attr_list = { 'Value': [[_DFT_VALUE_TYPE, _DFT_VALUE_FORMAT, READ, _DFT_VALUE_MAX_SHAPE[0]], {'abs_change': '1.0', }] } - standard_attr_list.update(PoolExpChannelDeviceClass.standard_attr_list) + standard_attr_list.update(PoolTimerableDeviceClass.standard_attr_list) def _get_class_properties(self): - ret = PoolExpChannelDeviceClass._get_class_properties(self) + ret = PoolTimerableDeviceClass._get_class_properties(self) ret['Description'] = "1D device class" - ret['InheritedFrom'].insert(0, 'PoolExpChannelDevice') + ret['InheritedFrom'].insert(0, 'PoolTimerableDevice') return ret diff --git a/src/sardana/tango/pool/PoolDevice.py b/src/sardana/tango/pool/PoolDevice.py index f037a5cccc..ab940fcc41 100644 --- a/src/sardana/tango/pool/PoolDevice.py +++ b/src/sardana/tango/pool/PoolDevice.py @@ -905,3 +905,41 @@ class PoolExpChannelDeviceClass(PoolElementDeviceClass): 'Data': [[DevString, SCALAR, READ]], # TODO: think about DevEncoded } standard_attr_list.update(PoolElementDeviceClass.standard_attr_list) + +class PoolTimerableDevice(PoolExpChannelDevice): + + def __init__(self, dclass, name): + """Constructor""" + PoolExpChannelDevice.__init__(self, dclass, name) + + + def read_Timer(self, attr): + """Reads the timer for this channel. + + :param attr: tango attribute + :type attr: :class:`~PyTango.Attribute`""" + attr.set_value(self.element.timer) + + def write_Timer(self, attr): + """Sets the timer for this channel. + + :param attr: tango attribute + :type attr: :class:`~PyTango.Attribute`""" + self.element.timer = attr.get_write_value() + +class PoolTimerableDeviceClass(PoolExpChannelDeviceClass): + + #: + #: Sardana device attribute definition + #: + #: .. seealso:: :ref:`server` + #: + + # Attribute definitions + attr_list = { + 'Timer': [[DevString, SCALAR, READ_WRITE]] + } + attr_list.update(PoolExpChannelDeviceClass.attr_list) + + standard_attr_list = {} + standard_attr_list.update(PoolExpChannelDeviceClass.standard_attr_list) diff --git a/src/sardana/tango/pool/TwoDExpChannel.py b/src/sardana/tango/pool/TwoDExpChannel.py index a8764b50bf..abda6f4296 100644 --- a/src/sardana/tango/pool/TwoDExpChannel.py +++ b/src/sardana/tango/pool/TwoDExpChannel.py @@ -42,16 +42,16 @@ from sardana.pool.controller import TwoDController, MaxDimSize, Type from sardana.tango.core.util import to_tango_type_format, exception_str -from sardana.tango.pool.PoolDevice import PoolExpChannelDevice, \ - PoolExpChannelDeviceClass +from sardana.tango.pool.PoolDevice import PoolTimerableDevice, \ + PoolTimerableDeviceClass -class TwoDExpChannel(PoolExpChannelDevice): +class TwoDExpChannel(PoolTimerableDevice): def __init__(self, dclass, name): - PoolExpChannelDevice.__init__(self, dclass, name) + PoolTimerableDevice.__init__(self, dclass, name) def init(self, name): - PoolExpChannelDevice.init(self, name) + PoolTimerableDevice.init(self, name) def get_twod(self): return self.element @@ -63,14 +63,14 @@ def set_twod(self, twod): @DebugIt() def delete_device(self): - PoolExpChannelDevice.delete_device(self) + PoolTimerableDevice.delete_device(self) twod = self.twod if twod is not None: twod.remove_listener(self.on_twod_changed) @DebugIt() def init_device(self): - PoolExpChannelDevice.init_device(self) + PoolTimerableDevice.init_device(self) twod = self.twod if twod is None: full_name = self.get_full_name() @@ -146,7 +146,7 @@ def get_dynamic_attributes(self): cache_built = hasattr(self, "_dynamic_attributes_cache") std_attrs, dyn_attrs = \ - PoolExpChannelDevice.get_dynamic_attributes(self) + PoolTimerableDevice.get_dynamic_attributes(self) if not cache_built: # For value attribute, listen to what the controller says for data @@ -193,20 +193,6 @@ def read_DataSource(self, attr): data_source = "{0}/value".format(full_name) attr.set_value(data_source) - def read_Timer(self, attr): - """Reads the timer for this channel. - - :param attr: tango attribute - :type attr: :class:`~PyTango.Attribute`""" - attr.set_value(self.element.timer) - - def write_Timer(self, attr): - """Sets the timer for this channel. - - :param attr: tango attribute - :type attr: :class:`~PyTango.Attribute`""" - self.element.timer = attr.get_write_value() - def Start(self): self.twod.start_acquisition() @@ -217,7 +203,7 @@ def Start(self): _DFT_VALUE_INFO[Type], DataFormat.TwoD) -class TwoDExpChannelClass(PoolExpChannelDeviceClass): +class TwoDExpChannelClass(PoolTimerableDeviceClass): # Class Properties class_property_list = { @@ -226,30 +212,29 @@ class TwoDExpChannelClass(PoolExpChannelDeviceClass): # Device Properties device_property_list = { } - device_property_list.update(PoolExpChannelDeviceClass.device_property_list) + device_property_list.update(PoolTimerableDeviceClass.device_property_list) # Command definitions cmd_list = { 'Start': [[DevVoid, ""], [DevVoid, ""]], } - cmd_list.update(PoolExpChannelDeviceClass.cmd_list) + cmd_list.update(PoolTimerableDeviceClass.cmd_list) # Attribute definitions attr_list = { 'DataSource': [[DevString, SCALAR, READ]], - 'Timer': [[DevString, SCALAR, READ_WRITE]] } - attr_list.update(PoolExpChannelDeviceClass.attr_list) + attr_list.update(PoolTimerableDeviceClass.attr_list) standard_attr_list = { 'Value': [[_DFT_VALUE_TYPE, _DFT_VALUE_FORMAT, READ, _DFT_VALUE_MAX_SHAPE[0], _DFT_VALUE_MAX_SHAPE[1]], {'abs_change': '1.0', }], } - standard_attr_list.update(PoolExpChannelDeviceClass.standard_attr_list) + standard_attr_list.update(PoolTimerableDeviceClass.standard_attr_list) def _get_class_properties(self): - ret = PoolExpChannelDeviceClass._get_class_properties(self) + ret = PoolTimerableDeviceClass._get_class_properties(self) ret['Description'] = "2D device class" - ret['InheritedFrom'].insert(0, 'PoolExpChannelDevice') + ret['InheritedFrom'].insert(0, 'PoolTimerableDevice') return ret From 69b10edffae65364f041707b774b0a3582f513fb Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 2 Jan 2019 16:26:42 +0100 Subject: [PATCH 417/652] Make count_raw return acquisition results SEP18 redefined MeasurementGroup Taurus extension methods. count is composed from preparation and acquisition and count_raw is just acquisition. The later one must however return the acquisition results (states and values). Do it. --- src/sardana/taurus/core/tango/sardana/pool.py | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 285e8bafe5..ac6170cde6 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1808,6 +1808,19 @@ def _start(self, *args, **kwargs): def prepare(self): self.command_inout("Prepare") + def count_raw(self, start_time=None): + PoolElement.go(self) + if start_time is None: + start_time = time.time() + state = self.getStateEG().readValue() + if state == Fault: + msg = "Measurement group ended acquisition with Fault state" + raise Exception(msg) + values = self.getValues() + ret = state, values + self._total_go_time = time.time() - start_time + return ret + def go(self, *args, **kwargs): start_time = time.time() cfg = self.getConfiguration() @@ -1819,15 +1832,7 @@ def go(self, *args, **kwargs): self.setMoveable(None) self.setNbStarts(1) self.prepare() - self.count_raw(self) - state = self.getStateEG().readValue() - if state == Fault: - msg = "Measurement group ended acquisition with Fault state" - raise Exception(msg) - values = self.getValues() - ret = state, values - self._total_go_time = time.time() - start_time - return ret + return self.count_raw(start_time) def count_continuous(self, synchronization, value_buffer_cb=None): """Execute measurement process according to the given synchronization @@ -1869,7 +1874,6 @@ class on a provisional basis. Backwards incompatible changes startCount = PoolElement.start waitCount = PoolElement.waitFinish count = go - count_raw = PoolElement.go stopCount = PoolElement.abort stop = PoolElement.stop From b1396dd164d1969269c6e6ddeccddbbd82e4dfc8 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 2 Jan 2019 16:30:35 +0100 Subject: [PATCH 418/652] SScan: count or count_raw depending if scan is deterministic SEP18 made deterministic scans to prepare the measurement group and then execute count_raw per each scan point. This was accidentally forgotten in the SEP18 implementation. count or count_raw in each scan point depending whether the scan is deterministic or not. --- src/sardana/macroserver/scan/gscan.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) mode change 100644 => 100755 src/sardana/macroserver/scan/gscan.py diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py old mode 100644 new mode 100755 index bf464f4c8f..b9e9214df6 --- a/src/sardana/macroserver/scan/gscan.py +++ b/src/sardana/macroserver/scan/gscan.py @@ -1006,6 +1006,7 @@ def scan_loop(self): macro = self.macro scream = False + self._deterministic_scan = False if hasattr(macro, "nr_points"): nr_points = float(macro.nr_points) if hasattr(macro, "integ_time"): @@ -1013,6 +1014,7 @@ def scan_loop(self): self.measurement_group.putIntegrationTime(integ_time) self.measurement_group.setNbStarts(nr_points) self.measurement_group.prepare() + self._deterministic_scan = True scream = True else: yield 0.0 @@ -1097,7 +1099,10 @@ def stepUp(self, n, step, lstep): integ_time = step['integ_time'] # Acquire data self.debug("[START] acquisition") - state, data_line = mg.count(integ_time) + if self._deterministic_scan: + state, data_line = mg.count_raw() + else: + state, data_line = mg.count(integ_time) for ec in self._extra_columns: data_line[ec.getName()] = ec.read() self.debug("[ END ] acquisition") From 05677c6d7eef1aa824bc3974fb3978fa1e2d15f6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 2 Jan 2019 17:24:03 +0100 Subject: [PATCH 419/652] Remove protection against unprepared acquisitions Unprepared acquisitions are protected on the measurement group with a proper counter of starts, etc. The protection on the acquisition class is not fully functional so it is better to remove it. Ideally the protection could be moved from the measurement group to to the acquisition. --- src/sardana/pool/poolacquisition.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index b0f2b1fc98..825e1e663c 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -288,7 +288,6 @@ def __init__(self, main_element, name="Acquisition"): self._0d_acq_args = None self._hw_acq_args = None self._synch_args = None - self._prepared = False self._sw_acq = PoolAcquisitionSoftware(main_element, name=swname) self._sw_start_acq = PoolAcquisitionSoftwareStart( main_element, name=sw_start_name) @@ -368,7 +367,6 @@ def prepare(self, config, acq_mode, value, synchronization=None, self._0d_acq_args = None self._hw_acq_args = None self._synch_args = None - self._prepared = False ctrls_hw = [] ctrls_sw = [] ctrls_sw_start = [] @@ -481,7 +479,6 @@ def prepare(self, config, acq_mode, value, synchronization=None, repetitions = 1 self._prepare_ctrls(ctrls_sw, value, repetitions, latency, nb_starts) - self._prepared = True @staticmethod def _prepare_ctrls(ctrls, value, repetitions, latency, nb_starts): @@ -504,9 +501,6 @@ def is_running(self): def run(self, *args, **kwargs): """Runs acquisition according to previous preparation.""" - if not self._prepared: - raise RuntimeError('You must call first "prepare" method.') - if self._hw_acq_args is not None: self._hw_acq.run(*self._hw_acq_args.args, **self._hw_acq_args.kwargs) @@ -520,8 +514,6 @@ def run(self, *args, **kwargs): self._synch.run(*self._synch_args.args, **self._synch_args.kwargs) - self._prepared = False - def _get_action_for_element(self, element): elem_type = element.get_type() if elem_type in TYPE_TIMERABLE_ELEMENTS: From f0bbdaf57f87e888c0f14db6bcc0b6c15e094a0a Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 4 Jan 2019 09:35:18 +0100 Subject: [PATCH 420/652] Setting Timer to memorized --- src/sardana/tango/pool/PoolDevice.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/tango/pool/PoolDevice.py b/src/sardana/tango/pool/PoolDevice.py index ab940fcc41..1ae4c42676 100644 --- a/src/sardana/tango/pool/PoolDevice.py +++ b/src/sardana/tango/pool/PoolDevice.py @@ -937,7 +937,8 @@ class PoolTimerableDeviceClass(PoolExpChannelDeviceClass): # Attribute definitions attr_list = { - 'Timer': [[DevString, SCALAR, READ_WRITE]] + 'Timer': [[DevString, SCALAR, READ_WRITE], + {'Memorized': "true", }] } attr_list.update(PoolExpChannelDeviceClass.attr_list) From dc4295e80f85c5b2e9961c6ec29ba2d7d2bbcc55 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 4 Jan 2019 13:06:38 +0100 Subject: [PATCH 421/652] In development: implementing start acquisition --- src/sardana/pool/poolbasechannel.py | 46 +++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index ffe3f5330c..9b46fea47f 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -33,9 +33,12 @@ from sardana.sardanaattribute import SardanaAttribute from sardana.sardanabuffer import SardanaBuffer from sardana.pool.poolelement import PoolElement -from sardana.pool.poolacquisition import PoolAcquisitionSoftware +from sardana.pool.poolacquisition import PoolAcquisitionSoftware, get_timerable_ctrls, AcqController +from sardana.pool.poolmeasurementgroup import TimerableControllerConfiguration, ChannelConfiguration, ControllerConfiguration from sardana.sardanaevent import EventType +from sardana.pool import AcqSynch, AcqMode + class ValueBuffer(SardanaBuffer): def is_value_required(self, idx): @@ -80,6 +83,8 @@ def __init__(self, **kwargs): acq_name = "%s.Acquisition" % self._name self.set_action_cache(self.AcquisitionClass(self, name=acq_name)) self._integration_time = False + self._timer = None + self.ctrls = None def has_pseudo_elements(self): """Informs whether this channel forms part of any pseudo element @@ -311,8 +316,37 @@ def start_acquisition(self): self._aborted = False self._stopped = False if not self._simulation_mode: - acq = self.acquisition.run(integ_time=self._integration_time) + if self.ctrls is None: + self.create_config() + acq = self.acquisition.run(self.ctrls, self.integration_time, self.master, None) + def create_config(self): + + ctrl = self.get_controller() + ctrl.set_ctrl_par("synchronization", + AcqSynch.SoftwareTrigger) + + self.conf_ctrl = ControllerConfiguration(ctrl) + # self has to be used. If not it is removed + self.conf_channel = ChannelConfiguration(self) + self.conf_ctrl.add_channel(self.conf_channel) + channel = self.conf_ctrl.get_channels(enabled=True)[0] + if self.timer == "__self": + self.conf_ctrl.timer = channel + else: + self.conf_timer = ChannelConfiguration(self.pool.get_element_by_name(self.timer)) + self.conf_ctrl.add_channel(self.conf_timer) + ctimer = self.conf_ctrl.get_channels(enabled=True)[1] + self.conf_ctrl.timer = ctimer + + self.conf_ctrl.monitor = channel + self.ctrls = get_timerable_ctrls([self.conf_ctrl], AcqMode.Timer) + self.master = self.ctrls[0].master + comp_self = "__self" + if self.timer != "__self": + self.acquisition.add_element(self.pool.get_element_by_name(self.timer)) + + class PoolTimerableChannel(PoolBaseChannel): def __init__(self, **kwargs): @@ -334,10 +368,18 @@ def get_timer(self, cache=True, propagate=1): return self._timer def set_timer(self, timer, propagate=1): + if timer == self._timer: # timer is not changed. Do nothing return + + if self._timer is not None and self._timer != "__self": + self.acquisition.remove_element(self.pool.get_element_by_name(self._timer)) + self._timer = timer + + self.create_config() + if not propagate: return self.fire_event(EventType("timer", priority=propagate), From 6d6cd1178b8d42863d08c16e60183a258ae58b97 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 4 Jan 2019 13:25:54 +0100 Subject: [PATCH 422/652] Converting str(None) to None in Timer Tango attribute of timerables --- src/sardana/tango/pool/PoolDevice.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sardana/tango/pool/PoolDevice.py b/src/sardana/tango/pool/PoolDevice.py index 1ae4c42676..04c9eb0538 100644 --- a/src/sardana/tango/pool/PoolDevice.py +++ b/src/sardana/tango/pool/PoolDevice.py @@ -918,14 +918,20 @@ def read_Timer(self, attr): :param attr: tango attribute :type attr: :class:`~PyTango.Attribute`""" - attr.set_value(self.element.timer) + timer = self.element.timer + if timer is None: + timer = 'None' + attr.set_value(timer) def write_Timer(self, attr): """Sets the timer for this channel. :param attr: tango attribute :type attr: :class:`~PyTango.Attribute`""" - self.element.timer = attr.get_write_value() + timer = attr.get_write_value() + if timer == 'None': + timer = None + self.element.timer = timer class PoolTimerableDeviceClass(PoolExpChannelDeviceClass): From 802fff7c3f0cb0992a0114ed6c8761ccf6124cc5 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 4 Jan 2019 14:12:19 +0100 Subject: [PATCH 423/652] Handling None case --- src/sardana/pool/poolbasechannel.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 9b46fea47f..606b9f5902 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -316,12 +316,16 @@ def start_acquisition(self): self._aborted = False self._stopped = False if not self._simulation_mode: - if self.ctrls is None: - self.create_config() - acq = self.acquisition.run(self.ctrls, self.integration_time, self.master, None) + if self._timer is not None: + if self.ctrls is None: + self.create_config() + acq = self.acquisition.run(self.ctrls, self.integration_time, self.master, None) def create_config(self): - + + if self._timer is None: + return + ctrl = self.get_controller() ctrl.set_ctrl_par("synchronization", AcqSynch.SoftwareTrigger) @@ -368,16 +372,25 @@ def get_timer(self, cache=True, propagate=1): return self._timer def set_timer(self, timer, propagate=1): - + if timer == self._timer: # timer is not changed. Do nothing return + if timer is not None and timer != "__self": + try: + self.acquisition.remove_element(self.pool.get_element_by_name(timer)) + except: # The new timer does not belong to action + pass + if self._timer is not None and self._timer != "__self": - self.acquisition.remove_element(self.pool.get_element_by_name(self._timer)) + try: + self.acquisition.remove_element(self.pool.get_element_by_name(timer)) + except: # Action does not contain + pass self._timer = timer - + self.create_config() if not propagate: From e0606644926f5a980ad5e83db3349f787627e5e9 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 4 Jan 2019 14:15:54 +0100 Subject: [PATCH 424/652] Handling None case --- src/sardana/pool/poolbasechannel.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 606b9f5902..0422743db6 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -395,6 +395,10 @@ def set_timer(self, timer, propagate=1): if not propagate: return + + if timer is None: + timer = 'None' + self.fire_event(EventType("timer", priority=propagate), timer) From e97a816a107d8b4cb097dab845ec92eda25e38e0 Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 7 Jan 2019 11:05:28 +0100 Subject: [PATCH 425/652] Implementing default axis --- src/sardana/pool/poolbasechannel.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 0422743db6..b6045a91af 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -338,7 +338,10 @@ def create_config(self): if self.timer == "__self": self.conf_ctrl.timer = channel else: - self.conf_timer = ChannelConfiguration(self.pool.get_element_by_name(self.timer)) + if self.timer == "__default": + self.conf_timer = ChannelConfiguration(self.pool.get_element_by_axis(self.default_axis)) + else: + self.conf_timer = ChannelConfiguration(self.pool.get_element_by_name(self.timer)) self.conf_ctrl.add_channel(self.conf_timer) ctimer = self.conf_ctrl.get_channels(enabled=True)[1] self.conf_ctrl.timer = ctimer @@ -348,7 +351,10 @@ def create_config(self): self.master = self.ctrls[0].master comp_self = "__self" if self.timer != "__self": - self.acquisition.add_element(self.pool.get_element_by_name(self.timer)) + if self.timer == "__default": + self.acquisition.add_element(self.pool.get_element_by_axis(self.default_axis)) + else: + self.acquisition.add_element(self.pool.get_element_by_name(self.timer)) class PoolTimerableChannel(PoolBaseChannel): @@ -377,17 +383,22 @@ def set_timer(self, timer, propagate=1): # timer is not changed. Do nothing return + if timer == "__default": + try: + ctrl = self.get_controller() + self.default_axis = ctrl.defaut_axis + except: + raise ValueError("Not default axis in controller") + return + if timer is not None and timer != "__self": try: - self.acquisition.remove_element(self.pool.get_element_by_name(timer)) + if timer != "__default": + self.acquisition.remove_element(self.pool.get_element_by_name(timer)) + else: + self.acquisition.remove_element(self.pool.get_element_by_axis(default_axis)) except: # The new timer does not belong to action pass - - if self._timer is not None and self._timer != "__self": - try: - self.acquisition.remove_element(self.pool.get_element_by_name(timer)) - except: # Action does not contain - pass self._timer = timer From e66aefb6b2f9619e2cc0190a235233c652f5e560 Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 7 Jan 2019 12:28:19 +0100 Subject: [PATCH 426/652] Setting Moveable to None if str(None) is written --- src/sardana/pool/poolmeasurementgroup.py | 11 ++++++++--- src/sardana/tango/pool/MeasurementGroup.py | 5 ++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 1fa363dd9f..ffa27cfe25 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -1070,12 +1070,17 @@ def get_moveable(self): def set_moveable(self, moveable, propagate=1, to_fqdn=True): self._moveable = moveable - if self._moveable != 'None' and self._moveable is not None: + if self._moveable is not None: if to_fqdn: moveable = _to_fqdn(moveable, logger=self) self._moveable_obj = self.pool.get_element_by_full_name(moveable) - self.fire_event(EventType("moveable", priority=propagate), - moveable) + + self.fire_event(EventType("moveable", priority=propagate), + moveable) + else: + self.fire_event(EventType("moveable", priority=propagate), + 'None') + moveable = property(get_moveable, set_moveable, doc="moveable source used in synchronization") diff --git a/src/sardana/tango/pool/MeasurementGroup.py b/src/sardana/tango/pool/MeasurementGroup.py index f9c449067b..d11deab01d 100644 --- a/src/sardana/tango/pool/MeasurementGroup.py +++ b/src/sardana/tango/pool/MeasurementGroup.py @@ -236,7 +236,10 @@ def read_Moveable(self, attr): attr.set_value(moveable) def write_Moveable(self, attr): - self.measurement_group.moveable = attr.get_write_value() + moveable = attr.get_write_value() + if moveable == 'None': + moveable = None + self.measurement_group.moveable = moveable def read_Synchronization(self, attr): synchronization = self.measurement_group.synchronization From 6285cfb8a8519f4d673aef6a62ba072342ccca23 Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 7 Jan 2019 12:53:42 +0100 Subject: [PATCH 427/652] Cleanup --- src/sardana/pool/poolmeasurementgroup.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index ffa27cfe25..bd7f4c842c 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -1074,12 +1074,11 @@ def set_moveable(self, moveable, propagate=1, to_fqdn=True): if to_fqdn: moveable = _to_fqdn(moveable, logger=self) self._moveable_obj = self.pool.get_element_by_full_name(moveable) - - self.fire_event(EventType("moveable", priority=propagate), - moveable) - else: - self.fire_event(EventType("moveable", priority=propagate), - 'None') + + if moveable is None: + moveable = 'None' + self.fire_event(EventType`("moveable", priority=propagate), + moveable) moveable = property(get_moveable, set_moveable, From ec4ad5e1479a0cee91b24b33e47d17f97f92b4b2 Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 7 Jan 2019 13:32:59 +0100 Subject: [PATCH 428/652] Cleanup --- src/sardana/pool/poolmeasurementgroup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index bd7f4c842c..0dd816b1aa 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -1077,7 +1077,7 @@ def set_moveable(self, moveable, propagate=1, to_fqdn=True): if moveable is None: moveable = 'None' - self.fire_event(EventType`("moveable", priority=propagate), + self.fire_event(EventType("moveable", priority=propagate), moveable) From 0bdd996b1822a347631a0378c92be987ec411301 Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 7 Jan 2019 13:35:16 +0100 Subject: [PATCH 429/652] PosFormat supported by wu --- src/sardana/macroserver/macros/standard.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index d9463e8570..84aa0c6318 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -158,6 +158,7 @@ def run(self, motor_list): motor_names = [] motor_pos = [] motor_list = sorted(motor_list) + pos_format = self.getViewOption(ViewOption.PosFormat) for motor in motor_list: name = motor.getName() motor_names.append([name]) @@ -168,6 +169,8 @@ def run(self, motor_list): motor_width = max(motor_width, len(name)) fmt = '%c*.%df' % ('%', motor_width - 5) + if pos_format > -1: + fmt = '%c*.%df' % ('%', int(pos_format)) table = Table(motor_pos, elem_fmt=[fmt], col_head_str=motor_names, col_head_width=motor_width, From abc94ddaa3070ce8662d046ee406822c2f2f3eeb Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 8 Jan 2019 10:56:53 +0100 Subject: [PATCH 430/652] Fix AcqSynchType enumeration Taurus enumerations must be defined as objects not classes. Fix it by creating an instance of the Enumeration instead of inheriting of Enumeration. Also move the documentation from inline members documentation to the object's docstring. --- src/sardana/pool/pooldefs.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sardana/pool/pooldefs.py b/src/sardana/pool/pooldefs.py index edb5f21ace..565fb3235a 100644 --- a/src/sardana/pool/pooldefs.py +++ b/src/sardana/pool/pooldefs.py @@ -111,21 +111,22 @@ class SynchParam(SynchEnum): Initial = 4 -class AcqSynchType(Enumeration): +AcqSynchType = Enumeration("AcqSynchType", ["Trigger", "Gate", "Start"]) +AcqSynchType.__doc__ = \ """Enumeration of synchronization types. + Options: + + - Trigger - Start each acquisition (experimental channel will decide on + itself when to end, based on integration time / monitor count) + - Gate - Start and end each acquisition + - Start - Start only the first acquisition (experimental channel will + drive the acquisition based on integration time / monitor count, latency + time and number of repetitions) + .. todo:: convert to python enums, but having in mind problems with JSON serialization: https://bugs.python.org/issue18264 """ - #: Start each acquisition (experimental channel will decide on - #: itself when to end - based on integration time / monitor count) - Trigger = 0 - #: Start and end each acquisition - Gate = 1 - #: Start only the first acquisition (experimental channel will drive - #: the acquisition based on integration time / monitor count, latency - #: time and number of repetitions) - Start = 2 class AcqSynch(Enumeration): From e97e510a173cef273d59915c80e1d22a08cf7d2b Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 8 Jan 2019 11:16:34 +0100 Subject: [PATCH 431/652] Migrate AcqSynch from taurus Enumeration to IntEnum AcqSynch were not correctly created as Taurus enumerations (Enumeration should be instantiated and not subclassed). Furthermore this was marked as TODO. Change AcqSynch to be IntEnum. --- src/sardana/pool/pooldefs.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/pooldefs.py b/src/sardana/pool/pooldefs.py index 565fb3235a..afb3092ada 100644 --- a/src/sardana/pool/pooldefs.py +++ b/src/sardana/pool/pooldefs.py @@ -129,17 +129,14 @@ class SynchParam(SynchEnum): """ -class AcqSynch(Enumeration): +class AcqSynch(IntEnum): """Enumeration of synchronization options. Uses software/hardware naming to refer to internal (software synchronizer) or external (hardware synchronization device) - synchronization modes. See :class:`~sardana.pool.pooldefs.AcqSynchType` + synchronization modes. See :obj:`~sardana.pool.pooldefs.AcqSynchType` to get more details about the synchronization type e.g. trigger, gate or start. - - .. todo:: convert to python enums, but having in mind problems with - JSON serialization: https://bugs.python.org/issue18264 """ #: Internal (software) trigger SoftwareTrigger = 0 From bbf29f4dc190801c080a85aae57d5e75926ad0be Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 8 Jan 2019 11:20:42 +0100 Subject: [PATCH 432/652] Fix documentation of AcqSynchType Now AcqSynchType is a data (object) and not a class. Adapt the documentation. --- doc/source/devel/api/sardana/pool/pooldefs.rst | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/doc/source/devel/api/sardana/pool/pooldefs.rst b/doc/source/devel/api/sardana/pool/pooldefs.rst index 97bd25699c..8f810f4b3b 100644 --- a/doc/source/devel/api/sardana/pool/pooldefs.rst +++ b/doc/source/devel/api/sardana/pool/pooldefs.rst @@ -9,13 +9,13 @@ .. autodata:: sardana.pool.pooldefs.ControllerAPI -.. rubric:: Classes +.. rubric:: Enumerations .. hlist:: :columns: 3 * :class:`~AcqSynch` - * :class:`~AcqSynchType` + * :data:`~AcqSynchType` * :class:`~SynchParam` * :class:`~SynchDomain` @@ -34,13 +34,7 @@ AcqSynch AcqSynchType ------------ -.. inheritance-diagram:: AcqSynchType - :parts: 1 - -.. autoclass:: AcqSynchType - :show-inheritance: - :members: - :undoc-members: +.. autodata:: AcqSynchType SynchParam From 83afb803c5799a8f75b9c2dca5c5cf9c4029a00f Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 8 Jan 2019 19:19:01 +0100 Subject: [PATCH 433/652] Fix measurement group configuration Remove unfinished implementation of feeling data_type, shape, nexus_path and data_units on the server side and rely, as it was done prior to SEP18, that these information will be filled by the Taurus extension. --- src/sardana/pool/poolmeasurementgroup.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 1fa363dd9f..f529263f0a 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -858,11 +858,8 @@ def _fill_channel_data(self, channel, channel_data): channel_data['conditioning'] = channel_data.get('conditioning', '') channel_data['normalization'] = channel_data.get('normalization', Normalization.No) - # TODO use real values - channel_data['data_type'] = channel_data.get('data_type', 'float64') - channel_data['data_units'] = channel_data.get('data_units', 'No unit') - channel_data['nexus_path'] = channel_data.get('nexus_path', '') - channel_data['shape'] = channel_data.get('shape', []) + # TODO: think of filling other keys: data_type, data_units, nexus_path + # shape here instead of feeling them on the Taurus extension level if ctype != ElementType.External: ctrl_name = channel.controller.full_name From 12c5722fc9af4221401603e2f94b6f8f94775fb8 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 9 Jan 2019 11:20:40 +0100 Subject: [PATCH 434/652] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac6ba9f616..93fb2f49f6 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ This file follows the formats and conventions from [keepachangelog.com] code are coherent (#936) - Macro/controller module description when module does not have a docstring (#945) +- Make `wu` macro respect view options (#1000, #1002) - Make cleanup (remove configuration) if spock profile creation was interrupted or failed (#791, #793) - Spock considers passing supernumerary parameters as errors (#438, #781) From 991d23932d3825834a250f14eba4a2f55c7e8c0d Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Wed, 9 Jan 2019 12:11:36 +0100 Subject: [PATCH 435/652] Use file dialogs from compat module Change all occurrences of QFileDialog.get{Open,Save}FileName{,s} by their equivalents from the taurus.external.qt.compat module in order to be py2+py3 compatible --- .../taurus/qt/qtgui/extra_macroexecutor/macroeditor.py | 6 +++--- .../macroparameterseditor/parameditors.py | 4 ++-- .../sequenceeditor/sequenceeditor.py | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py index 85481add09..35e8933f36 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py @@ -23,7 +23,7 @@ ## ############################################################################## -from taurus.external.qt import Qt +from taurus.external.qt import Qt, compat from PyQt4 import Qsci from taurus.qt.qtgui.resource import getThemeIcon @@ -117,7 +117,7 @@ def newFile(self): def openFile(self): if self.maybeSave(): - fileName = Qt.QFileDialog.getOpenFileName(self) + fileName, _ = compat.getOpenFileName(self) if not fileName is None and file != "": self.loadFile(fileName) @@ -128,7 +128,7 @@ def saveFile(self): return self.__saveFile(self.curFile) def __saveAs(self): - self.fileName = Qt.QFileDialog.getSaveFileName(self) + self.fileName, _ = compat.getSaveFileName(self) if self.fileName == "": return False return self.__saveFile(self.fileName) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py index a5cacde127..4a874d31a2 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py @@ -29,7 +29,7 @@ import os -from taurus.external.qt import Qt +from taurus.external.qt import Qt, compat from taurus.qt.qtgui.input import TaurusAttrListComboBox from sardana.taurus.qt.qtgui.extra_macroexecutor import globals @@ -286,7 +286,7 @@ def __init__(self, parent=None, paramModel=None): "clicked()"), self._chooseAFile) def _chooseAFile(self): - path = Qt.QFileDialog().getOpenFileName() + path, _ = compat.getOpenFileName() self.filePath.setText(path) def _readFileContent(self, path): diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py index 0103b08f50..addce3b969 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py @@ -34,7 +34,7 @@ import PyTango from taurus import Device -from taurus.external.qt import Qt +from taurus.external.qt import Qt, compat from taurus.qt.qtgui.container import TaurusMainWindow, TaurusWidget from taurus.qt.qtcore.configuration import BaseConfigurableClass from taurus.qt.qtgui.display import TaurusLed @@ -642,11 +642,11 @@ def onOpenSequence(self): self.tree.clearTree() sequencesPath = self.sequencesPath() - fileName = str(Qt.QFileDialog.getOpenFileName( + fileName, _ = compat.getOpenFileName( self, "Choose a sequence to open...", sequencesPath, - "*")) + "*") self.loadFile(fileName) @@ -656,11 +656,11 @@ def onSaveSequence(self): sequencesPath = str(Qt.QDir.homePath()) sequencesPath = os.path.join(sequencesPath, "Untitled.xml") - fileName = str(Qt.QFileDialog.getSaveFileName( + fileName, _ = compat.getSaveFileName( self, "Choose a sequence file name...", sequencesPath, - "*.xml")) + "*.xml") if fileName == "": return try: From cbc17b77a22af8fd7f96437e8c43c80edbfc4b51 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 9 Jan 2019 13:37:11 +0100 Subject: [PATCH 436/652] Use Qt5 pattern for signals Use Qt5 pattern for signal emission. Remove old Qt4 pattern. --- .../qt/qtcore/tango/sardana/macroserver.py | 77 +++++++------------ 1 file changed, 29 insertions(+), 48 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index cfcd701036..400be88a16 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -41,20 +41,18 @@ class QDoor(BaseDoor, Qt.QObject): __pyqtSignals__ = ["resultUpdated", "recordDataUpdated", "macroStatusUpdated"] __pyqtSignals__ += ["%sUpdated" % l.lower() for l in BaseDoor.log_streams] - # TODO: For Taurus 4 compatibility - try: - # sometimes we emit None hence the type is object - # (but most of the data are passed with type list) - resultUpdated = Qt.pyqtSignal(object) - recordDataUpdated = Qt.pyqtSignal(object) - errorUpdated = Qt.pyqtSignal(object) - warningUpdated = Qt.pyqtSignal(object) - infoUpdated = Qt.pyqtSignal(object) - outputUpdated = Qt.pyqtSignal(object) - debugUpdated = Qt.pyqtSignal(object) - experimentConfigurationChanged = Qt.pyqtSignal() - except AttributeError: - pass + + # sometimes we emit None hence the type is object + # (but most of the data are passed with type list) + resultUpdated = Qt.pyqtSignal(object) + recordDataUpdated = Qt.pyqtSignal(object) + macroStatusUpdated = Qt.pyqtSignal(object) + errorUpdated = Qt.pyqtSignal(object) + warningUpdated = Qt.pyqtSignal(object) + infoUpdated = Qt.pyqtSignal(object) + outputUpdated = Qt.pyqtSignal(object) + debugUpdated = Qt.pyqtSignal(object) + experimentConfigurationChanged = Qt.pyqtSignal() def __init__(self, name, qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) @@ -65,20 +63,14 @@ def __init__(self, name, qt_parent=None, **kw): def resultReceived(self, log_name, result): res = BaseDoor.resultReceived(self, log_name, result) - self.emit(Qt.SIGNAL("resultUpdated"), res) - # TODO: For Taurus 4 compatibility - if hasattr(self, "resultUpdated"): - self.resultUpdated.emit(res) + self.resultUpdated.emit(res) return res def recordDataReceived(self, s, t, v): if t not in CHANGE_EVTS: return res = BaseDoor.recordDataReceived(self, s, t, v) - self.emit(Qt.SIGNAL("recordDataUpdated"), res) - # TODO: For Taurus 4 compatibility - if hasattr(self, "recordDataUpdated"): - self.recordDataUpdated.emit(res) + self.recordDataUpdated.emit(res) return res def macroStatusReceived(self, s, t, v): @@ -89,22 +81,14 @@ def macroStatusReceived(self, s, t, v): macro = self.getRunningMacro() if macro is None: return - self.emit(Qt.SIGNAL("macroStatusUpdated"), (macro, res)) - # TODO: For Taurus 4 compatibility - if hasattr(self, "macroStatusUpdated"): - self.macroStatusUpdated.emit(res) + self.macroStatusUpdated.emit(res) return res def logReceived(self, log_name, output): res = BaseDoor.logReceived(self, log_name, output) log_name = log_name.lower() - self.emit(Qt.SIGNAL("%sUpdated" % log_name), output) - # TODO: For Taurus 4 compatibility - try: - recordDataUpdated = getattr(self, "%sUpdated" % log_name) - recordDataUpdated.emit(output) - except AttributeError: - pass + recordDataUpdated = getattr(self, "%sUpdated" % log_name) + recordDataUpdated.emit(output) return res def _prepare_connections(self): @@ -132,10 +116,10 @@ def _elementsChanged(self): self._mntgrp_connected = new_mntgrp_connected if mntgrp_changed: - self.emit(Qt.SIGNAL("experimentConfigurationChanged")) + self.experimentConfigurationChanged.emit() def _experimentConfigurationChanged(self, *args): - self.emit(Qt.SIGNAL("experimentConfigurationChanged")) + self.experimentConfigurationChanged.emit() def getExperimentConfigurationObj(self): self._prepare_connections() @@ -148,15 +132,12 @@ def getExperimentConfiguration(self): class QMacroServer(BaseMacroServer, Qt.QObject): - # TODO: For Taurus 4 compatibility - try: - typesUpdated = Qt.pyqtSignal() - elementsUpdated = Qt.pyqtSignal() - elementsChanged = Qt.pyqtSignal() - macrosUpdated = Qt.pyqtSignal() - environmentChanged = Qt.pyqtSignal(list) - except AttributeError: - pass + + typesUpdated = Qt.pyqtSignal() + elementsUpdated = Qt.pyqtSignal() + elementsChanged = Qt.pyqtSignal() + macrosUpdated = Qt.pyqtSignal() + environmentChanged = Qt.pyqtSignal(list) def __init__(self, name, qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) @@ -164,17 +145,17 @@ def __init__(self, name, qt_parent=None, **kw): def typesChanged(self, s, t, v): res = BaseMacroServer.typesChanged(self, s, t, v) - self.emit(Qt.SIGNAL("typesUpdated")) + self.typesUpdated.emit(res) return res def elementsChanged(self, s, t, v): res = BaseMacroServer.elementsChanged(self, s, t, v) - self.emit(Qt.SIGNAL("elementsUpdated")) + self.elementsUpdated.emit(res) return res def macrosChanged(self, s, t, v): res = BaseMacroServer.macrosChanged(self, s, t, v) - self.emit(Qt.SIGNAL("macrosUpdated")) + self.macrosUpdated.emit(res) return res def on_elements_changed(self, s, t, v): @@ -198,7 +179,7 @@ def on_environment_changed(self, s, t, v): ret = added, removed, changed = \ BaseMacroServer.on_environment_changed(self, s, t, v) if added or removed or changed: - self.emit(Qt.SIGNAL("environmentChanged"), ret) + self.environmentChanged.emit(ret) return ret From e673f8565cd1994cb40cc8ea56d441af1687f4c2 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 9 Jan 2019 15:34:41 +0100 Subject: [PATCH 437/652] Update SEP register --- doc/source/sep/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/source/sep/index.md b/doc/source/sep/index.md index cf2ce181e8..584a57fccc 100644 --- a/doc/source/sep/index.md +++ b/doc/source/sep/index.md @@ -12,7 +12,7 @@ Proposals list ------------| --------- | --------------------------------------------------------- [SEP0][] | OBSOLETE | Introducing Sardana Enhancement Proposal [SEP1][] | OBSOLETE | Reorganization of code repos - [SEP2][] | DRAFT | Lima integration + [SEP2][] | CANDIDATE | Improve integration of 1D and 2D experimental channels [SEP3][] | REJECTED (handled in [#297][]) | Adapt to [TEP3][] (Tango-independent taurus.core) [SEP4][] | ACCEPTED | HKL integration [SEP5][] | ACCEPTED | Implementation of tests infrastructure @@ -26,15 +26,16 @@ Proposals list [SEP13][] | REJECTED (moved to [TEP13][]) | Unified plugins support in Taurus & Sardana [SEP14][] | DRAFT | MSENV taurus schema [SEP15][] | ACCEPTED | Moving Sardana to Github - [SEP18][] | ACCEPTED | Extend acquisition and synchronization - concepts for SEP2 needs + [SEP16][] | DRAFT | Plugins (controllers, macros, etc.) register + [SEP17][] | DRAFT | Ongoing acquisition formalization and implementation + [SEP18][] | ACCEPTED | Extend acquisition and synchronization concepts for SEP2 needs [SEP0]: http://www.sardana-controls.org/sep/?SEP0.md [SEP1]: http://www.sardana-controls.org/sep/?SEP1.md -[SEP2]: http://www.sardana-controls.org/sep/?SEP2.md +[SEP2]: https://github.com/reszelaz/sardana/blob/sep2/doc/source/sep/SEP2.md [SEP3]: http://www.sardana-controls.org/sep/?SEP3.md [SEP4]: http://www.sardana-controls.org/sep/?SEP4.md [SEP5]: http://www.sardana-controls.org/sep/?SEP5.md @@ -48,6 +49,8 @@ Proposals list [SEP13]: http://www.sardana-controls.org/sep/?SEP13.md [SEP14]: http://www.sardana-controls.org/sep/?SEP14.md [SEP15]: http://www.sardana-controls.org/sep/?SEP15.md +[SEP16]: https://github.com/reszelaz/sardana/blob/sep16/doc/source/sep/SEP16.md +[SEP17]: https://github.com/reszelaz/sardana/blob/sep17/doc/source/sep/SEP17.md [SEP18]: http://www.sardana-controls.org/sep/?SEP18.md From 2d502f1a7a918714f8118f729853ed1390284ddd Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 9 Jan 2019 16:07:35 +0100 Subject: [PATCH 438/652] Use Qt5 pattern for signals Use Qt5 pattern for signal emision. Remove old Qt4 pattern. --- .../qt/qtcore/tango/sardana/macroserver.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 400be88a16..61ae52f4e5 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -53,12 +53,14 @@ class QDoor(BaseDoor, Qt.QObject): outputUpdated = Qt.pyqtSignal(object) debugUpdated = Qt.pyqtSignal(object) experimentConfigurationChanged = Qt.pyqtSignal() + elementsChanged = Qt.pyqtSignal() + environmentChanged = Qt.pyqtSignal() def __init__(self, name, qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) self.call__init__(BaseDoor, name, **kw) self._mntgrps_connected = [] - self._use_experimet_configuration = False + self._use_experiment_configuration = False self._connections_prepared = False def resultReceived(self, log_name, result): @@ -92,12 +94,11 @@ def logReceived(self, log_name, output): return res def _prepare_connections(self): - if not self._use_experimet_configuration and \ + if not self._use_experiment_configuration and \ not self._connections_prepared: - self.connect(self.macro_server, Qt.SIGNAL("environmentChanged"), - self._experimentConfigurationChanged) - self.connect(self.macro_server, Qt.SIGNAL("elementsChanged"), - self._elementsChanged) + self.macro_server.environmentChanged.connect( + self._experimentConfigurationChanged) + self.macro_server.elementsChanged.connect(self._elementsChanged) self._elementsChanged() self._connections_prepared = True @@ -110,8 +111,8 @@ def _elementsChanged(self): if name not in self._mntgrps_connected: mntgrp_changed = True # this measurement group is new obj = mg.getObj() - self.connect(obj, Qt.SIGNAL("configurationChanged"), - self._experimentConfigurationChanged) + obj.configurationChanged.connect( + self._experimentConfigurationChanged) new_mntgrp_connected.append(name) self._mntgrp_connected = new_mntgrp_connected @@ -170,9 +171,9 @@ def on_elements_changed(self, s, t, v): if elements and macros: break if elements: - self.emit(Qt.SIGNAL("elementsChanged")) + self.elementsChanged.emit() if macros: - self.emit(Qt.SIGNAL("macrosUpdated")) + self.macrosUpdated.emit() return ret def on_environment_changed(self, s, t, v): From 24060a81cc3a4b1f9e37f1fc7965f212fdfa1bd9 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 9 Jan 2019 16:09:08 +0100 Subject: [PATCH 439/652] Use Qt5 pattern for signals Remove old Qt4 pattern. --- src/sardana/taurus/qt/qtcore/tango/sardana/pool.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py index 5a47d4e56a..3f46ae3144 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py @@ -46,11 +46,8 @@ def __init__(self, name, qt_parent=None, **kw): class QMeasurementGroup(Qt.QObject, TangoDevice): - # TODO: For Taurus 4 compatibility - try: - configurationChanged = Qt.pyqtSignal() - except AttributeError: - pass + + configurationChanged = Qt.pyqtSignal() def __init__(self, name, qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) From dc970c56043694f08b0b86919a39fecbaa852c9f Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 9 Jan 2019 16:23:40 +0100 Subject: [PATCH 440/652] Use Qt5 pattern for signals Use Qt5 pattern for signals Remove old Qt4 pattern --- src/sardana/spock/spockms.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sardana/spock/spockms.py b/src/sardana/spock/spockms.py index 2a661f45b4..0fb4c91d6b 100755 --- a/src/sardana/spock/spockms.py +++ b/src/sardana/spock/spockms.py @@ -516,8 +516,7 @@ class QSpockDoor(SpockBaseDoor): def __init__(self, name, **kw): self.call__init__(SpockBaseDoor, name, **kw) - Qt.QObject.connect(self, Qt.SIGNAL('recordDataUpdated'), - self.processRecordData) + self.recordDataUpdated.connect(self.processRecordData) def recordDataReceived(self, s, t, v): if genutils.get_pylab_mode() == "inline": From c9b4d089cfc975302b5c55a50463c6c2f49d5395 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 9 Jan 2019 16:38:02 +0100 Subject: [PATCH 441/652] Use Qt5 pattern for signals Use Qt5 pattern for Qt signals. Remove old pattern based on Qt4.4 and older Qt versions. --- src/sardana/spock/inputhandler.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sardana/spock/inputhandler.py b/src/sardana/spock/inputhandler.py index 4174582541..1a5f528bbf 100644 --- a/src/sardana/spock/inputhandler.py +++ b/src/sardana/spock/inputhandler.py @@ -71,14 +71,16 @@ def input_timeout(self, input_data): class MessageHandler(Qt.QObject): + messageArrived = Qt.pyqtSignal(object) + def __init__(self, conn, parent=None): Qt.QObject.__init__(self, parent) self._conn = conn self._dialog = None - self.connect(self, Qt.SIGNAL("messageArrived"), self.on_message) + self.messageArrived.connect(self.on_message) def handle_message(self, input_data): - self.emit(Qt.SIGNAL("messageArrived"), input_data) + self.messageArrived.emit(input_data) def on_message(self, input_data): msg_type = input_data['type'] From 87d88c426759b8064ccfeeb9edcfe203d78a34d8 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 9 Jan 2019 16:42:57 +0100 Subject: [PATCH 442/652] Use new style signals Use new style signals. Remove old style signals. --- src/sardana/taurus/qt/qtcore/tango/sardana/pool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py index 3f46ae3144..6a14816a23 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py @@ -70,7 +70,7 @@ def _configurationChanged(self, s, t, v): self._config = None else: self._config = json.loads(v.value) - self.emit(Qt.SIGNAL("configurationChanged")) + self.configurationChanged.emit() def getConfiguration(self, cache=True): if self._config is None or not cache: From 0a93b34c491466415505066a18b1e384ac4a4ffe Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 9 Jan 2019 17:12:19 +0100 Subject: [PATCH 443/652] Use new style signals Use new style signals Remove old style signals --- src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 61ae52f4e5..b8a7fd15c4 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -146,17 +146,17 @@ def __init__(self, name, qt_parent=None, **kw): def typesChanged(self, s, t, v): res = BaseMacroServer.typesChanged(self, s, t, v) - self.typesUpdated.emit(res) + self.typesUpdated.emit() return res def elementsChanged(self, s, t, v): res = BaseMacroServer.elementsChanged(self, s, t, v) - self.elementsUpdated.emit(res) + self.elementsUpdated.emit() return res def macrosChanged(self, s, t, v): res = BaseMacroServer.macrosChanged(self, s, t, v) - self.macrosUpdated.emit(res) + self.macrosUpdated.emit() return res def on_elements_changed(self, s, t, v): From 3435bc2d548d091a570c1f976d7e716dc82582b7 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 10 Jan 2019 11:16:41 +0100 Subject: [PATCH 444/652] Add TODOs about unused methods Add TODOs about unused methods and signal name homogenization. --- .../qt/qtcore/tango/sardana/macroserver.py | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index b8a7fd15c4..32b8e1431a 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -131,9 +131,11 @@ def getExperimentConfiguration(self): return BaseDoor.getExperimentConfiguration(self) - class QMacroServer(BaseMacroServer, Qt.QObject): + # TODO: Choose and homogenize signals named ...Updated and ...Changed. + # e.g: there should exist only one signal for elementsUpdated + # and elementsChanged. typesUpdated = Qt.pyqtSignal() elementsUpdated = Qt.pyqtSignal() elementsChanged = Qt.pyqtSignal() @@ -144,20 +146,23 @@ def __init__(self, name, qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) self.call__init__(BaseMacroServer, name, **kw) - def typesChanged(self, s, t, v): - res = BaseMacroServer.typesChanged(self, s, t, v) - self.typesUpdated.emit() - return res - - def elementsChanged(self, s, t, v): - res = BaseMacroServer.elementsChanged(self, s, t, v) - self.elementsUpdated.emit() - return res - - def macrosChanged(self, s, t, v): - res = BaseMacroServer.macrosChanged(self, s, t, v) - self.macrosUpdated.emit() - return res + # TODO: The following three methods are not used, and are not + # implemented in the base class 'BaseMacroServer': Implement them. + # (Now commented because they give conflicts with new style PyQt signals). + # def typesChanged(self, s, t, v): + # res = BaseMacroServer.typesChanged(self, s, t, v) + # self.typesUpdated.emit() + # return res + # + # def elementsChanged(self, s, t, v): + # res = BaseMacroServer.elementsChanged(self, s, t, v) + # self.elementsUpdated.emit() + # return res + # + # def macrosChanged(self, s, t, v): + # res = BaseMacroServer.macrosChanged(self, s, t, v) + # self.macrosUpdated.emit() + # return res def on_elements_changed(self, s, t, v): ret = added, removed, changed = \ From 1c6680241f72e425f6043c091289a1ac40acb9de Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 10 Jan 2019 11:30:01 +0100 Subject: [PATCH 445/652] Change type of argument Signal environmentChanged emits a tuple and not a list. Change type to 'object' instead of 'list'. --- src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 32b8e1431a..49e0f54e54 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -140,7 +140,7 @@ class QMacroServer(BaseMacroServer, Qt.QObject): elementsUpdated = Qt.pyqtSignal() elementsChanged = Qt.pyqtSignal() macrosUpdated = Qt.pyqtSignal() - environmentChanged = Qt.pyqtSignal(list) + environmentChanged = Qt.pyqtSignal(object) def __init__(self, name, qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) From 39f955fb79f631578d72e7100ef92869aba7be57 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 10 Jan 2019 11:51:31 +0100 Subject: [PATCH 446/652] Use new style signals Use new style signals. --- .../favouriteseditor/favouriteseditor.py | 18 ++++++++---------- .../favouriteseditor/historyviewer.py | 9 +++++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/favouriteseditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/favouriteseditor.py index 5b83faa398..6b73926833 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/favouriteseditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/favouriteseditor.py @@ -103,6 +103,8 @@ def getQtDesignerPluginInfo(cls): class FavouritesMacrosList(Qt.QListView, BaseConfigurableClass): + favouriteSelected = Qt.pyqtSignal(object) + def __init__(self, parent): Qt.QListView.__init__(self, parent) @@ -110,31 +112,27 @@ def __init__(self, parent): self.removeAction = Qt.QAction(getIcon(":/actions/list-remove.svg"), "Remove from favourites", self) - self.connect(self.removeAction, Qt.SIGNAL("triggered()"), - self.removeMacros) + self.removeAction.triggered.connect(self.removeMacros) self.removeAction.setToolTip( "Clicking this button will remove selected macros " "from favourites.") self.removeAllAction = Qt.QAction(getIcon(":/places/user-trash.svg"), "Remove all from favourites", self) - self.connect(self.removeAllAction, Qt.SIGNAL( - "triggered()"), self.removeAllMacros) + self.removeAllAction.triggered.connect(self.removeAllMacros) self.removeAllAction.setToolTip( "Clicking this button will remove all macros from favourites.") self.moveUpAction = Qt.QAction(getIcon(":/actions/go-up.svg"), "Move up", self) - self.connect(self.moveUpAction, Qt.SIGNAL( - "triggered()"), self.upMacro) + self.moveUpAction.triggered.connect(self.upMacro) self.moveUpAction.setToolTip( "Clicking this button will move the macro up " "in the favourites hierarchy.") self.moveDownAction = Qt.QAction(getIcon(":/actions/go-down.svg"), "Move down", self) - self.connect(self.moveDownAction, Qt.SIGNAL( - "triggered()"), self.downMacro) + self.moveDownAction.triggered.connect(self.downMacro) self.moveDownAction.setToolTip( "Clicking this button will move the macro down " "in the favourites hierarchy.") @@ -143,7 +141,7 @@ def __init__(self, parent): def currentChanged(self, current, previous): macro = copy.deepcopy(self.currentIndex().internalPointer()) - self.emit(Qt.SIGNAL("favouriteSelected"), macro) + self.favouriteSelected.emit(macro) Qt.QListView.currentChanged(self, current, previous) def selectionChanged(self, old, new): @@ -174,7 +172,7 @@ def mousePressEvent(self, e): clickedIndex = self.indexAt(e.pos()) if clickedIndex.isValid(): macro = copy.deepcopy(self.currentIndex().internalPointer()) - self.emit(Qt.SIGNAL("favouriteSelected"), macro) + self.favouriteSelected.emit(macro) Qt.QListView.mousePressEvent(self, e) def disableActions(self): diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/historyviewer.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/historyviewer.py index 96397f2538..e76455cd34 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/historyviewer.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/historyviewer.py @@ -114,28 +114,29 @@ def getQtDesignerPluginInfo(cls): class HistoryMacrosList(Qt.QListView, BaseConfigurableClass): + historySelected = Qt.pyqtSignal(object) + def __init__(self, parent): Qt.QListView.__init__(self, parent) self.setSelectionMode(Qt.QListView.SingleSelection) self.removeAllAction = Qt.QAction(getIcon(":/places/user-trash.svg"), "Remove all from history", self) - self.connect(self.removeAllAction, Qt.SIGNAL( - "triggered()"), self.removeAllMacros) + self.removeAllAction.triggered.connect(self.removeAllMacros) self.removeAllAction.setToolTip( "Clicking this button will remove all macros from history.") self.removeAllAction.setEnabled(False) def currentChanged(self, current, previous): macro = copy.deepcopy(self.currentIndex().internalPointer()) - self.emit(Qt.SIGNAL("historySelected"), macro) + self.historySelected.emit(macro) Qt.QListView.currentChanged(self, current, previous) def mousePressEvent(self, e): clickedIndex = self.indexAt(e.pos()) if clickedIndex.isValid(): macro = copy.deepcopy(self.currentIndex().internalPointer()) - self.emit(Qt.SIGNAL("historySelected"), macro) + self.historySelected.emit(macro) self.removeAllAction.setEnabled(True) Qt.QListView.mousePressEvent(self, e) From 87a3221974a417abf7264af7ac575049669435a5 Mon Sep 17 00:00:00 2001 From: teresa Date: Thu, 10 Jan 2019 13:34:06 +0100 Subject: [PATCH 447/652] Use Qt5 pattern for signals --- .../qt/qtgui/extra_sardana/controllertree.py | 16 ++-- .../qt/qtgui/extra_sardana/expdescription.py | 78 ++++++++----------- .../qt/qtgui/extra_sardana/macrotree.py | 14 ++-- .../qtgui/extra_sardana/measurementgroup.py | 48 +++--------- .../qt/qtgui/extra_sardana/sardanaeditor.py | 16 +--- 5 files changed, 68 insertions(+), 104 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py b/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py index 7445bb772e..2671ce8b9a 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py @@ -122,13 +122,13 @@ class ControllerBaseModel(TaurusBaseModel): ColumnRoles = (PoolControllerView.ControllerModule, PoolControllerView.ControllerModule, PoolControllerView.ControllerClass), + + def setDataSource(self, pool): if self._data_src is not None: - Qt.QObject.disconnect(self._data_src, Qt.SIGNAL( - 'controllerClassesUpdated'), self.controllerClassesUpdated) + self._data_src.controllerClassesUpdated.disconnect(self.controllerClassesUpdated) if pool is not None: - Qt.QObject.connect(pool, Qt.SIGNAL( - 'controllerClassesUpdated'), self.controllerClassesUpdated) + self.pool.controllerClassesUpdated.connect(self.controllerClassesUpdated) TaurusBaseModel.setDataSource(self, pool) def controllerClassesUpdated(self): @@ -277,7 +277,11 @@ def getModelClass(self): class ControllerClassSelectionDialog(Qt.QDialog): + + __pyqtSignals__ = ["accepted", + "rejected"] + def __init__(self, parent=None, designMode=False, model_name=None, perspective=None): Qt.QDialog.__init__(self, parent) @@ -297,8 +301,8 @@ def __init__(self, parent=None, designMode=False, model_name=None, perspective=N self._buttonBox.setStandardButtons(bts) layout.addWidget(self._panel) layout.addWidget(self._buttonBox) - self.connect(self._buttonBox, Qt.SIGNAL("accepted()"), self.accept) - self.connect(self._buttonBox, Qt.SIGNAL("rejected()"), self.reject) + self._buttonBox.accepted.connect(self.accept) + self._buttonBox.rejected.connect(self.reject) def selectedItems(self): return self._panel.selectedItems() diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 32ae56f1d1..dac7d90b11 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -172,11 +172,7 @@ class ExpDescriptionEditor(Qt.QWidget, TaurusBaseWidget): using the `ExperimentConfiguration` environmental variable for that Door. ''' - try: - # TODO: For Taurus 4 compatibility - createExpConfChangedDialog = Qt.pyqtSignal() - except AttributeError: - pass + createExpConfChangedDialog = Qt.pyqtSignal() def __init__(self, parent=None, door=None, plotsButton=True, autoUpdate=False): @@ -212,34 +208,33 @@ def __init__(self, parent=None, door=None, plotsButton=True, # Pending event variables self._expConfChangedDialog = None - self.connect(self, Qt.SIGNAL('createExpConfChangedDialog'), - self._createExpConfChangedDialog) - - self.connect(self.ui.activeMntGrpCB, Qt.SIGNAL( - 'activated (QString)'), self.changeActiveMntGrp) - self.connect(self.ui.createMntGrpBT, Qt.SIGNAL( - 'clicked ()'), self.createMntGrp) - self.connect(self.ui.deleteMntGrpBT, Qt.SIGNAL( - 'clicked ()'), self.deleteMntGrp) - self.connect(self.ui.compressionCB, Qt.SIGNAL( - 'currentIndexChanged (int)'), self.onCompressionCBChanged) - self.connect(self.ui.pathLE, Qt.SIGNAL( - 'textEdited (QString)'), self.onPathLEEdited) - self.connect(self.ui.filenameLE, Qt.SIGNAL( - 'textEdited (QString)'), self.onFilenameLEEdited) - self.connect(self.ui.channelEditor.getQModel(), Qt.SIGNAL( - 'dataChanged (QModelIndex, QModelIndex)'), self._updateButtonBox) - self.connect(self.ui.channelEditor.getQModel(), Qt.SIGNAL( - 'modelReset ()'), self._updateButtonBox) + self.createExpConfChangedDialog.connect( + self._createExpConfChangedDialog) + self.ui.activeMntGrpCB.activated.connect( + self.changeActiveMntGrp) + self.ui.createMntGrpBT.clicked.connect( + self.createMntGrp) + self.ui.deleteMntGrpBT.clicked.connect( + self.deleteMntGrp) + self.ui.compressionCB.currentIndexChanged.connect( + self.onCompressionCBChanged) + self.ui.pathLE.textEdited.connect( + self.onPathLEEdited) + self.ui.filenameLE.textEdited.connect( + self.onFilenameLEEdited) + self.ui.channelEditor.getQModel.dataChanged.connect( + self._updateButtonBox) + self.ui.channelEditor.getQModel.modelReset.connect( + self._updateButtonBox) preScanList = self.ui.preScanList - self.connect(preScanList, Qt.SIGNAL('dataChanged'), - self.onPreScanSnapshotChanged) - # TODO: For Taurus 4 compatibility + preScanList.dataChanged.connect( + self.onPreScanSnapshotChanged) + if hasattr(preScanList, "dataChangedSignal"): preScanList.dataChangedSignal.connect( self.onPreScanSnapshotChanged) - self.connect(self.ui.choosePathBT, Qt.SIGNAL( - 'clicked ()'), self.onChooseScanDirButtonClicked) + self.ui.choosePathBT.clicked.connect( + self.onChooseScanDirButtonClicked) self.__plotManager = None icon = resource.getIcon(":/actions/view.svg") @@ -248,14 +243,13 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.togglePlotsAction.setChecked(False) self.togglePlotsAction.setEnabled(plotsButton) self.addAction(self.togglePlotsAction) - self.connect(self.togglePlotsAction, Qt.SIGNAL("toggled(bool)"), - self.onPlotsButtonToggled) + self.togglePlotsAction.toggled.connect(self.onPlotsButtonToggled) self.ui.plotsButton.setDefaultAction(self.togglePlotsAction) if door is not None: self.setModel(door) - self.connect(self.ui.buttonBox, Qt.SIGNAL( - "clicked(QAbstractButton *)"), self.onDialogButtonClicked) + + self.ui.buttonBox.clicked.connect(self.onDialogButtonClicked) # Taurus Configuration properties and delegates self.registerConfigDelegate(self.ui.channelEditor) @@ -356,8 +350,6 @@ def _experimentConfigurationChanged(self): self._reloadConf(force=True) else: if self._expConfChangedDialog is None: - self.emit(Qt.SIGNAL('createExpConfChangedDialog')) - # TODO: For Taurus 4 compatibility if hasattr(self, 'createExpConfChangedDialog'): self.createExpConfChangedDialog.emit() else: @@ -384,7 +376,7 @@ def onChooseScanDirButtonClicked(self): self, 'Choose directory for saving files', self.ui.pathLE.text()) if ret: self.ui.pathLE.setText(ret) - self.ui.pathLE.emit(Qt.SIGNAL('textEdited (QString)'), ret) + self.ui.pathLE.emit.textEdited.emit(ret) def onDialogButtonClicked(self, button): role = self.ui.buttonBox.buttonRole(button) @@ -412,8 +404,7 @@ def setModel(self, model): msname = door.macro_server.getFullName() self.ui.taurusModelTree.setModel(tghost) self.ui.sardanaElementTree.setModel(msname) - self.connect(door, Qt.SIGNAL("experimentConfigurationChanged"), - self._experimentConfigurationChanged) + door.experimentConfigurationChanged.connect(self._experimentConfigurationChanged) def _reloadConf(self, force=False): if not force and self.isDataChanged(): @@ -535,8 +526,7 @@ def writeExperimentConfiguration(self, ask=True): self._dirtyMntGrps = set() self.ui.channelEditor.getQModel().setDataChanged(False) self._setDirty(False) - self.emit(Qt.SIGNAL('experimentConfigurationChanged'), - copy.deepcopy(conf)) + self.experimentConfigurationChanged.emit(copy.deepcopy(conf)) return True def changeActiveMntGrp(self, activeMntGrpName): @@ -667,11 +657,11 @@ def onPlotsButtonToggled(self, checked): DynamicPlotManager self.__plotManager = DynamicPlotManager(self) self.__plotManager.setModel(self.getModelName()) - self.connect(self, Qt.SIGNAL('experimentConfigurationChanged'), - self.__plotManager.onExpConfChanged) + self.experimentConfigurationChanged.connect( + self.__plotManager.onExpConfChanged) else: - self.disconnect(self, Qt.SIGNAL('experimentConfigurationChanged'), - self.__plotManager.onExpConfChanged) + self.experimentConfigurationChanged.disconnect( + self.__plotManager.onExpConfChanged) self.__plotManager.removePanels() self.__plotManager.setModel(None) self.__plotManager = None diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/macrotree.py b/src/sardana/taurus/qt/qtgui/extra_sardana/macrotree.py index bb01715584..22518f9a6f 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/macrotree.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/macrotree.py @@ -126,11 +126,11 @@ class MacroBaseModel(TaurusBaseModel): def setDataSource(self, ms): if self._data_src is not None: - Qt.QObject.disconnect(self._data_src, Qt.SIGNAL( - 'macrosUpdated'), self.macrosUpdated) + self._data_src.macrosUpdated.disconnect( + self.macrosUpdated) if ms is not None: - Qt.QObject.connect(ms, Qt.SIGNAL( - 'macrosUpdated'), self.macrosUpdated) + ms.macrosUpdated.connect( + self.macrosUpdated) TaurusBaseModel.setDataSource(self, ms) def macrosUpdated(self): @@ -273,8 +273,10 @@ def __init__(self, parent=None, designMode=False, model_name=None, perspective=N self._buttonBox.setStandardButtons(bts) layout.addWidget(self._panel) layout.addWidget(self._buttonBox) - self.connect(self._buttonBox, Qt.SIGNAL("accepted()"), self.accept) - self.connect(self._buttonBox, Qt.SIGNAL("rejected()"), self.reject) + self._buttonBox.accepted.connect( + self.accept) + self._buttonBox.rejected.connect( + self.reject) def selectedItems(self): return self._panel.selectedItems() diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py index b00e0200bb..d93f895446 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py @@ -273,6 +273,8 @@ def getElementTypeToolTip(t): class BaseMntGrpChannelItem(TaurusBaseTreeItem): """ """ + dataChanged = Qt.pyqtSignal(const QModelIndex &, const QModelIndex &) + def data(self, index): """Returns the data of this node for the given index @@ -591,8 +593,7 @@ def setData(self, index, qvalue, role=Qt.Qt.EditRole): item = index.internalPointer() item.setData(index, qvalue) self._dirty = True - self.emit(Qt.SIGNAL("dataChanged(const QModelIndex &, const QModelIndex &)"), - index, index) + self.dataChanged.emit(index, index) return True # @todo: Very inefficient implementation. We should use {begin|end}InsertRows @@ -683,11 +684,9 @@ class MntGrpChannelModel(BaseMntGrpChannelModel): def setDataSource(self, mg): if self._data_src is not None: - Qt.QObject.disconnect(self._data_src, Qt.SIGNAL( - 'configurationChanged'), self.configurationChanged) + self._data_src.configurationChanged.disconnect(self.configurationChanged) if mg is not None: - Qt.QObject.connect(mg, Qt.SIGNAL( - 'configurationChanged'), self.configurationChanged) + mg.configurationChanged.connect(self.configurationChanged) BaseMntGrpChannelModel.setDataSource(self, mg) def configurationChanged(self): @@ -971,8 +970,7 @@ def __init__(self, parent=None, designMode=False, with_filter_widget=True, persp self.setContextMenuPolicy(Qt.Qt.ActionsContextMenu) self._simpleViewAction = Qt.QAction("Simple View", self) self._simpleViewAction.setCheckable(True) - self.connect(self._simpleViewAction, Qt.SIGNAL( - "toggled(bool)"), self.setSimpleView) + self._simpleViewAction.toggled.connect(self.setSimpleView) self.addAction(self._simpleViewAction) self.registerConfigProperty( self.isSimpleView, self.setSimpleView, "simpleView") @@ -1004,34 +1002,12 @@ def createViewWidget(self): # causes a segfault when calling ChannelDelegate.createEditor tableView.setItemDelegate(self._delegate) tableView.setSortingEnabled(False) - self.connect(self._editorBar, Qt.SIGNAL( - "addTriggered"), self.addChannel) - # TODO: For Taurus 4 compatibility - if hasattr(self._editorBar, "addTriggered"): - self._editorBar.addTriggered.connect(self.addChannel) - self.connect(self._editorBar, Qt.SIGNAL( - "removeTriggered"), self.removeChannels) - # TODO: For Taurus 4 compatibility - if hasattr(self._editorBar, "removeTriggered"): - self._editorBar.removeTriggered.connect(self.removeChannels) - self.connect(self._editorBar, Qt.SIGNAL( - "moveUpTriggered"), self.moveUpChannel) - # TODO: For Taurus 4 compatibility - if hasattr(self._editorBar, "moveUpTriggered"): - self._editorBar.moveUpTriggered.connect(self.moveUpChannel) - self.connect(self._editorBar, Qt.SIGNAL( - "moveDownTriggered"), self.moveDownChannel) - # TODO: For Taurus 4 compatibility - if hasattr(self._editorBar, "moveDownTriggered"): - self._editorBar.moveDownTriggered.connect(self.moveDownChannel) - self.connect(self._editorBar, Qt.SIGNAL( - "moveTopTriggered"), self.moveTopChannel) - if hasattr(self._editorBar, "moveTopTriggered"): - self._editorBar.moveTopTriggered.connect(self.moveTopChannel) - self.connect(self._editorBar, Qt.SIGNAL( - "moveBottomTriggered"), self.moveBottomChannel) - if hasattr(self._editorBar, "moveBottomTriggered"): - self._editorBar.moveBottomTriggered.connect(self.moveBottomChannel) + self._editorBar.addTriggered.connect(self.addChannel) + self._editorBar.removeTriggered.connect(self.removeChannels) + self._editorBar.moveUpTriggered.connect(self.moveUpChannel) + self._editorBar.moveDownTriggered.connect(self.moveDownChannel) + self._editorBar.moveTopTriggered.connect(self.moveTopChannel) + self._editorBar.moveBottomTriggered.connect(self.moveBottomChannel) return tableView def createToolArea(self): diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py b/src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py index 70d0ce6b59..8d6ae8b5f0 100755 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py @@ -150,12 +150,8 @@ def __init__(self, parent=None, designMode=None): SardanaLibTreeWidget(self, with_navigation_bar=False, with_filter_widget=False,) elementTree.treeView().setColumnHidden(1, True) - try: - self._elementTree.itemDoubleClicked.connect( - self.on_element_clicked) - except AttributeError: - self.connect(self._elementTree, Qt.SIGNAL("itemDoubleClicked"), - self.on_element_clicked) + self._elementTree.itemDoubleClicked.connect( + self.on_element_clicked) self.insertWidget(0, self._elementTree) self.setAutoTooltip(False) @@ -206,12 +202,8 @@ def createMenuActions(self): def register_editorstack(self, editorstack): TaurusBaseEditor.register_editorstack(self, editorstack) - try: - self.editorstack.refresh_save_all_action.connect( - self.refresh_save_and_apply_action) - except AttributeError: - self.connect(editorstack, Qt.SIGNAL('refresh_save_all_action()'), - self.refresh_save_and_apply_action) + self.editorstack.refresh_save_all_action.connect( + self.refresh_save_and_apply_action) def refresh_save_and_apply_action(self): self.save_and_apply_action.setEnabled(self.save_action.isEnabled()) From b43ea0b017e78d99e71846b24b674566b92302be Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 10 Jan 2019 12:27:17 +0100 Subject: [PATCH 448/652] Use new style signals --- .../macroparameterseditor.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/macroparameterseditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/macroparameterseditor.py index 27e2b3a8be..de58b3125c 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/macroparameterseditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/macroparameterseditor.py @@ -118,35 +118,30 @@ def __init__(self, parent=None, designMode=False): self.addAction = Qt.QAction(getThemeIcon( "list-add"), "Add new repetition", self) - self.connect(self.addAction, Qt.SIGNAL( - "triggered()"), self.onAddRepeat) + self.addAction.triggered.connect(self.onAddRepeat) self.addAction.setToolTip( "Clicking this button will add new repetition to current parameter.") self.deleteAction = Qt.QAction(getThemeIcon( "list-remove"), "Remove repetition", self) - self.connect(self.deleteAction, Qt.SIGNAL( - "triggered()"), self.onDelRepeat) + self.deleteAction.triggered.connect(self.onDelRepeat) self.deleteAction.setToolTip( "Clicking this button will remove current repetition.") self.moveUpAction = Qt.QAction(getThemeIcon("go-up"), "Move up", self) - self.connect(self.moveUpAction, Qt.SIGNAL( - "triggered()"), self.onUpRepeat) + self.moveUpAction.triggered.connect(self.onUpRepeat) self.moveUpAction.setToolTip( "Clicking this button will move current repetition up.") self.moveDownAction = Qt.QAction( getThemeIcon("go-down"), "Move down", self) - self.connect(self.moveDownAction, Qt.SIGNAL( - "triggered()"), self.onDownRepeat) + self.moveDownAction.triggered.connect(self.onDownRepeat) self.moveDownAction.setToolTip( "Clicking this button will move current repetition down.") self.duplicateAction = Qt.QAction(getThemeIcon("edit-copy"), "Duplicate", self) - self.connect(self.duplicateAction, Qt.SIGNAL("triggered()"), - self.onDuplicateRepeat) + self.duplicateAction.triggered.connect(self.onDuplicateRepeat) msg = "Clicking this button will duplicate the given node." self.duplicateAction.setToolTip(msg) From f71d7ad6e62fffc72aac4a9f1bb2f993cc59a1eb Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 10 Jan 2019 14:17:50 +0100 Subject: [PATCH 449/652] Use new style signals --- .../qtgui/extra_macroexecutor/macroparameterseditor/model.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py index fad224e602..b497d545e9 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py @@ -184,8 +184,7 @@ def setData(self, index, value, role=Qt.Qt.EditRole): # if index.isValid() and 0 <= index.row() < len(node.parent()): if index.column() == 1: node.setValue(Qt.from_qvariant(value, str)) - self.emit( - Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index) + self.dataChanged.emit(index, index) return True return False From 5717b318162af1cd08524715fd91fbb693c87843 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 10 Jan 2019 16:22:08 +0100 Subject: [PATCH 450/652] Adapt to new signal style Adapt to new signal style. The signal "modelChanged()" is only used to call the method onModelChanged. No other widgets are using this signal, and it is not easy to adapt it to the new PyQt signal style without finding collisions with a Taurus signal with the same name, etc. Applied solution: After discussion, decided to remove signal "modelChanged()" and its emits, and call directly the method onModelChanged instead. --- CHANGELOG.md | 5 +++++ .../macroparameterseditor/customeditors/senv.py | 6 +++--- .../macroparameterseditor/parameditors.py | 15 +++++++-------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93fb2f49f6..91d321d24e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -146,6 +146,11 @@ This file follows the formats and conventions from [keepachangelog.com] - `Controller.getUsedAxis` (Taurus device extension) in favor of `Controller.getUsedAxes` (#609) +### Removed +- Signal `modelChanged()` from ParamBase class to use the call to + method onModelChanged directly instead + + ## [2.4.0] 2018-03-14 ### Added diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py index ee283dc0d0..48c4987d87 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py @@ -171,14 +171,14 @@ def setValue(self, value): def onAddNewColumn(self): self.extraColumnsTable.insertRows() - self.emit(Qt.SIGNAL("modelChanged()")) + self.onModelChanged() def onRemoveSelectedColumns(self): self.extraColumnsTable.removeRows() - self.emit(Qt.SIGNAL("modelChanged()")) + self.onModelChanged() def onExtraColumnsChanged(self): - self.emit(Qt.SIGNAL("modelChanged()")) + self.onModelChanged() class ExtraColumnsTable(Qt.QTableView): diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py index 4a874d31a2..ed1c06536f 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py @@ -42,7 +42,7 @@ def str2bool(text): return text in ("True", "1") -class ParamBase: +class ParamBase(object): def __init__(self, paramModel=None): self.setParamModel(paramModel) @@ -66,7 +66,6 @@ def setIndex(self, index): self._index = index paramModel = index.model().nodeFromIndex(index) self.setParamModel(paramModel) - self.connect(self, Qt.SIGNAL("modelChanged()"), self.onModelChanged) self.setValue(paramModel.value()) def onModelChanged(self): @@ -97,7 +96,7 @@ def setValue(self, value): self.setCurrentIndex(idx) def onCurrentIndexChanged(self): - self.emit(Qt.SIGNAL("modelChanged()")) + self.onModelChanged() class ComboBoxParam(ParamBase, Qt.QComboBox): @@ -121,7 +120,7 @@ def setValue(self, value): self.setCurrentIndex(idx) def onCurrentIndexChanged(self): - self.emit(Qt.SIGNAL("modelChanged()")) + self.onModelChanged() class MSAttrListComboBoxParam(ParamBase, MSAttrListComboBox): @@ -141,7 +140,7 @@ def setValue(self, value): self.setCurrentText(value) def onCurrentIndexChanged(self): - self.emit(Qt.SIGNAL("modelChanged()")) + self.onModelChanged() class AttrListComboBoxParam(ParamBase, TaurusAttrListComboBox): @@ -182,7 +181,7 @@ def __init__(self, parent=None, paramModel=None): "textChanged(const QString&)"), self.onTextChanged) def onTextChanged(self): - self.emit(Qt.SIGNAL("modelChanged()")) + self.onModelChanged() # def setDefaultValue(self): # defVal = self.paramModel().defValue() @@ -214,7 +213,7 @@ def setValue(self, value): self.setChecked(str2bool(value)) def onStateChanged(self): - self.emit(Qt.SIGNAL("modelChanged()")) + self.onModelChanged() class SpinBoxParam(ParamBase, Qt.QSpinBox): @@ -330,7 +329,7 @@ def __init__(self, parent=None, paramModel=None): "textChanged(const QString&)"), self.onDirPathChanged) def onDirPathChanged(self): - self.emit(Qt.SIGNAL("modelChanged()")) + self.onModelChanged() def __chooseDirPath(self): path = Qt.QFileDialog().getExistingDirectory() From 220dd45925c6d88a7d19c5cc4de32c18eaa3b08e Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 10 Jan 2019 16:41:45 +0100 Subject: [PATCH 451/652] Adapt to new PyQt signal style --- src/sardana/taurus/qt/qtcore/tango/sardana/model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/model.py b/src/sardana/taurus/qt/qtcore/tango/sardana/model.py index 0e3a529db0..8136cc4793 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/model.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/model.py @@ -175,6 +175,8 @@ def icon(self, index): class SardanaBaseElementModel(TaurusBaseModel): + elementsChanged = Qt.pyqtSignal() + ColumnNames = ["Elements", "Controller/Module/Parent"] ColumnRoles = ('Root', 'type', 'name', 'name'), "parent" @@ -185,11 +187,9 @@ def __init__(self, parent=None, data=None): def setDataSource(self, data_source): old_ds = self.dataSource() if old_ds is not None: - Qt.QObject.disconnect(old_ds, Qt.SIGNAL('elementsChanged'), - self.on_elements_changed) + old_ds.elementsChanged.disconnect(self.on_elements_changed) if data_source is not None: - Qt.QObject.connect(data_source, Qt.SIGNAL('elementsChanged'), - self.on_elements_changed) + data_source.elementsChanged.connect(self.on_elements_changed) TaurusBaseModel.setDataSource(self, data_source) def on_elements_changed(self): From 26702336390975aed00ec4707d6b16a8464cfc23 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 10 Jan 2019 16:51:57 +0100 Subject: [PATCH 452/652] Adapt to new PyQt signal style --- src/sardana/taurus/qt/qtcore/tango/sardana/model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/model.py b/src/sardana/taurus/qt/qtcore/tango/sardana/model.py index 8136cc4793..9f33b6f88e 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/model.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/model.py @@ -379,6 +379,8 @@ def icon(self, index): class SardanaEnvironmentModel(TaurusBaseModel): + environmentChanged = Qt.pyqtSignal() + ColumnNames = ["Environment", "Value", "Data Type"] ColumnRoles = ('Root', 'key'), 'value', 'datatype' @@ -389,11 +391,9 @@ def __init__(self, parent=None, data=None): def setDataSource(self, data_source): old_ds = self.dataSource() if old_ds is not None: - Qt.QObject.disconnect(old_ds, Qt.SIGNAL('environmentChanged'), - self.on_environment_changed) + old_ds.environmentChanged(self.on_environment_changed) if data_source is not None: - Qt.QObject.connect(data_source, Qt.SIGNAL('environmentChanged'), - self.on_environment_changed) + data_source.environmentChanged(self.on_environment_changed) TaurusBaseModel.setDataSource(self, data_source) def on_environment_changed(self): From b72256a97bcd07d0729b8d7b7f9cc55e8141c579 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 10 Jan 2019 16:58:04 +0100 Subject: [PATCH 453/652] Update how to release with comments from sardana followup (2019/01/10) --- doc/how_to_release.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/how_to_release.md b/doc/how_to_release.md index 688b82f718..757332b593 100644 --- a/doc/how_to_release.md +++ b/doc/how_to_release.md @@ -1,4 +1,4 @@ -# How to +# How to release This is a guide for sardana release managers: it details the steps for making an official release, including a checklist of stuff that should be manually @@ -34,6 +34,7 @@ tested. 3. The version numbers used in the man pages of the Sardana scripts are bumped (you may use `taurus/doc/makeman` script executing it from the doc directory e.g. `sardana/doc`) and committing the changes. + There is a known [problem with the spock version number](https://github.com/sardana-org/sardana/issues/518). 4. In the code use version number instead of milestone in deprecation warnings (if any) e.g. replace *Jul18* with *2.5.0*. 5. Create a PR to merge the `release-XXX` against the **`master`** branch From 3ca8971678a2da5b2c56d99c9e74cac9931b3182 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 10 Jan 2019 17:10:00 +0100 Subject: [PATCH 454/652] Adapt to new PyQt signal style --- .../macroparameterseditor/parameditors.py | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py index ed1c06536f..5326074ca2 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py @@ -80,8 +80,7 @@ def __init__(self, parent=None, paramModel=None): ParamBase.__init__(self, paramModel) self.addItems(['True', 'False']) - self.connect(self, Qt.SIGNAL("currentIndexChanged(int)"), - self.onCurrentIndexChanged) + self.currentIndexChanged.connect(self.onCurrentIndexChanged) def getValue(self): return str(self.currentText()) @@ -90,8 +89,7 @@ def setValue(self, value): currentIdx = self.currentIndex() idx = self.findText(value) if currentIdx == idx: - self.emit(Qt.SIGNAL("currentIndexChanged(int)"), - self.currentIndex()) + self.currentIndexChanged.emit(self.currentIndex()) else: self.setCurrentIndex(idx) @@ -104,8 +102,7 @@ class ComboBoxParam(ParamBase, Qt.QComboBox): def __init__(self, parent=None, paramModel=None): Qt.QComboBox.__init__(self, parent) ParamBase.__init__(self, paramModel) - self.connect(self, Qt.SIGNAL("currentIndexChanged(int)"), - self.onCurrentIndexChanged) + self.currentIndexChanged.connect(self.onCurrentIndexChanged) def getValue(self): return str(self.currentText()) @@ -114,8 +111,7 @@ def setValue(self, value): currentIdx = self.currentIndex() idx = self.findText(value) if currentIdx == idx: - self.emit(Qt.SIGNAL("currentIndexChanged(int)"), - self.currentIndex()) + self.currentIndexChanged.emit(self.currentIndex()) else: self.setCurrentIndex(idx) @@ -130,8 +126,7 @@ def __init__(self, parent=None, paramModel=None): ParamBase.__init__(self, paramModel) # self.setUseParentModel(True) # self.setModel("/" + self.paramModel().type() + "List") - self.connect(self, Qt.SIGNAL("currentIndexChanged(int)"), - self.onCurrentIndexChanged) + self.currentIndexChanged.connect(self.onCurrentIndexChanged) def getValue(self): return str(self.currentText()) @@ -177,8 +172,7 @@ class LineEditParam(ParamBase, Qt.QLineEdit): def __init__(self, parent=None, paramModel=None): Qt.QLineEdit.__init__(self, parent) ParamBase.__init__(self, paramModel) - self.connect(self, Qt.SIGNAL( - "textChanged(const QString&)"), self.onTextChanged) + self.textChanged.connect(self.onTextChanged) def onTextChanged(self): self.onModelChanged() @@ -204,7 +198,7 @@ class CheckBoxParam(ParamBase, Qt.QCheckBox): def __init__(self, parent=None, paramModel=None): Qt.QCheckBox.__init__(self, parent) ParamBase.__init__(self, paramModel) - self.connect(self, Qt.SIGNAL("stateChanged(int)"), self.onStateChanged) + self.stateChanged.connect(self.onStateChanged) def getValue(self): return str(self.isChecked()) @@ -281,8 +275,7 @@ def __init__(self, parent=None, paramModel=None): self.text = "" - Qt.QObject.connect(self.button, Qt.SIGNAL( - "clicked()"), self._chooseAFile) + self.button.clicked.connect(self._chooseAFile) def _chooseAFile(self): path, _ = compat.getOpenFileName() @@ -324,9 +317,8 @@ def __init__(self, parent=None, paramModel=None): self.button.setText("...") self.layout.addWidget(self.button) - self.connect(self.button, Qt.SIGNAL("clicked()"), self.__chooseDirPath) - self.connect(self.dirPath, Qt.SIGNAL( - "textChanged(const QString&)"), self.onDirPathChanged) + self.button.clicked.connect(self.__chooseDirPath) + self.dirPath.textChanged.connect(self.onDirPathChanged) def onDirPathChanged(self): self.onModelChanged() From dcbbf5ff6ff1ed791a8c0b4f53e194872cef7d5c Mon Sep 17 00:00:00 2001 From: mrosanes Date: Fri, 11 Jan 2019 08:50:10 +0100 Subject: [PATCH 455/652] Use new style signals Use new style PyQt signals --- .../customeditors/senv.py | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py index 48c4987d87..0156307f33 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py @@ -52,8 +52,8 @@ def initComponents(self): self.nameComboBox.addItems( ["ActiveMntGrp", "ExtraColumns", "JsonRecorder", "ScanFile", "ScanDir"]) self.nameComboBox.setEditable(True) - self.connect(self.nameComboBox, Qt.SIGNAL( - "currentIndexChanged(int)"), self.onNameComboBoxChanged) + self.nameComboBox.currentIndexChanged.connect( + self.onNameComboBoxChanged) self.layout().addRow("name:", self.nameComboBox) nameIndex = self.model().index(0, 1, self.rootIndex()) @@ -150,14 +150,11 @@ def __init__(self, parent=None, paramModel=None): self.layout().addWidget(self.extraColumnsTable) - self.connect(addNewColumnButton, Qt.SIGNAL( - "clicked()"), self.onAddNewColumn) - self.connect(removeSelectedColumnsButton, Qt.SIGNAL( - "clicked()"), self.onRemoveSelectedColumns) - self.connect(self.extraColumnsModel, Qt.SIGNAL( - "dataChanged (const QModelIndex&,const QModelIndex&)"), self.onExtraColumnsChanged) - self.connect(self.extraColumnsModel, Qt.SIGNAL( - "modelReset()"), self.onExtraColumnsChanged) + addNewColumnButton.clicked.connect(self.onAddNewColumn) + removeSelectedColumnsButton.clicked.connect( + self.onRemoveSelectedColumns) + self.extraColumnsModel.dataChanged.connect(self.onExtraColumnsChanged) + self.extraColumnsModel.modelReset.connect(self.onExtraColumnsChanged) def getValue(self): return repr(self.extraColumnsTable.model().columns()) @@ -351,8 +348,7 @@ def setData(self, index, value=None, role=Qt.Qt.EditRole): self.__columns[row]['model'] = value elif column == 2: self.__columns[row]['instrument'] = value - self.emit( - Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index) + self.dataChanged.emit(index, index) return True return False From be0bc26b4bdd25c43986f9193d7a6e74209686b4 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 11 Jan 2019 08:58:57 +0100 Subject: [PATCH 456/652] Correcting bug: self.pool -> pool --- src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py b/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py index 2671ce8b9a..43749a6d6b 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py @@ -128,7 +128,7 @@ def setDataSource(self, pool): if self._data_src is not None: self._data_src.controllerClassesUpdated.disconnect(self.controllerClassesUpdated) if pool is not None: - self.pool.controllerClassesUpdated.connect(self.controllerClassesUpdated) + pool.controllerClassesUpdated.connect(self.controllerClassesUpdated) TaurusBaseModel.setDataSource(self, pool) def controllerClassesUpdated(self): From e1257f950277e0bed3f7835200ec9979ac880df9 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 11 Jan 2019 10:20:02 +0100 Subject: [PATCH 457/652] Correcting arguments --- src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py index d93f895446..33b18ba3ca 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py @@ -273,7 +273,7 @@ def getElementTypeToolTip(t): class BaseMntGrpChannelItem(TaurusBaseTreeItem): """ """ - dataChanged = Qt.pyqtSignal(const QModelIndex &, const QModelIndex &) + dataChanged = Qt.pyqtSignal('QModelIndex', 'QModelIndex') def data(self, index): """Returns the data of this node for the given index From 15fb7ee002214e095749522589ba5e5dfc919c65 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Fri, 11 Jan 2019 10:46:24 +0100 Subject: [PATCH 458/652] Use new style signals Use new style PyQt signals --- .../qt/qtgui/extra_macroexecutor/common.py | 43 +++++++++---------- .../qtgui/extra_macroexecutor/dooroutput.py | 14 +++--- .../qtgui/extra_macroexecutor/macroeditor.py | 23 +++++----- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py index 9ff779a4ff..292bc8778f 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py @@ -119,25 +119,27 @@ def selectMacro(self, macroName): index = self.findText(macroName) self.setCurrentIndex(index) if currentIdx == index: - self.emit(Qt.SIGNAL("currentIndexChanged(QString)"), macroName) + self.currentIndexChanged.emit(macroName) class TaurusMacroConfigurationDialog(Qt.QDialog): + macroserverNameChanged = Qt.pyqtSignal('QString') + doorNameChanged = Qt.pyqtSignal('QString') + def __init__(self, parent=None, initMacroServer=None, initDoor=None): Qt.QDialog.__init__(self, parent) self.initMacroServer = initMacroServer self.initDoor = initDoor configureAction = Qt.QAction(getThemeIcon( "folder-open"), "Change custom macro editors paths", self) - self.connect(configureAction, Qt.SIGNAL( - "triggered()"), self.onReloadMacroServers) + self.configureAction.triggered.connect(self.onReloadMacroServers) configureAction.setToolTip("Change custom macro editors paths") configureAction.setShortcut("F11") self.refreshMacroServersAction = Qt.QAction( getThemeIcon("view-refresh"), "Reload macroservers", self) - self.connect(self.refreshMacroServersAction, Qt.SIGNAL( - "triggered()"), self.onReloadMacroServers) + self.refreshMacroServersAction.triggered.connect( + self.onReloadMacroServers) self.refreshMacroServersAction.setToolTip( "This will reload list of all macroservers from Tango DB") self.refreshMacroServersAction.setShortcut("F5") @@ -171,20 +173,18 @@ def initComponents(self): self.layout().addWidget(self.buttonBox) self.adjustSize() - self.connect(self.buttonBox, Qt.SIGNAL( - "accepted()"), self, Qt.SLOT("accept()")) - self.connect(self.buttonBox, Qt.SIGNAL( - "rejected()"), self, Qt.SLOT("reject()")) - self.connect(self.macroServerComboBox, Qt.SIGNAL( - "currentIndexChanged(const QString&)"), self.onMacroServerComboBoxChanged) + self.buttonBox.accepted.connect(Qt.SLOT("accept()")) + self.buttonBox.rejected.connect(Qt.SLOT("reject()")) + self.macroServerComboBox.currentIndexChanged.connect( + self.onMacroServerComboBoxChanged) self.selectMacroServer(self.initMacroServer) self.selectDoor(self.initDoor) def accept(self): - self.emit(Qt.SIGNAL("macroserverNameChanged"), str( - self.macroServerComboBox.currentText())) - self.emit(Qt.SIGNAL("doorNameChanged"), str( - self.doorComboBox.currentText())) + self.macroserverNameChanged.emit( + str(self.macroServerComboBox.currentText())) + self.doorNameChanged.emit( + str(self.doorComboBox.currentText())) Qt.QDialog.accept(self) def __retriveMacroServersFromDB(self): @@ -252,6 +252,8 @@ def selectMacroServer(self, macroServerName): class MacroExecutionWindow(TaurusMainWindow): + doorChanged = Qt.pyqtSignal('QString') + def __init__(self, parent=None, designMode=False): TaurusMainWindow.__init__(self, parent, designMode) self.statusBar().showMessage("") @@ -273,7 +275,7 @@ def __init__(self, parent=None, designMode=False): self.addToolBar(toolBar) self.initComponents() self.splashScreen().finish(self) - self.connect(self, Qt.SIGNAL("doorChanged"), self.onDoorChanged) + self.doorChanged.connect(self.onDoorChanged) def doorName(self): return self._doorName @@ -310,8 +312,7 @@ def setModel(self, model): def createConfigureAction(self): configureAction = Qt.QAction(getThemeIcon( "preferences-system-session"), "Change configuration", self) - self.connect(configureAction, Qt.SIGNAL( - "triggered()"), self.changeConfiguration) + configureAction.triggered.connect(self.changeConfiguration) configureAction.setToolTip("Configuring MacroServer and Door") configureAction.setShortcut("F10") return configureAction @@ -319,8 +320,7 @@ def createConfigureAction(self): def createCustomMacroEditorPathsAction(self): configureAction = Qt.QAction(getThemeIcon( "folder-open"), "Change custom macro editors paths", self) - self.connect(configureAction, Qt.SIGNAL( - "triggered()"), self.onCustomMacroEditorPaths) + configureAction.triggered.connect(self.onCustomMacroEditorPaths) configureAction.setToolTip("Change custom macro editors paths") configureAction.setShortcut("F11") return configureAction @@ -333,8 +333,7 @@ def changeConfiguration(self): self, self.modelName, self.doorName()) if dialog.exec_(): self.setModel(str(dialog.macroServerComboBox.currentText())) - self.emit(Qt.SIGNAL("doorChanged"), str( - dialog.doorComboBox.currentText())) + self.doorChanged.emit(str(dialog.doorComboBox.currentText())) else: return diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py index 330eb5b62a..1da914e4aa 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py @@ -104,9 +104,8 @@ def contextMenuEvent(self, event): if not len(self.toPlainText()): clearAction.setEnabled(False) - Qt.QObject.connect(clearAction, Qt.SIGNAL("triggered()"), self.clear) - Qt.QObject.connect(self.stopAction, Qt.SIGNAL( - "toggled(bool)"), self.stopScrolling) + clearAction.triggered.connect(self.clear) + self.stopAction.toggled.connect(self.stopScrolling) menu.exec_(event.globalPos()) def stopScrolling(self, stop): @@ -143,9 +142,8 @@ def contextMenuEvent(self, event): if not len(self.toPlainText()): clearAction.setEnabled(False) - Qt.QObject.connect(clearAction, Qt.SIGNAL("triggered()"), self.clear) - Qt.QObject.connect(self.stopAction, Qt.SIGNAL( - "toggled(bool)"), self.stopScrolling) + clearAction.triggered.connect(self.clear) + self.stopAction.toggled.connect(self.stopScrolling) menu.exec_(event.globalPos()) def stopScrolling(self, stop): @@ -175,7 +173,7 @@ def contextMenuEvent(self, event): if not len(self.toPlainText()): clearAction.setEnabled(False) - Qt.QObject.connect(clearAction, Qt.SIGNAL("triggered()"), self.clear) + clearAction.triggered.connect(self.clear) menu.exec_(event.globalPos()) @@ -202,6 +200,7 @@ def eventReceived(self, src, type, value): return self.emit(Qt.SIGNAL('door%sChanged' % self.attrName), value.value) + if __name__ == "__main__": import sys import taurus @@ -213,6 +212,7 @@ def eventReceived(self, src, type, value): doorOutput = DoorOutput() if len(args) == 1: door = taurus.Device(args[0]) + Qt.QObject.connect(door, Qt.SIGNAL("outputUpdated"), doorOutput.onDoorOutputChanged) Qt.QObject.connect(door, Qt.SIGNAL("infoUpdated"), diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py index 35e8933f36..42f3bd4eaa 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py @@ -49,37 +49,36 @@ def __init__(self, parent=None, designMode=False): self.textEdit.setLexer(self.pythonLexer) self.newAction = Qt.QAction(getThemeIcon("document-new"), "New", self) - self.connect(self.newAction, Qt.SIGNAL("triggered()"), self.newFile) + self.newAction.triggered.connect(self.newFile) self.newAction.setToolTip("Create new file") self.newAction.setShortcut("Ctrl+N") self.openAction = Qt.QAction( getThemeIcon("document-open"), "Open", self) - self.connect(self.openAction, Qt.SIGNAL("triggered()"), self.openFile) + self.openAction.triggered.connect(self.openFile) self.openAction.setToolTip("Open existing file") self.openAction.setShortcut("Ctrl+O") self.saveAction = Qt.QAction( getThemeIcon("document-save"), "Save", self) - self.connect(self.saveAction, Qt.SIGNAL("triggered()"), self.saveFile) + self.saveAction.triggered.connect(self.saveFile) self.saveAction.setToolTip("Save document to disk") self.saveAction.setShortcut("Ctrl+S") self.saveAsAction = Qt.QAction(getThemeIcon( "document-save-as"), "Save as...", self) - self.connect(self.saveAsAction, Qt.SIGNAL( - "triggered()"), self.saveFile) + self.saveAction.triggered.connect(self.saveFile) self.saveAsAction.setToolTip("Save document under a new name") self.cutAction = Qt.QAction(getThemeIcon("edit-cut"), "Cut", self) - self.connect(self.cutAction, Qt.SIGNAL("triggered()"), self.cut) + self.cutAction.triggered.connect(self.cut) self.cutAction.setToolTip( "Cut current selection's contents to the clipboard") self.cutAction.setShortcut("Ctrl+X") self.cutAction.setEnabled(False) self.copyAction = Qt.QAction(getThemeIcon("edit-copy"), "Copy", self) - self.connect(self.copyAction, Qt.SIGNAL("triggered()"), self.copy) + self.copyAction.triggered.connect(self.copy) self.copyAction.setToolTip( "Copy current selection's contents to the clipboard") self.copyAction.setShortcut("Ctrl+C") @@ -87,19 +86,17 @@ def __init__(self, parent=None, designMode=False): self.pasteAction = Qt.QAction( getThemeIcon("edit-paste"), "Paste", self) - self.connect(self.pasteAction, Qt.SIGNAL("triggered()"), self.paste) + self.pasteAction.triggered.connect(self.paste) self.pasteAction.setToolTip( "Paste the clipboard's contents into the current selection") self.pasteAction.setShortcut("Ctrl+V") self.aboutAction = Qt.QAction("About", self) - self.connect(self.aboutAction, Qt.SIGNAL("triggered()"), self.about) + self.aboutAction.triggered.connect(self.about) self.aboutAction.setToolTip("Show the application's About box") - self.connect(self.textEdit, Qt.SIGNAL( - "copyAvailable(bool)"), self.cutAction.setEnabled) - self.connect(self.textEdit, Qt.SIGNAL( - "copyAvailable(bool)"), self.copyAction.setEnabled) + self.textEdit.copyAvailable.connect(self.cutAction.setEnabled) + self.textEdit.copyAvailable.connect(self.copyAction.setEnabled) self.setCurrentFile("") From d1dffc948a63390fbe811292faea5246185d8545 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Fri, 11 Jan 2019 11:05:30 +0100 Subject: [PATCH 459/652] Use new style signals Use new style PyQt signals --- src/sardana/taurus/qt/qtgui/extra_pool/poolchannel.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolchannel.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolchannel.py index 626cee2972..1fb5d01af4 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolchannel.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolchannel.py @@ -115,8 +115,7 @@ def __init__(self, parent=None, designMode=False): self._devButton.setText('') self.layout().addWidget(self._devButton) - self.connect(self, Qt.SIGNAL( - 'modelChanged(const QString &)'), self._updateTaurusValue) + self.modelChanged.connect(self._updateTaurusValue) def _updateTaurusValue(self): m = self.getModelName() From 8a604ff79b9eeb59c596319197f6e86c0068a763 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Fri, 11 Jan 2019 11:11:09 +0100 Subject: [PATCH 460/652] Use new style signals Use new style PyQt signals --- src/sardana/taurus/qt/qtgui/extra_pool/poolioregister.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolioregister.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolioregister.py index 4cce82b180..5a95b4d6d6 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolioregister.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolioregister.py @@ -248,7 +248,7 @@ def setModel(self, model): # Empty previous buttons # self.ui.lo_buttons_write. for button in self.button_value_dict.keys(): - self.disconnect(button, Qt.SIGNAL('clicked'), self.writeValue) + self.button.clicked.disconnect(self.writeValue) button.deleteLater() self.button_value_dict = {} @@ -260,7 +260,7 @@ def setModel(self, model): button = Qt.QPushButton(label) self.button_value_dict[button] = value self.ui.lo_buttons_write.addWidget(button) - self.connect(button, Qt.SIGNAL('clicked()'), self.writeValue) + self.button.clicked.connect(self.writeValue) def writeValue(self): if self.ioreg_dev is None: From cd858a7019cb8cebb756d103609dbc61560d22c6 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 11 Jan 2019 11:36:11 +0100 Subject: [PATCH 461/652] Correcting call to functions --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index dac7d90b11..05c4f9a6c2 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -222,9 +222,9 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.onPathLEEdited) self.ui.filenameLE.textEdited.connect( self.onFilenameLEEdited) - self.ui.channelEditor.getQModel.dataChanged.connect( + self.ui.channelEditor.getQModel().dataChanged.connect( self._updateButtonBox) - self.ui.channelEditor.getQModel.modelReset.connect( + self.ui.channelEditor.getQModel().modelReset.connect( self._updateButtonBox) preScanList = self.ui.preScanList preScanList.dataChanged.connect( From ee2fc2da831a81984ce01d60f28772024c2809da Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 11 Jan 2019 12:10:29 +0100 Subject: [PATCH 462/652] Use new style signals --- .../taurus/qt/qtgui/extra_hkl/computeu.py | 3 +- .../extra_hkl/diffractometeralignment.py | 21 +++++--------- .../taurus/qt/qtgui/extra_hkl/hklscan.py | 15 ++++------ .../qt/qtgui/extra_hkl/reflectionseditor.py | 4 +-- .../taurus/qt/qtgui/extra_hkl/selectsignal.py | 3 +- .../taurus/qt/qtgui/extra_hkl/ubmatrix.py | 29 +++++++------------ 6 files changed, 26 insertions(+), 49 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/computeu.py b/src/sardana/taurus/qt/qtgui/extra_hkl/computeu.py index efd984cd04..2134d98d9c 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/computeu.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/computeu.py @@ -42,8 +42,7 @@ def __init__(self, parent=None, designMode=False): self.loadUi(filename="computeu.ui") - self.connect(self._ui.ComputeButton, Qt.SIGNAL( - "clicked()"), self.compute_u) + self._ui.ComputeButton.clicked().connect(self.compute_u) @classmethod def getQtDesignerPluginInfo(cls): diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py b/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py index 3b86002ffc..0c564ae6ae 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py @@ -79,16 +79,12 @@ def __init__(self, parent=None, designMode=False): self.selectsignal = SelectSignal() - self.connect(self._ui.AlignmentStopButton, - Qt.SIGNAL("clicked()"), self.stop_movements) - self.connect(self._ui.AlignmentStoreReflectionButton, - Qt.SIGNAL("clicked()"), self.store_reflection) + self._ui.AlignmentStopButton.clicked.connect(self.stop_movements) + self._ui.AlignmentStoreReflectionButton.clicked.connect(self.store_reflection) - self.connect(self._ui.MacroServerConnectionButton, Qt.SIGNAL( - "clicked()"), self.open_macroserver_connection_panel) + self._ui.MacroServerConnectionButton.clicked.connect(self.open_macroserver_connection_panel) - self.connect(self._ui.SelectSignalButton, Qt.SIGNAL( - "clicked()"), self.open_selectsignal_panel) + self._ui.SelectSignalButton.clicked.connect(self.open_selectsignal_panel) # Create a global SharedDataManager Qt.qApp.SDM = SharedDataManager(self) @@ -203,8 +199,7 @@ def setModel(self, model): self.enginemodescombobox.loadEngineModeNames(self.device.hklmodelist) - self.connect(self.enginemodescombobox, Qt.SIGNAL( - "currentIndexChanged(QString)"), self.onModeChanged) + self.enginemodescombobox.currentIndexChanged.connect(self.onModeChanged) # Add dynamically the scan buttons, range inputs and 'to max' buttons @@ -229,8 +224,7 @@ def setModel(self, model): scan_buttons[i].setText(QtGui.QApplication.translate( "DiffractometerAlignment", self.angles_names[i], None, QtGui.QApplication.UnicodeUTF8)) - self.connect(scan_buttons[i], Qt.SIGNAL( - "clicked()"), exec_functions[i]) + scan_buttons[i].clicked.connect(exec_functions[i]) self.range_inputs.append(QtGui.QLineEdit(self)) self.range_inputs[i].setGeometry( @@ -247,8 +241,7 @@ def setModel(self, model): self.tomax_buttons[i].setText(QtGui.QApplication.translate( "DiffractometerAlignment", 'n.n.', None, QtGui.QApplication.UnicodeUTF8)) - self.connect(self.tomax_buttons[i], Qt.SIGNAL( - "clicked()"), tomax_functions[i]) + self.tomax_buttons[i].clicked().connect(tomax_functions[i]) def exec_scan1(self): self.exec_scan(0) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py b/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py index 0d6519d986..c1064ff548 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py @@ -75,14 +75,10 @@ def __init__(self, parent=None, designMode=False): self.loadUi(filename="hklscan.ui") - self.connect(self._ui.hklStartScanButton, - Qt.SIGNAL("clicked()"), self.start_hklscan) - self.connect(self._ui.hklStopScanButton, - Qt.SIGNAL("clicked()"), self.stop_hklscan) - self.connect(self._ui.hklDisplayAnglesButton, - Qt.SIGNAL("clicked()"), self.display_angles) - self.connect(self._ui.MacroServerConnectionButton, Qt.SIGNAL( - "clicked()"), self.open_macroserver_connection_panel) + self._ui.hklStartScanButton.clicked.connect(self.start_hklscan) + self._ui.hklStopScanButton.clicked.connectself.stop_hklscan) + self._ui.hklDisplayAnglesButton.clicked.connectself.display_angles) + self._ui.MacroServerConnectionButton.clicked.connect(self.open_macroserver_connection_panel) # Create a global SharedDataManager Qt.qApp.SDM = SharedDataManager(self) @@ -182,8 +178,7 @@ def setModel(self, model): self.enginemodescombobox.loadEngineModeNames(self.device.hklmodelist) - self.connect(self.enginemodescombobox, Qt.SIGNAL( - "currentIndexChanged(QString)"), self.onModeChanged) + self.enginemodescombobox.currentIndexChanged.connect(self.onModeChanged) def onModeChanged(self, modename): if self.device.engine != "hkl": diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/reflectionseditor.py b/src/sardana/taurus/qt/qtgui/extra_hkl/reflectionseditor.py index 3ffbd97951..e5b470a35f 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/reflectionseditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/reflectionseditor.py @@ -44,8 +44,8 @@ def __init__(self, parent=None, designMode=False): self.loadUi(filename="reflectionseditor.ui") - self.connect(self._ui.ApplyButton, Qt.SIGNAL("clicked()"), self.apply) - self.connect(self._ui.ClearButton, Qt.SIGNAL("clicked()"), self.clear) + self._ui.ApplyButton.clicked.connect(self.apply) + self._ui.ClearButton.clicked.connect(self.clear) @classmethod def getQtDesignerPluginInfo(cls): diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py index d87ef5da6d..81cd0737dc 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py @@ -69,8 +69,7 @@ def __init__(self, parent=None, designMode=False): self.signalComboBox.setGeometry(QtCore.QRect(70, 50, 161, 27)) self.signalComboBox.setObjectName("SignalcomboBox") - self.connect(self.signalComboBox, Qt.SIGNAL( - "currentIndexChanged(QString)"), self.onSignalChanged) + self.signalComboBox.currentIndexChanged.connect(self.onSignalChanged) self.doorName = None self.door_device = None diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py b/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py index 8887fcec3a..d9e1ea816d 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py @@ -74,19 +74,13 @@ def __init__(self, parent=None, designMode=False): self.loadUi(filename="ubmatrix.ui") - self.connect(self._ui.UpdateButton, Qt.SIGNAL( - "clicked()"), self.update_values) - self.connect(self._ui.ComputeUButton, - Qt.SIGNAL("clicked()"), self.compute_ub) - self.connect(self._ui.ReflectionsListButton, Qt.SIGNAL( - "clicked()"), self.reflections_list_window) - self.connect(self._ui.EditReflectionsButton, Qt.SIGNAL( - "clicked()"), self.edit_reflections_window) - self.connect(self._ui.AffineButton, - Qt.SIGNAL("clicked()"), self.affine) - self.connect(self._ui.AddCrystalButton, Qt.SIGNAL( - "clicked()"), self.add_select_crystal) -# self.connect(self._ui.alattice_value, Qt.SIGNAL("textEdited()"), self.on_alattice_value_textEdited) + self._ui.UpdateButton.clicked.connect(self.update_values) + self._ui.ComputeUButton.clicked.connect(self.compute_ub) + self._ui.ReflectionsListButton.clicked.connect(self.reflections_list_window) + self._ui.EditReflectionsButton.clicked.connect(self.edit_reflections_window) + self._ui.AffineButton.clicked.connect(self.affine) + self._ui.AddCrystalButton.clicked.connect(self.add_select_crystal) +# self._ui.alattice_value.textEdited.connect(self.on_alattice_value_textEdited) # Funciona con puro QEditValue pero no con TaurusQEdit ... @classmethod @@ -157,8 +151,7 @@ def setModel(self, model): self.enginescombobox.loadItems(self.device.enginelist) - self.connect(self.enginescombobox, Qt.SIGNAL( - "currentIndexChanged(QString)"), self.onEngineChanged) + self.enginescombobox.currentIndexChanged.connect(self.onEngineChanged) enginemodemodel = model + '/enginemode' self._ui.taurusLabelEngineMode.setModel(enginemodemodel) @@ -169,8 +162,7 @@ def setModel(self, model): self.enginemodescombobox.loadItems(self.device.enginemodelist) - self.connect(self.enginemodescombobox, Qt.SIGNAL( - "currentIndexChanged(QString)"), self.onModeChanged) + self.enginemodescombobox.currentIndexChanged.connect(self.onModeChanged) # Set model to crystal @@ -183,8 +175,7 @@ def setModel(self, model): self.crystalscombobox.loadItems(self.device.crystallist) - self.connect(self.crystalscombobox, Qt.SIGNAL( - "currentIndexChanged(QString)"), self.onCrystalChanged) + self.crystalscombobox.currentIndexChanged.connect(self.onCrystalChanged) def onEngineChanged(self, enginename): self.device.write_attribute("engine", str(enginename)) From bc627f35e52e7cd2a59ff65c72095a0e00dd8061 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 11 Jan 2019 14:45:21 +0100 Subject: [PATCH 463/652] Implementing default timer and adding it to dummy ct --- src/sardana/pool/poolbasechannel.py | 8 ++++---- .../pool/poolcontrollers/DummyCounterTimerController.py | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index b6045a91af..6221a9d50b 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -339,7 +339,7 @@ def create_config(self): self.conf_ctrl.timer = channel else: if self.timer == "__default": - self.conf_timer = ChannelConfiguration(self.pool.get_element_by_axis(self.default_axis)) + self.conf_timer = ChannelConfiguration(ctrl.get_element(axis=ctrl.get_ctrl_par("default_timer"))) else: self.conf_timer = ChannelConfiguration(self.pool.get_element_by_name(self.timer)) self.conf_ctrl.add_channel(self.conf_timer) @@ -352,7 +352,7 @@ def create_config(self): comp_self = "__self" if self.timer != "__self": if self.timer == "__default": - self.acquisition.add_element(self.pool.get_element_by_axis(self.default_axis)) + self.acquisition.add_element(ctrl.get_element(axis=ctrl.get_ctrl_par("default_timer"))) else: self.acquisition.add_element(self.pool.get_element_by_name(self.timer)) @@ -386,7 +386,7 @@ def set_timer(self, timer, propagate=1): if timer == "__default": try: ctrl = self.get_controller() - self.default_axis = ctrl.defaut_axis + self.default_timer_axis = ctrl.get_ctrl_par("default_timer") except: raise ValueError("Not default axis in controller") return @@ -396,7 +396,7 @@ def set_timer(self, timer, propagate=1): if timer != "__default": self.acquisition.remove_element(self.pool.get_element_by_name(timer)) else: - self.acquisition.remove_element(self.pool.get_element_by_axis(default_axis)) + self.acquisition.remove_element(ctrl.get_element(axis = self.default_timer_axis)) except: # The new timer does not belong to action pass diff --git a/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py b/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py index 94b4a7bdda..bea122f45e 100644 --- a/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py +++ b/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py @@ -64,11 +64,12 @@ class DummyCounterTimerController(CounterTimerController): TimerMode = 1 MonitorMode = 2 CounterMode = 3 - + def __init__(self, inst, props, *args, **kwargs): CounterTimerController.__init__(self, inst, props, *args, **kwargs) self._synchronization = AcqSynch.SoftwareTrigger self._latency_time = 0 + self._default_timer = 1 self.channels = self.MaxDevice * [None, ] self.reset() @@ -265,6 +266,8 @@ def GetCtrlPar(self, par): return self._synchronization elif par == 'latency_time': return self._latency_time + elif par == 'default_timer': + return self._default_timer def SetCtrlPar(self, par, value): if par == 'synchronization': @@ -272,3 +275,5 @@ def SetCtrlPar(self, par, value): for channel in self.channels: if channel: channel.mode = value + elif par == 'default_timer': + self._default_timer = value From 2860632af3879dd4e235368629f83002b4f6ab69 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Fri, 11 Jan 2019 15:12:01 +0100 Subject: [PATCH 464/652] Use new style signals Use new style PyQt signals --- .../qtgui/extra_macroexecutor/macrobutton.py | 86 +++++++++---------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py index 06717297a2..11c899abbc 100755 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py @@ -53,11 +53,13 @@ class DoorStateListener(Qt.QObject): __pyqtSignals__ = ["doorStateChanged"] + doorStateChanged = Qt.pyqtSignal(object) + def eventReceived(self, evt_src, evt_type, evt_value): if evt_type not in (TaurusEventType.Change, TaurusEventType.Periodic): return door_state = evt_value.value - self.emit(Qt.SIGNAL('doorStateChanged'), door_state) + self.doorStateChanged.emit(door_state) @UILoadable(with_ui='ui') @@ -72,6 +74,9 @@ class MacroButton(TaurusWidget): __pyqtSignals__ = ['statusUpdated', 'resultUpdated'] + statusUpdated = Qt.pyqtSignal(object) + resultUpdated = Qt.pyqtSignal(object) + def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) self.loadUi() @@ -85,8 +90,7 @@ def __init__(self, parent=None, designMode=False): self.ui.progress.setValue(0) self.ui.button.setCheckable(True) - self.connect(self.ui.button, Qt.SIGNAL('clicked()'), - self._onButtonClicked) + self.ui.button.clicked.connect(self._onButtonClicked) # Override default implementation of handleEvent from TaurusWidget # in order to avoid button's text being lost on the MS restart. @@ -113,16 +117,14 @@ def setModel(self, model): ''' TaurusWidget.setModel(self, model) if self.door is not None: - self.disconnect(self.door, Qt.SIGNAL( - 'macroStatusUpdated'), self._statusUpdated) - self.disconnect(self.door, Qt.SIGNAL( - 'resultUpdated'), self._resultUpdated) + self.door.macroStatusUpdated.disconnect(self._statusUpdated) + self.door.resultUpdated.disconnect(self._resultUpdated) # disable management of Door Tango States self.door.getAttribute('State').removeListener( self.door_state_listener) - self.disconnect(self.door_state_listener, Qt.SIGNAL( - 'doorStateChanged'), self._doorStateChanged) + self.door_state_listener.doorStateChanged.disconnect( + self._doorStateChanged) self.door_state_listener = None try: @@ -130,15 +132,13 @@ def setModel(self, model): except: return - self.connect(self.door, Qt.SIGNAL( - 'macroStatusUpdated'), self._statusUpdated) - self.connect(self.door, Qt.SIGNAL( - 'resultUpdated'), self._resultUpdated) + self.door.macroStatusUpdated.connect(self._statusUpdated) + self.door.resultUpdated.connect(self._resultUpdated) # Manage Door Tango States self.door_state_listener = DoorStateListener() - self.connect(self.door_state_listener, Qt.SIGNAL( - 'doorStateChanged'), self._doorStateChanged) + self.door_state_listener.doorStateChanged.connect( + self._doorStateChanged) self.door.getAttribute('State').addListener(self.door_state_listener) def _doorStateChanged(self, state): @@ -191,7 +191,7 @@ def _statusUpdated(self, *args): if state in ['stop', 'abort', 'finish', 'alarm']: self.ui.button.setChecked(False) - self.emit(Qt.SIGNAL('statusUpdated'), status_dict) + self.statusUpdated.emit(status_dict) def _resultUpdated(self, *args): '''slot called on result changes''' @@ -201,7 +201,7 @@ def _resultUpdated(self, *args): if self.running_macro is None: return result = self.running_macro.getResult() - self.emit(Qt.SIGNAL('resultUpdated'), result) + self.resultUpdated.emit(result) def setText(self, text): '''set the button text @@ -253,19 +253,20 @@ def updateMacroArgumentFromSignal(self, index, obj, signal): functools.partial(self.updateMacroArgument, index)) def connectArgEditors(self, signals): - '''Associate signals to argument changes. - - :param signals: (seq) An ordered sequence of (`obj`, `sig`) - tuples , where `obj` is a parameter editor object and - `sig` is a signature for a signal emitted by `obj` which - provides the value of a parameter as its argument. - Each (`obj`, `sig`) tuple is associated to parameter - corresponding to its position in the `signals` sequence. - ''' - - for i, (obj, sig) in enumerate(signals): - self.connect(obj, Qt.SIGNAL(sig), - functools.partial(self.updateMacroArgument, i)) + """ + Associate signals to argument changes. + + :param signals: (seq) An ordered sequence of signals + """ + _pyqtsignals = [] + for i, signal in enumerate(signals): + # TODO: if possible, better check that this is not a pyqtsignal + if isinstance(signal, (tuple, list, set)): + obj, sig = signal + msg = "Old style PyQt signals is deprecated: %s" + self.deprecated(msg) + signal = getattr(obj, sig.split('(')[0]) + signal.connect(functools.partial(self.updateMacroArgument, i)) def _onButtonClicked(self): if self.ui.button.isChecked(): @@ -343,7 +344,7 @@ def __init__(self, parent=None, designMode=False): self.setText('Abort') self.setToolTip('Abort Macro') - self.connect(self, Qt.SIGNAL('clicked()'), self.abort) + self.clicked.connect(self.abort) def getModelClass(self): '''reimplemented from :class:`TaurusBaseWidget`''' @@ -479,10 +480,10 @@ def create_layout(self, macro_name): self.w_bottom.layout().addWidget(mb_abort, 3, 1) # Toggle progressbar - Qt.QObject.connect(self.show_progress, Qt.SIGNAL( - 'stateChanged(int)'), self.toggle_progress) + self.show_progress.stateChanged.connect(self.toggle_progress) # connect the argument editors - signals = [(e, 'textChanged(QString)') for e in _argEditors] + # signals = [(e, 'textChanged(QString)') for e in _argEditors] + signals = [getattr(e, 'textChanged') for e in _argEditors] self.mb.connectArgEditors(signals) self.setLayout(Qt.QVBoxLayout()) @@ -490,17 +491,12 @@ def create_layout(self, macro_name): self.layout().addWidget(self.w_bottom) # Update possible macro result - Qt.QObject.connect(self.mb, Qt.SIGNAL( - 'resultUpdated'), self.update_result) - - Qt.QObject.connect(self.w_macro_name, Qt.SIGNAL( - 'textEdited(QString)'), self.update_macro_name) - Qt.QObject.connect(self.w_macro_name, Qt.SIGNAL( - 'editingFinished()'), self.update_layout) - Qt.QObject.connect(self.w_macro_name, Qt.SIGNAL( - 'textChanged(QString)'), self.mb.setMacroName) - Qt.QObject.connect(self.w_macro_name, Qt.SIGNAL( - 'textChanged(QString)'), self.mb.setButtonText) + self.mb.resultUpdated.connect(self.update_result) + + self.w_macro_name.textEdited.connect(self.update_macro_name) + self.w_macro_name.editingFinished.connect(self.update_layout) + self.w_macro_name.textChanged.connect(self.mb.setMacroName) + self.w_macro_name.textChanged.connect(self.mb.setButtonText) # Since everything is now connected, the parameters will be updated self.w_macro_name.setText(macro_name) From fde24f1c83aaeeb51ba9a0dd5988f9d7af8a53ef Mon Sep 17 00:00:00 2001 From: mrosanes Date: Fri, 11 Jan 2019 16:21:31 +0100 Subject: [PATCH 465/652] Use new style signals Use new style PyQt signals --- .../extra_macroexecutor/macroexecutor.py | 77 +++++++++---------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index 93f1b057a3..0dc8125734 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -58,6 +58,12 @@ def __init__(self, parent=None): class SpockCommandWidget(Qt.QLineEdit, TaurusBaseContainer): + pressedReturn = Qt.pyqtSignal() + spockComboBox = Qt.pyqtSignal(str) + elementUp = Qt.pyqtSignal() + elementDown = Qt.pyqtSignal() + setHistoryFocus = Qt.pyqtSignal() + def __init__(self, name, parent=None, designMode=False): # self.newValue - is used as a flag to indicate whether a controlUp controlDown actions are used to iterate existing element or put new one # self.disableEditMode - flag, used to disable edition, when user enters name of the macro which is not valid (not allowed to edit in the yellow line) @@ -80,9 +86,8 @@ def __init__(self, name, parent=None, designMode=False): self.setEnabled(False) self.setActions() - self.connect(self, Qt.SIGNAL( - "textChanged(const QString &)"), self.textChanged) - self.connect(self, Qt.SIGNAL("returnPressed()"), self.returnPressed) + self.textChanged.connect(self.textChanged) + self.returnPressed.connect(self.returnPressed) def setActions(self): self._downAction = Qt.QAction("downAction", self) @@ -106,13 +111,10 @@ def setActions(self): self.addAction(self._ctrlUpAction) self.addAction(self._downAction) self.addAction(self._upAction) - self.connect(self._downAction, Qt.SIGNAL( - "triggered()"), self.downAction) - self.connect(self._upAction, Qt.SIGNAL("triggered()"), self.upAction) - self.connect(self._ctrlDownAction, Qt.SIGNAL( - "triggered()"), self.controlDownAction) - self.connect(self._ctrlUpAction, Qt.SIGNAL( - "triggered()"), self.controlUpAction) + self._downAction.triggered.connect(self.downAction) + self._upAction.triggered.connect(self.upAction) + self._ctrlDownAction.triggered.connect(self.controlDownAction) + self._ctrlUpAction.triggered.connect(self.controlUpAction) def setCommand(self): command = self._model.toSpockCommand().strip() @@ -636,23 +638,19 @@ def __init__(self, parent=None, designMode=False): self.addToFavouritesAction = Qt.QAction(getThemeIcon( "software-update-available"), "Add to favourites", self) - self.connect(self.addToFavouritesAction, Qt.SIGNAL( - "triggered()"), self.onAddToFavourites) + self.addToFavouritesAction.triggered.connect(self.onAddToFavourites) self.addToFavouritesAction.setToolTip("Add to favourites") self.stopMacroAction = Qt.QAction( getIcon(":/actions/media_playback_stop.svg"), "Stop macro", self) - self.connect(self.stopMacroAction, Qt.SIGNAL( - "triggered()"), self.onStopMacro) + self.stopMacroAction.triggered.connect(self.onStopMacro) self.stopMacroAction.setToolTip("Stop macro") self.pauseMacroAction = Qt.QAction( getIcon(":/actions/media_playback_pause.svg"), "Pause macro", self) - self.connect(self.pauseMacroAction, Qt.SIGNAL( - "triggered()"), self.onPauseMacro) + self.pauseMacroAction.triggered.connect(self.onPauseMacro) self.pauseMacroAction.setToolTip("Pause macro") self.playMacroAction = Qt.QAction( getIcon(":/actions/media_playback_start.svg"), "Start macro", self) - self.connect(self.playMacroAction, Qt.SIGNAL( - "triggered()"), self.onPlayMacro) + self.playMacroAction.triggered.connect(self.onPlayMacro) self.playMacroAction.setToolTip("Start macro") actionsLayout = Qt.QHBoxLayout() actionsLayout.setContentsMargins(0, 0, 0, 0) @@ -731,25 +729,20 @@ def __init__(self, parent=None, designMode=False): # spockCommandLayout.addWidget(spockCommandLabel) spockCommandLayout.addWidget(self.spockCommand) self.layout().addLayout(spockCommandLayout) - self.connect(self.macroComboBox, Qt.SIGNAL( - "currentIndexChanged(QString)"), self.onMacroComboBoxChanged) - self.connect(self.favouritesMacrosEditor.list, Qt.SIGNAL( - "favouriteSelected"), self.onFavouriteSelected) - self.connect(self.historyMacrosViewer.list, Qt.SIGNAL( - "historySelected"), self.onHistorySelected) - - self.connect(self.spockCommand, Qt.SIGNAL( - "pressedReturn"), self.onPlayMacro) - self.connect(self.spockCommand, Qt.SIGNAL( - "spockComboBox"), self.setComboBoxItem) - self.connect(self.spockCommand, Qt.SIGNAL( - "elementUp"), self.setHistoryUp) - self.connect(self.spockCommand, Qt.SIGNAL( - "elementDown"), self.setHistoryDown) - self.connect(self.spockCommand, Qt.SIGNAL( - "setHistoryFocus"), self.setHistoryFocus) - self.connect(self.spockCommand, Qt.SIGNAL("expandTree"), - self.standardMacroParametersEditor.tree.expandAll) + + self.macroComboBox.currentIndexChanged.connect( + self.onMacroComboBoxChanged) + self.favouritesMacrosEditor.list.favouriteSelected.connect( + self.onFavouriteSelected) + self.historyMacrosViewer.list.historySelected.connect( + self.onHistorySelected) + + self.spockCommand.pressedReturn.connect(self.onPlayMacro) + self.spockCommand.spockComboBox.connect(self.setComboBoxItem) + self.spockCommand.elementUp.connect(self.setHistoryUp) + self.spockCommand.elementDown.connect(self.setHistoryDown) + self.spockCommand.expandTree( + self.standardMacroParametersEditor.tree.expandAll) def macroId(self): return self._macroId @@ -1071,18 +1064,18 @@ def setCustomMacroEditorPaths(self, customMacroEditorPaths): def loadSettings(self): TaurusMainWindow.loadSettings(self) - self.emit(Qt.SIGNAL("doorChanged"), self.doorName()) + self.doorChanged.emit(self.doorName()) def onDoorChanged(self, doorName): MacroExecutionWindow.onDoorChanged(self, doorName) if self._qDoor: - Qt.QObject.disconnect(self._qDoor, Qt.SIGNAL( - "macroStatusUpdated"), self.taurusMacroExecutorWidget.onMacroStatusUpdated) + self._qDoor.macroStatusUpdated.disconnect( + self.taurusMacroExecutorWidget.onMacroStatusUpdated) if doorName == "": return self._qDoor = Device(doorName) - Qt.QObject.connect(self._qDoor, Qt.SIGNAL( - "macroStatusUpdated"), self.taurusMacroExecutorWidget.onMacroStatusUpdated) + self._qDoor.macroStatusUpdated.connect( + self.taurusMacroExecutorWidget.onMacroStatusUpdated) self.taurusMacroExecutorWidget.onDoorChanged(doorName) @classmethod From 37db27fe307ea8d66d2a23c7cb38cbaa79950669 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Fri, 11 Jan 2019 16:57:22 +0100 Subject: [PATCH 466/652] Use new style signals Use new style PyQt signals --- src/sardana/taurus/qt/qtgui/extra_pool/motor.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/motor.py b/src/sardana/taurus/qt/qtgui/extra_pool/motor.py index 3ee2c21a21..f1d3c0521b 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/motor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/motor.py @@ -53,8 +53,7 @@ def __init__(self, parent=None, designMode=False): self.call__init__(TaurusBaseWidget, str( self.objectName()), designMode=designMode) self.loadUi() - Qt.QObject.connect(self.ui.config, Qt.SIGNAL( - "clicked()"), self.configureMotor) + self.ui.config.clicked.connect(self.configureMotor) def sizeHint(self): return Qt.QSize(330, 50) @@ -112,8 +111,7 @@ def __init__(self, parent=None, designMode=False): self.call__init__(TaurusBaseWidget, str( self.objectName()), designMode=designMode) self.loadUi() - Qt.QObject.connect(self.ui.config, Qt.SIGNAL( - "clicked()"), self.configureMotor) + self.ui.config.clicked.connect(self.configureMotor) def sizeHint(self): return Qt.QSize(215, 85) @@ -171,8 +169,7 @@ def __init__(self, parent=None, designMode=False): self.call__init__(TaurusBaseWidget, str( self.objectName()), designMode=designMode) self.loadUi() - Qt.QObject.connect(self.ui.config, Qt.SIGNAL( - "clicked()"), self.configureMotor) + self.ui.config.clicked.connect(self.configureMotor) def sizeHint(self): return Qt.QSize(120, 145) From f1e1c0b2484646ee5267697230547c2d7cd82359 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Fri, 11 Jan 2019 17:22:04 +0100 Subject: [PATCH 467/652] Use new style signals Use new style PyQt signals --- .../extra_macroexecutor/macroexecutor.py | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index 0dc8125734..9b08521e03 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -63,6 +63,7 @@ class SpockCommandWidget(Qt.QLineEdit, TaurusBaseContainer): elementUp = Qt.pyqtSignal() elementDown = Qt.pyqtSignal() setHistoryFocus = Qt.pyqtSignal() + expandTree = Qt.pyqtSignal() def __init__(self, name, parent=None, designMode=False): # self.newValue - is used as a flag to indicate whether a controlUp controlDown actions are used to iterate existing element or put new one @@ -314,7 +315,7 @@ def validateAllExpresion(self, secValidation=False): index = self.findParamRepeat(i) self.currentIndex = self.model()._insertRow(index) nn = self.model().nodeFromIndex(self.currentIndex) - self.emit(Qt.SIGNAL("expandTree")) + self.expandTree.emit() ix = self.getIndex() if not secValidation: self.validateAllExpresion(True) @@ -375,7 +376,7 @@ def validateOneValue(self, value): def returnPressed(self): # SLOT called when return is pressed if self.toolTip() == "": - self.emit(Qt.SIGNAL("pressedReturn")) + self.pressedReturn.emit() else: raise Exception( "Cannot start macro. Please correct following mistakes:
    " + self.toolTip()) @@ -431,7 +432,7 @@ def downAction(self): # line when model is changed. (when new row in history is chosen) self.disableSpockCommandUpdate = False - self.emit(Qt.SIGNAL("elementDown")) + self.elementDown.emit() text = str(self.text()).split() if len(text) > 0: self.validateMacro(text[0]) @@ -439,7 +440,7 @@ def downAction(self): def upAction(self): self.disableSpockCommandUpdate = False - self.emit(Qt.SIGNAL("elementUp")) + self.elementUp.emit() text = str(self.text()).split() if len(text) > 0: self.validateMacro(text[0]) @@ -601,7 +602,7 @@ def updateMacroEditor(self, macroName): # I had to make the macroname lowered as macros in comboBox (with macros), has names with all letter low. # Because of that sometimes it was not loading macros in MacroEditor # TO FIX - self.emit(Qt.SIGNAL("spockComboBox"), str(macroName).lower()) + self.spockComboBox.emit(str(macroName).lower()) def measureSelection(self, position): s = str(self.text()) + " " @@ -627,6 +628,8 @@ def focusOutEvent(self, event): class TaurusMacroExecutorWidget(TaurusWidget): + doorChanged = Qt.pyqtSignal('QString') + def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) self.setObjectName(self.__class__.__name__) @@ -741,7 +744,7 @@ def __init__(self, parent=None, designMode=False): self.spockCommand.spockComboBox.connect(self.setComboBoxItem) self.spockCommand.elementUp.connect(self.setHistoryUp) self.spockCommand.elementDown.connect(self.setHistoryDown) - self.spockCommand.expandTree( + self.spockCommand.expandTree.connect( self.standardMacroParametersEditor.tree.expandAll) def macroId(self): @@ -1086,22 +1089,20 @@ def getQtDesignerPluginInfo(cls): def createMacroExecutorWidget(args): macroExecutor = TaurusMacroExecutorWidget() macroExecutor.setModelInConfig(True) - Qt.QObject.connect(macroExecutor, Qt.SIGNAL( - "doorChanged"), macroExecutor.onDoorChanged) + macroExecutor.doorChanged.connect(macroExecutor.onDoorChanged) if len(args) == 2: macroExecutor.setModel(args[0]) - macroExecutor.emit(Qt.SIGNAL('doorChanged'), args[1]) + macroExecutor.doorChanged.emit(args[1]) return macroExecutor def createMacroExecutor(args): macroExecutor = TaurusMacroExecutor() macroExecutor.setModelInConfig(True) - Qt.QObject.connect(macroExecutor, Qt.SIGNAL( - "doorChanged"), macroExecutor.onDoorChanged) + macroExecutor.doorChanged.connect(macroExecutor.onDoorChanged) if len(args) == 2: macroExecutor.setModel(args[0]) - macroExecutor.emit(Qt.SIGNAL('doorChanged'), args[1]) + macroExecutor.doorChanged.emit(args[1]) macroExecutor.loadSettings() return macroExecutor From bfb93874ba236ca1df3fb05ec8f8ff0a16c4a31e Mon Sep 17 00:00:00 2001 From: cfalcon Date: Mon, 14 Jan 2019 10:01:40 +0100 Subject: [PATCH 468/652] Use new style signals Adapt `sardana.taurus.qt.qtgui.extra_macroexecutor.dooroutput` module to new style PyQt signals. Mark DoorAttrListener class as deprectaed --- CHANGELOG.md | 2 ++ .../qtgui/extra_macroexecutor/dooroutput.py | 20 ++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91d321d24e..6e00f30087 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,8 @@ This file follows the formats and conventions from [keepachangelog.com] - Measurement group start without prior preparation (SEP18, #773) - Loadable controller's API: `LoadOne(axis, value, repeats)` in favor of `LoadOne(axis, value, repeats, latency)` (SEP18, #773) +- Unused class `sardana.taurus.qt.qtgui.extra_macroexecutor.dooroutput.DoorAttrListener` + ## [2.5.0] 2018-08-10 diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py index 1da914e4aa..c9008bb17e 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py @@ -185,8 +185,11 @@ class DoorAttrListener(Qt.QObject): def __init__(self, attrName): Qt.QObject.__init__(self) + from taurus.core.util.log import deprecated + deprecated(msg="Do not use", rel="Jan19") self.attrName = attrName self.attrObj = None + setattr(self, 'door%sChanged' % self.attrName, Qt.pyqtSignal('object')) def setDoorName(self, doorName): if not self.attrObj is None: @@ -198,7 +201,10 @@ def eventReceived(self, src, type, value): if (type == taurus.core.taurusbasetypes.TaurusEventType.Error or type == taurus.core.taurusbasetypes.TaurusEventType.Config): return - self.emit(Qt.SIGNAL('door%sChanged' % self.attrName), value.value) + + # self.emit(Qt.SIGNAL('door%sChanged' % self.attrName), value.value) + signal = getattr(self, 'door%sChanged' % self.attrName) + signal.emit(value.value) if __name__ == "__main__": @@ -212,14 +218,10 @@ def eventReceived(self, src, type, value): doorOutput = DoorOutput() if len(args) == 1: door = taurus.Device(args[0]) + door.outputUpdated.connect(doorOutput.onDoorOutputChanged) + door.infoUpdated.connect(doorOutput.onDoorInfoChanged) + door.warningUpdated.connect(doorOutput.onDoorWarningChanged) + door.errorUpdated.connect(doorOutput.onDoorErrorChanged) - Qt.QObject.connect(door, Qt.SIGNAL("outputUpdated"), - doorOutput.onDoorOutputChanged) - Qt.QObject.connect(door, Qt.SIGNAL("infoUpdated"), - doorOutput.onDoorInfoChanged) - Qt.QObject.connect(door, Qt.SIGNAL("warningUpdated"), - doorOutput.onDoorWarningChanged) - Qt.QObject.connect(door, Qt.SIGNAL("errorUpdated"), - doorOutput.onDoorErrorChanged) doorOutput.show() sys.exit(app.exec_()) From a82d15042dca6121a236fac26288dd1663746d9f Mon Sep 17 00:00:00 2001 From: mrosanes Date: Mon, 14 Jan 2019 11:23:34 +0100 Subject: [PATCH 469/652] Use new style signals Use new style PyQt signals --- .../extra_macroexecutor/macroexecutor.py | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index 9b08521e03..c573db8655 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -141,9 +141,8 @@ def setModel(self, model): self.disableEditMode = not enable self.setEnabled(enable) self._model = model - self.connect(self._model, Qt.SIGNAL( - "dataChanged(QModelIndex,QModelIndex)"), self.onDataChanged) - self.connect(self._model, Qt.SIGNAL("modelReset()"), self.setCommand) + self._model.dataChanged.connect(self.onDataChanged) + self._model.modelReset.connect(self.setCommand) def model(self): return self._model @@ -629,6 +628,10 @@ def focusOutEvent(self, event): class TaurusMacroExecutorWidget(TaurusWidget): doorChanged = Qt.pyqtSignal('QString') + macroNameChanged = Qt.pyqtSignal('QString') + macroStarted = Qt.pyqtSignal('QString') + plotablesFilterChanged = Qt.pyqtSignal('object') + shortMessageEmitted = Qt.pyqtSignal('QString') def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) @@ -859,7 +862,7 @@ def onMacroComboBoxChanged(self, macroName): self.standardMacroParametersEditor.setModel( self.paramEditorModel()) - self.emit(Qt.SIGNAL("macroNameChanged"), macroName) + self.macroNameChanged.emit(macroName) def onFavouriteSelected(self, macroNode): self.setFavouritesBuffer(macroNode) @@ -975,14 +978,13 @@ def onMacroStatusUpdated(self, data): macroName = macro.name shortMessage = "" if state == "start": - self.emit(Qt.SIGNAL("macroStarted"), "DoorOutput") + self.macroStarted.emit("DoorOutput") self.macroProgressBar.setRange(range[0], range[1]) self.playMacroAction.setEnabled(False) self.pauseMacroAction.setEnabled(True) self.stopMacroAction.setEnabled(True) - self.emit(Qt.SIGNAL("plotablesFilterChanged"), None) - self.emit(Qt.SIGNAL("plotablesFilterChanged"), - standardPlotablesFilter) + self.plotablesFilterChanged.emit(None) + self.plotablesFilterChanged.emit(standardPlotablesFilter) shortMessage = "Macro %s started." % macroName elif state == "pause": self.playMacroAction.setText("Resume macro") @@ -1019,7 +1021,7 @@ def onMacroStatusUpdated(self, data): shortMessage = "Macro %s stopped." % macroName elif state == "step": shortMessage = "Macro %s at %d %% of progress." % (macroName, step) - self.emit(Qt.SIGNAL("shortMessageEmitted"), shortMessage) + self.shortMessageEmitted.emit(shortMessage) self.macroProgressBar.setValue(step) def disableControlActions(self): @@ -1030,12 +1032,13 @@ def disableControlActions(self): def setModel(self, model): oldModelObj = self.getModelObj() if oldModelObj is not None: - self.disconnect(oldModelObj, Qt.SIGNAL( - "macrosUpdated"), self.macroComboBox.onMacrosUpdated) + # TODO: check if macrosUpdated signal exists + oldModelObj.macrosUpdated.disconnect( + self.macroComboBox.onMacrosUpdated) TaurusWidget.setModel(self, model) newModelObj = self.getModelObj() - self.connect(newModelObj, Qt.SIGNAL("macrosUpdated"), - self.macroComboBox.onMacrosUpdated) + newModelObj.macrosUpdated.connect( + self.macroComboBox.onMacrosUpdated) @classmethod def getQtDesignerPluginInfo(cls): @@ -1055,8 +1058,8 @@ def initComponents(self): self.registerConfigDelegate(self.taurusMacroExecutorWidget) self.taurusMacroExecutorWidget.setUseParentModel(True) self.setCentralWidget(self.taurusMacroExecutorWidget) - self.connect(self.taurusMacroExecutorWidget, Qt.SIGNAL( - 'shortMessageEmitted'), self.onShortMessage) + self.taurusMacroExecutorWidget.shortMessageEmitted.connect( + self.onShortMessage) self.statusBar().showMessage("MacroExecutor ready") def setCustomMacroEditorPaths(self, customMacroEditorPaths): From 33606429e4f5fd17f4fc0dafce32c9d97a704491 Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 14 Jan 2019 11:28:07 +0100 Subject: [PATCH 470/652] Changing default_timer implementation --- src/sardana/pool/controller.py | 4 +++- src/sardana/pool/poolbasechannel.py | 12 +++++++----- .../poolcontrollers/DummyCounterTimerController.py | 7 ++----- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index 92caa7be91..314c5de4af 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -298,7 +298,7 @@ class Controller(object): #: A :obj:`str` containning the path to the image logo file logo = None - + def __init__(self, inst, props, *args, **kwargs): self._inst_name = inst self._log = Logger("Controller.%s" % inst) @@ -661,6 +661,8 @@ class Loadable(object): .. note: Do not inherit directly from Loadable.""" + default_timer = None + def PrepareOne(self, axis, value, repetitions, latency, nb_starts): """**Controller API**. Override if necessary. Called to prepare the master channel axis with the measurement diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 6221a9d50b..93882e7c0f 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -339,7 +339,7 @@ def create_config(self): self.conf_ctrl.timer = channel else: if self.timer == "__default": - self.conf_timer = ChannelConfiguration(ctrl.get_element(axis=ctrl.get_ctrl_par("default_timer"))) + self.conf_timer = ChannelConfiguration(ctrl.get_element(axis=ctrl.ctrl.default_timer)) else: self.conf_timer = ChannelConfiguration(self.pool.get_element_by_name(self.timer)) self.conf_ctrl.add_channel(self.conf_timer) @@ -352,7 +352,7 @@ def create_config(self): comp_self = "__self" if self.timer != "__self": if self.timer == "__default": - self.acquisition.add_element(ctrl.get_element(axis=ctrl.get_ctrl_par("default_timer"))) + self.acquisition.add_element(ctrl.get_element(axis=ctrl.ctrl.default_timer)) else: self.acquisition.add_element(self.pool.get_element_by_name(self.timer)) @@ -386,11 +386,13 @@ def set_timer(self, timer, propagate=1): if timer == "__default": try: ctrl = self.get_controller() - self.default_timer_axis = ctrl.get_ctrl_par("default_timer") + self.default_timer_axis = ctrl.ctrl.default_timer except: - raise ValueError("Not default axis in controller") + raise ValueError("Error reading default_timer") return - + if self.default_timer_axis == None: + raise ValueError("default_timer not defined in controller") + if timer is not None and timer != "__self": try: if timer != "__default": diff --git a/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py b/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py index bea122f45e..4fbb1e33ab 100644 --- a/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py +++ b/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py @@ -64,12 +64,13 @@ class DummyCounterTimerController(CounterTimerController): TimerMode = 1 MonitorMode = 2 CounterMode = 3 + + default_timer = 1 def __init__(self, inst, props, *args, **kwargs): CounterTimerController.__init__(self, inst, props, *args, **kwargs) self._synchronization = AcqSynch.SoftwareTrigger self._latency_time = 0 - self._default_timer = 1 self.channels = self.MaxDevice * [None, ] self.reset() @@ -266,8 +267,6 @@ def GetCtrlPar(self, par): return self._synchronization elif par == 'latency_time': return self._latency_time - elif par == 'default_timer': - return self._default_timer def SetCtrlPar(self, par, value): if par == 'synchronization': @@ -275,5 +274,3 @@ def SetCtrlPar(self, par, value): for channel in self.channels: if channel: channel.mode = value - elif par == 'default_timer': - self._default_timer = value From 98222e43f2088c2e29dcad348a0e3610e91f9758 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Mon, 14 Jan 2019 11:55:58 +0100 Subject: [PATCH 471/652] Rename Slots Rename Slots to avoid collision with PyQt signal names. --- CHANGELOG.md | 2 ++ .../qt/qtgui/extra_macroexecutor/macroexecutor.py | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e00f30087..654197c18e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,8 @@ This file follows the formats and conventions from [keepachangelog.com] #933) - Logstash handler from python-logstash to python-logstash-async (#895) - Move `ParamParser` to `sardana.util.parser` (#781, #907, #908) +- SpockCommandWidget.returnPressed method renamed to onReturnPressed +- SpockCommandWidget.textChanged method renamed to onTextChanged ### Deprecated - Measurement group start without prior preparation (SEP18, #773) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index c573db8655..bb828f1ea9 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -87,8 +87,8 @@ def __init__(self, name, parent=None, designMode=False): self.setEnabled(False) self.setActions() - self.textChanged.connect(self.textChanged) - self.returnPressed.connect(self.returnPressed) + self.textChanged.connect(self.onTextChanged) + self.returnPressed.connect(self.onReturnPressed) def setActions(self): self._downAction = Qt.QAction("downAction", self) @@ -372,7 +372,7 @@ def validateOneValue(self, value): paramNode.setValue(value) return self.getModelObj().validateSingleParam(paramNode) - def returnPressed(self): + def onReturnPressed(self): # SLOT called when return is pressed if self.toolTip() == "": self.pressedReturn.emit() @@ -380,7 +380,7 @@ def returnPressed(self): raise Exception( "Cannot start macro. Please correct following mistakes:
    " + self.toolTip()) - def textChanged(self, strs): + def onTextChanged(self, strs): # SLOT called when QLineEdit text is changed if strs == "": self.updateMacroEditor("") @@ -630,7 +630,7 @@ class TaurusMacroExecutorWidget(TaurusWidget): doorChanged = Qt.pyqtSignal('QString') macroNameChanged = Qt.pyqtSignal('QString') macroStarted = Qt.pyqtSignal('QString') - plotablesFilterChanged = Qt.pyqtSignal('object') + plotablesFilterChanged = Qt.pyqtSignal(object) shortMessageEmitted = Qt.pyqtSignal('QString') def __init__(self, parent=None, designMode=False): From 5b8206e6dc350c91bfd7888dee14b09669e870a9 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Mon, 14 Jan 2019 12:53:37 +0100 Subject: [PATCH 472/652] Fix problem with Slot Fix problem with connecting to Slot. Use signature with 'QString' and define a pyqtSlot using the decorator. --- src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py | 3 +-- .../taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py index 292bc8778f..971ed6ad28 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py @@ -119,8 +119,7 @@ def selectMacro(self, macroName): index = self.findText(macroName) self.setCurrentIndex(index) if currentIdx == index: - self.currentIndexChanged.emit(macroName) - + self.currentIndexChanged['QString'].emit(macroName) class TaurusMacroConfigurationDialog(Qt.QDialog): diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index bb828f1ea9..afdb711156 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -736,7 +736,7 @@ def __init__(self, parent=None, designMode=False): spockCommandLayout.addWidget(self.spockCommand) self.layout().addLayout(spockCommandLayout) - self.macroComboBox.currentIndexChanged.connect( + self.macroComboBox.currentIndexChanged['QString'].connect( self.onMacroComboBoxChanged) self.favouritesMacrosEditor.list.favouriteSelected.connect( self.onFavouriteSelected) @@ -822,6 +822,7 @@ def setParamEditorModel(self, paramEditorModel): def setComboBoxItem(self, macroName): self.macroComboBox.selectMacro(macroName) + @Qt.pyqtSlot('QString') def onMacroComboBoxChanged(self, macroName): macroName = str(macroName) if macroName == "": From 092172fa234b54b6924ef91f23825d3b0822bb76 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Mon, 14 Jan 2019 13:22:05 +0100 Subject: [PATCH 473/652] Use new style signals Use new style PyQt signals --- .../sequenceeditor/model.py | 11 +- .../sequenceeditor/sequenceeditor.py | 117 ++++++++---------- 2 files changed, 58 insertions(+), 70 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py index 04bf41b03f..8033bacd75 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py @@ -188,24 +188,21 @@ def setData(self, index, value, role=Qt.Qt.EditRole): if index.column() == 1: if isinstance(node, macro.SingleParamNode): node.setValue(Qt.from_qvariant(value, str)) - self.emit( - Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index) + self.dataChanged.emit(index, index) while True: index = index.parent() node = self.nodeFromIndex(index) if isinstance(node, macro.MacroNode): - self.emit(Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index.sibling( + self.dataChanged.emit(index, index.sibling( index.row(), self.columnCount(index) - 1)) break elif index.column() == 2: progress = Qt.from_qvariant(value, float) node.setProgress(progress) - self.emit( - Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index) + self.dataChanged.emit(index, index) elif index.column() == 3: node.setPause(Qt.from_qvariant(value, bool)) - self.emit( - Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index) + self.dataChanged.emit(index, index) return True def headerData(self, section, orientation, role): diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py index addce3b969..ff1bbf6c12 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py @@ -67,7 +67,7 @@ def __init__(self, text, parent, macroNode): if text in self.macroNode().hookPlaces(): self.setChecked(True) self.setToolTip("This macro will be executed as a %s" % text) - self.connect(self, Qt.SIGNAL('toggled(bool)'), self.onToggle) + self.toggled.connect(self.onToggle) def macroNode(self): return self._macroNode @@ -84,6 +84,9 @@ def onToggle(self, trueFalse): class MacroSequenceTree(Qt.QTreeView, BaseConfigurableClass): + macroNameChanged = Qt.pyqtSignal('QString') + macroChanged = Qt.pyqtSignal(object) + def __init__(self, parent=None): Qt.QTreeView.__init__(self, parent) BaseConfigurableClass.__init__(self) @@ -102,34 +105,30 @@ def __init__(self, parent=None): self.deleteAction = Qt.QAction( getThemeIcon("list-remove"), "Remove macro", self) - self.connect(self.deleteAction, Qt.SIGNAL( - "triggered()"), self.deleteMacro) + self.deleteAction.triggered.connect(self.deleteMacro) self.deleteAction.setToolTip( "Clicking this button will remove current macro.") self.moveUpAction = Qt.QAction(getThemeIcon("go-up"), "Move up", self) - self.connect(self.moveUpAction, Qt.SIGNAL("triggered()"), self.upMacro) + self.moveUpAction.triggered.connect(self.upMacro) self.moveUpAction.setToolTip( "Clicking this button will move current macro up.") self.moveDownAction = Qt.QAction( getThemeIcon("go-down"), "Move down", self) - self.connect(self.moveDownAction, Qt.SIGNAL( - "triggered()"), self.downMacro) + self.moveDownAction.triggered.connect(self.downMacro) self.moveDownAction.setToolTip( "Clicking this button will move current macro down.") self.moveLeftAction = Qt.QAction( getThemeIcon("go-previous"), "Move left", self) - self.connect(self.moveLeftAction, Qt.SIGNAL( - "triggered()"), self.leftMacro) + self.moveLeftAction.triggered.connect(self.leftMacro) self.moveLeftAction.setToolTip( "Clicking this button will move current macro to the left.") self.moveRightAction = Qt.QAction( getThemeIcon("go-next"), "Move right", self) - self.connect(self.moveRightAction, Qt.SIGNAL( - "triggered()"), self.rightMacro) + self.moveRightAction.triggered.connect(self.rightMacro) self.moveRightAction.setToolTip( "Clicking this button will move current macro to the right.") @@ -181,8 +180,8 @@ def selectionChanged(self, selected, deselected): self.moveLeftAction.setEnabled(node.isAllowedMoveLeft()) self.moveRightAction.setEnabled(node.isAllowedMoveRight()) sourceIndex = self.model().mapToSource(proxyIndex) - self.emit(Qt.SIGNAL("macroChanged"), sourceIndex) - self.emit(Qt.SIGNAL("macroNameChanged"), macroName) + self.macroChanged.emit(sourceIndex) + self.macroNameChanged.emit(macroName) def expanded(self): for column in range(self.model().columnCount(Qt.QModelIndex())): @@ -324,6 +323,13 @@ def dropEvent(self, event): class TaurusSequencerWidget(TaurusWidget): + macroStarted = Qt.pyqtSignal('QString') + plotablesFilterChanged = Qt.pyqtSignal(object) + currentMacroChanged = Qt.pyqtSignal(object) + macroNameChanged = Qt.pyqtSignal('QString') + shortMessageEmitted = Qt.pyqtSignal('QString') + sequenceEmpty = Qt.pyqtSignal() + def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) # list representing all macros ids (all from sequence) currently @@ -357,8 +363,7 @@ def __init__(self, parent=None, designMode=False): actionsLayout.setContentsMargins(0, 0, 0, 0) self.newSequenceAction = Qt.QAction( getThemeIcon("document-new"), "New", self) - self.connect(self.newSequenceAction, Qt.SIGNAL( - "triggered()"), self.onNewSequence) + self.newSequenceAction.triggered.connect(self.onNewSequence) self.newSequenceAction.setToolTip("New sequence") self.newSequenceAction.setEnabled(False) newSequenceButton = Qt.QToolButton() @@ -367,8 +372,7 @@ def __init__(self, parent=None, designMode=False): self.openSequenceAction = Qt.QAction( getThemeIcon("document-open"), "Open...", self) - self.connect(self.openSequenceAction, Qt.SIGNAL( - "triggered()"), self.onOpenSequence) + self.openSequenceAction.triggered.connect(self.onOpenSequence) self.openSequenceAction.setToolTip("Open sequence...") openSequenceButton = Qt.QToolButton() openSequenceButton.setDefaultAction(self.openSequenceAction) @@ -376,8 +380,7 @@ def __init__(self, parent=None, designMode=False): self.saveSequenceAction = Qt.QAction( getThemeIcon("document-save"), "Save...", self) - self.connect(self.saveSequenceAction, Qt.SIGNAL( - "triggered()"), self.onSaveSequence) + self.saveSequenceAction.triggered.connect(self.onSaveSequence) self.saveSequenceAction.setToolTip("Save sequence...") self.saveSequenceAction.setEnabled(False) saveSequenceButton = Qt.QToolButton() @@ -386,8 +389,7 @@ def __init__(self, parent=None, designMode=False): self.stopSequenceAction = Qt.QAction( getIcon(":/actions/media_playback_stop.svg"), "Stop", self) - self.connect(self.stopSequenceAction, Qt.SIGNAL( - "triggered()"), self.onStopSequence) + self.stopSequenceAction.triggered.connect(self.onStopSequence) self.stopSequenceAction.setToolTip("Stop sequence") stopSequenceButton = Qt.QToolButton() stopSequenceButton.setDefaultAction(self.stopSequenceAction) @@ -395,8 +397,7 @@ def __init__(self, parent=None, designMode=False): self.pauseSequenceAction = Qt.QAction( getIcon(":/actions/media_playback_pause.svg"), "Pause", self) - self.connect(self.pauseSequenceAction, Qt.SIGNAL( - "triggered()"), self.onPauseSequence) + self.pauseSequenceAction.triggered.connect(self.onPauseSequence) self.pauseSequenceAction.setToolTip("Pause sequence") pauseSequenceButton = Qt.QToolButton() pauseSequenceButton.setDefaultAction(self.pauseSequenceAction) @@ -404,8 +405,7 @@ def __init__(self, parent=None, designMode=False): self.playSequenceAction = Qt.QAction( getIcon(":/actions/media_playback_start.svg"), "Play", self) - self.connect(self.playSequenceAction, Qt.SIGNAL( - "triggered()"), self.onPlaySequence) + self.playSequenceAction.triggered.connect(self.onPlaySequence) self.playSequenceAction.setToolTip("Play sequence") playSequenceButton = Qt.QToolButton() playSequenceButton.setDefaultAction(self.playSequenceAction) @@ -418,8 +418,7 @@ def __init__(self, parent=None, designMode=False): # sequence tree view indicating clearing of the plot after execution self.fullSequencePlotCheckBox = Qt.QCheckBox( "Full sequence plot", self) - self.connect(self.fullSequencePlotCheckBox, Qt.SIGNAL( - "toggled(bool)"), self.setFullSequencePlot) + self.fullSequencePlotCheckBox.toggled.connect(self.setFullSequencePlot) self.fullSequencePlotCheckBox.setChecked(True) actionsLayout.addWidget(self.fullSequencePlotCheckBox) @@ -442,9 +441,7 @@ def __init__(self, parent=None, designMode=False): self.addMacroAction = Qt.QAction( getThemeIcon("list-add"), "Add macro...", self) - self.connect(self.addMacroAction, - Qt.SIGNAL("triggered()"), - self.onAdd) + self.addMacroAction.triggered.connect(self.onAdd) self.addMacroAction.setToolTip( "Clicking this button will add selected macro") self.addMacroAction.setEnabled(False) @@ -497,10 +494,9 @@ def __init__(self, parent=None, designMode=False): self.stackedWidget.addWidget(self.standardMacroParametersEditor) self.customMacroParametersEditor = None - self.connect(self.macroComboBox, Qt.SIGNAL( - "currentIndexChanged(QString)"), self.onMacroComboBoxChanged) - self.connect(self.tree, Qt.SIGNAL("macroChanged"), - self.setMacroParametersRootIndex) + self.macroComboBox.currentIndexChanged.connect( + self.onMacroComboBoxChanged) + self.tree.macroChanged.connect(self.setMacroParametersRootIndex) def contextMenuEvent(self, event): menu = Qt.QMenu() @@ -584,7 +580,7 @@ def onNewSequence(self): self.tree.clearTree() self.newSequenceAction.setEnabled(False) self.saveSequenceAction.setEnabled(False) - self.emit(Qt.SIGNAL("currentMacroChanged"), None) + self.currentMacroChanged.emit(None) def loadFile(self, fileName): if fileName == "": @@ -628,7 +624,7 @@ def loadFile(self, fileName): file.close() self.setSequencesPath(str.join("/", fileName.rsplit("/")[:-1])) - self.emit(Qt.SIGNAL("currentMacroChanged"), None) + self.currentMacroChanged.emit(None) def onOpenSequence(self): if not self._sequenceModel.isEmpty(): @@ -754,18 +750,17 @@ def onMacroStatusUpdated(self, data): #@todo: Check this signal because it doesn't work, # emitExecutionStarted is not set!!! if self.emitExecutionStarted(): - self.emit(Qt.SIGNAL("macroStarted"), "DoorOutput") + self.macroStarted.emit("DoorOutput") self.tree.setRangeForMacro(id, range) self.playSequenceAction.setEnabled(False) self.pauseSequenceAction.setEnabled(True) self.stopSequenceAction.setEnabled(True) if id == self.firstMacroId(): - self.emit(Qt.SIGNAL("plotablesFilterChanged"), None) - self.emit(Qt.SIGNAL("plotablesFilterChanged"), - standardPlotablesFilter) + self.plotablesFilterChanged.emit(None) + self.plotablesFilterChanged.emit(standardPlotablesFilter) shortMessage = "Sequence started." elif not self.isFullSequencePlot(): - self.emit(Qt.SIGNAL("plotablesFilterChanged"), None) + self.plotablesFilterChanged.emit(None) shortMessage += " Macro %s started." % macroName elif state == "pause": self.playSequenceAction.setText("Resume sequence") @@ -805,7 +800,7 @@ def onMacroStatusUpdated(self, data): elif state == "step": shortMessage = "Macro %s at %d %% of progress." % (macroName, step) - self.emit(Qt.SIGNAL("shortMessageEmitted"), shortMessage) + self.shortMessageEmitted.emit(shortMessage) self.tree.setProgressForMacro(id, step) def onDoorChanged(self, doorName): @@ -863,7 +858,7 @@ def onMacroComboBoxChanged(self): self.addMacroAction.setEnabled(False) else: self.addMacroAction.setEnabled(True) - self.emit(Qt.SIGNAL("macroNameChanged"), macroName) + self.macroNameChanged.emit(macroName) def onAdd(self): macroName = str(self.macroComboBox.currentText()) @@ -881,8 +876,8 @@ def isMacroSelected(self): def emptySequence(self): self.tree.clearTree() self.disableButtons() - self.emit(Qt.SIGNAL("currentMacroChanged"), None) - self.emit(Qt.SIGNAL("sequenceEmpty")) + self.currentMacroChanged.emit(None) + self.sequenceEmpty.emit() def fromXmlString(self, xmlString): newRoot = self.tree.fromXmlString(xmlString) @@ -913,12 +908,11 @@ def fromPlainText(self, plainText): def setModel(self, model): oldModelObj = self.getModelObj() if oldModelObj is not None: - self.disconnect(oldModelObj, Qt.SIGNAL( - "macrosUpdated"), self.macroComboBox.onMacrosUpdated) + oldModelObj.macrosUpdated.disconnect( + self.macroComboBox.onMacrosUpdated) TaurusWidget.setModel(self, model) newModelObj = self.getModelObj() - self.connect(newModelObj, Qt.SIGNAL("macrosUpdated"), - self.macroComboBox.onMacrosUpdated) + newModelObj.macrosUpdated.connect(self.macroComboBox.onMacrosUpdated) @classmethod def getQtDesignerPluginInfo(cls): @@ -929,6 +923,7 @@ def getQtDesignerPluginInfo(cls): class TaurusSequencer(MacroExecutionWindow): + doorChanged = Qt.pyqtSignal('QString') def __init__(self, parent=None, designMode=False): MacroExecutionWindow.__init__(self) @@ -940,8 +935,8 @@ def initComponents(self): self.taurusSequencerWidget.setUseParentModel(True) self.registerConfigDelegate(self.taurusSequencerWidget) self.setCentralWidget(self.taurusSequencerWidget) - self.connect(self.taurusSequencerWidget, Qt.SIGNAL( - 'shortMessageEmitted'), self.onShortMessage) + self.taurusSequencerWidget.shortMessageEmitted.connect( + self.onShortMessage) self.statusBar().showMessage("Sequencer ready") def setCustomMacroEditorPaths(self, customMacroEditorPaths): @@ -952,23 +947,20 @@ def setCustomMacroEditorPaths(self, customMacroEditorPaths): def loadSettings(self): TaurusMainWindow.loadSettings(self) - self.emit(Qt.SIGNAL("doorChanged"), self.doorName()) + self.doorChanged.emit(self.doorName()) def onDoorChanged(self, doorName): MacroExecutionWindow.onDoorChanged(self, doorName) if self._qDoor: - Qt.QObject.disconnect( - self._qDoor, - Qt.SIGNAL("macroStatusUpdated"), + self._qDoor.macroStatusUpdated.disconnect( self.taurusSequencerWidget.onMacroStatusUpdated) self._qDoor = None if doorName == "": return self._qDoor = Device(doorName) - Qt.QObject.connect(self._qDoor, - Qt.SIGNAL("macroStatusUpdated"), - self.taurusSequencerWidget.onMacroStatusUpdated) + self._qDoor.macroStatusUpdated.connect( + self.taurusSequencerWidget.onMacroStatusUpdated) self.taurusSequencerWidget.onDoorChanged(doorName) @classmethod @@ -979,22 +971,21 @@ def getQtDesignerPluginInfo(cls): def createSequencerWidget(args): sequencer = TaurusSequencerWidget() sequencer.setModelInConfig(True) - Qt.QObject.connect(sequencer, Qt.SIGNAL( - "doorChanged"), sequencer.onDoorChanged) + sequencer.doorChanged.connect(sequencer.onDoorChanged) + if len(args) == 2: sequencer.setModel(args[0]) - sequencer.emit(Qt.SIGNAL('doorChanged'), args[1]) + sequencer.doorChanged.emit(args[1]) return sequencer def createSequencer(args, options): sequencer = TaurusSequencer() sequencer.setModelInConfig(True) - Qt.QObject.connect(sequencer, Qt.SIGNAL( - "doorChanged"), sequencer.onDoorChanged) + sequencer.doorChanged.connect(sequencer.onDoorChanged) if len(args) == 2: sequencer.setModel(args[0]) - sequencer.emit(Qt.SIGNAL('doorChanged'), args[1]) + sequencer.doorChanged.emit(args[1]) sequencer.loadSettings() if options.file is not None: sequencer.taurusSequencerWidget.loadFile(options.file) From 544fa88193c777c501d5102e2fd5af946e42df79 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Mon, 14 Jan 2019 13:24:09 +0100 Subject: [PATCH 474/652] Fix signals adaptation --- src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py | 3 ++- src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 49e0f54e54..a5ca37efdb 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -83,7 +83,8 @@ def macroStatusReceived(self, s, t, v): macro = self.getRunningMacro() if macro is None: return - self.macroStatusUpdated.emit(res) + + self.macroStatusUpdated.emit((macro, res)) return res def logReceived(self, log_name, output): diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py index 971ed6ad28..441d782433 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py @@ -132,7 +132,7 @@ def __init__(self, parent=None, initMacroServer=None, initDoor=None): self.initDoor = initDoor configureAction = Qt.QAction(getThemeIcon( "folder-open"), "Change custom macro editors paths", self) - self.configureAction.triggered.connect(self.onReloadMacroServers) + configureAction.triggered.connect(self.onReloadMacroServers) configureAction.setToolTip("Change custom macro editors paths") configureAction.setShortcut("F11") self.refreshMacroServersAction = Qt.QAction( @@ -172,8 +172,8 @@ def initComponents(self): self.layout().addWidget(self.buttonBox) self.adjustSize() - self.buttonBox.accepted.connect(Qt.SLOT("accept()")) - self.buttonBox.rejected.connect(Qt.SLOT("reject()")) + self.buttonBox.accepted.connect(self.accept) + self.buttonBox.rejected.connect(self.reject) self.macroServerComboBox.currentIndexChanged.connect( self.onMacroServerComboBoxChanged) self.selectMacroServer(self.initMacroServer) From dc4a3f084f0f204f5d4acca1554153b61806cdca Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 14 Jan 2019 13:32:29 +0100 Subject: [PATCH 475/652] Use new style signals --- .../taurus/qt/qtgui/extra_pool/poolmotor.py | 208 +++++++----------- 1 file changed, 85 insertions(+), 123 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index d87f4fa154..88ad2b9afe 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -71,7 +71,7 @@ def eventReceived(self, evt_src, evt_type, evt_value): if evt_type not in [TaurusEventType.Change, TaurusEventType.Periodic]: return limits = evt_value.value - self.emit(Qt.SIGNAL('updateLimits(PyQt_PyObject)'), limits.tolist()) + self.updateLimits.emit(limits.tolist()) class PoolMotorClient(): @@ -382,32 +382,24 @@ def just_ctrl_status_line(evt_src, evt_type, evt_value): self.__setTaurusIcons() self.ui.motorGroupBox.setContextMenuPolicy(Qt.Qt.CustomContextMenu) - self.connect(self.ui.motorGroupBox, Qt.SIGNAL( - 'customContextMenuRequested(QPoint)'), self.buildContextMenu) - - self.connect(self.ui.btnGoToNeg, Qt.SIGNAL('clicked()'), self.jogNeg) - self.connect(self.ui.btnGoToNegPress, - Qt.SIGNAL('pressed()'), self.jogNeg) - self.connect(self.ui.btnGoToNegPress, - Qt.SIGNAL('released()'), self.abort) - self.connect(self.ui.btnGoToNegInc, Qt.SIGNAL( - 'clicked()'), self.goToNegInc) - self.connect(self.ui.btnGoToPos, Qt.SIGNAL('clicked()'), self.jogPos) - self.connect(self.ui.btnGoToPosPress, - Qt.SIGNAL('pressed()'), self.jogPos) - self.connect(self.ui.btnGoToPosPress, - Qt.SIGNAL('released()'), self.abort) - self.connect(self.ui.btnGoToPosInc, Qt.SIGNAL( - 'clicked()'), self.goToPosInc) - - self.connect(self.ui.btnHome, Qt.SIGNAL('clicked()'), self.goHome) - self.connect(self.ui.btnStop, Qt.SIGNAL('clicked()'), self.abort) + + self.ui.motorGroupBox.customContextMenuRequested.connect( + self.buildContextMenu) + self.ui.btnGoToNeg.clicked.connect(self.jogNeg) + self.ui.btnGoToNegPress.pressed.connect(self.jogNeg) + self.ui.btnGoToNegPress.released.connect(self.abort) + self.ui.btnGoToNegInc.clicked.connect(self.goToNegInc) + self.ui.btnGoToPos.clicked.connect(self.jogPos) + self.ui.btnGoToPosPress.pressed.connect(self.jogPos) + self.ui.btnGoToPosPress.released.connect(self.abort) + self.ui.btnGoToPosInc.clicked.connect(self.goToPosInc) + + self.ui.btnHome.clicked.connect(self.goHome) + self.ui.btnStop.clicked.connect(self.abort) # ALSO UPDATE THE WIDGETS EVERYTIME THE FORM HAS TO BE SHOWN - self.connect(self.ui.btnCfg, Qt.SIGNAL('clicked()'), - taurus_attr_form._updateAttrWidgets) - self.connect(self.ui.btnCfg, Qt.SIGNAL('clicked()'), - self.buildBetterCfgDialogTitle) + self.ui.btnCfg.clicke.connect(taurus_attr_form._updateAttrWidgets) + self.ui.btnCfg.clicked.connect(self.buildBetterCfgDialogTitle) ####################################################################### ######################################## @@ -566,28 +558,17 @@ def buildContextMenu(self, point): action_status.setChecked(self.ui.lblStatus.isVisible()) menu.addAction(action_status) - self.connect(action_hide_all, Qt.SIGNAL( - 'triggered()'), self.toggleHideAll) - self.connect(action_show_all, Qt.SIGNAL( - 'triggered()'), self.toggleShowAll) - self.connect(action_move_absolute, Qt.SIGNAL( - 'toggled(bool)'), self.toggleMoveAbsolute) - self.connect(action_move_relative, Qt.SIGNAL( - 'toggled(bool)'), self.toggleMoveRelative) - self.connect(action_move_continuous, Qt.SIGNAL( - 'toggled(bool)'), self.toggleMoveContinuous) - self.connect(action_move_to_limits, Qt.SIGNAL( - 'toggled(bool)'), self.toggleMoveToLimits) - self.connect(action_encoder, Qt.SIGNAL( - 'toggled(bool)'), self.toggleEncoder) - self.connect(action_stop_move, Qt.SIGNAL( - 'toggled(bool)'), self.toggleStopMove) - self.connect(action_homing, Qt.SIGNAL( - 'toggled(bool)'), self.toggleHoming) - self.connect(action_config, Qt.SIGNAL( - 'toggled(bool)'), self.toggleConfig) - self.connect(action_status, Qt.SIGNAL( - 'toggled(bool)'), self.toggleStatus) + action_hide_all.triggered.connect(self.toggleHideAll) + action_show_all.triggered.connect(self.toggleShowAll) + action_move_absolute.toggled.connect(self.toggleMoveAbsolute) + action_move_relative.toggled.connect(self.toggleMoveRelative) + action_move_continuous.toggled.connect(self.toggleMoveContinuous) + action_move_to_limits.toggled.connect(self.toggleMoveToLimits) + action_encoder.toggled.connect(self.toggleEncoder) + action_stop_move.toggled.connect(self.toggleStopMove) + action_homing.toggled.connect(self.toggleHoming) + action_config.toggled.connect(self.toggleConfig) + action_statu.stoggled.connect(self.toggleStatus) menu.popup(self.cursor().pos()) @@ -748,8 +729,8 @@ def setModel(self, model): # CONFIGURE A LISTENER IN ORDER TO UPDATE LIMIT SWITCHES STATES self.limits_listener = LimitsListener() - self.connect(self.limits_listener, Qt.SIGNAL( - 'updateLimits(PyQt_PyObject)'), self.updateLimits) + self.limits_listener.updateLimits.connect( + self.updateLimits) limits_visible = False if self.has_limits: limits_attribute = self.motor_dev.getAttribute( @@ -830,7 +811,7 @@ def eventReceived(self, evt_src, evt_type, evt_value): if evt_type not in [TaurusEventType.Change, TaurusEventType.Periodic]: return value = evt_value.value - self.emit(Qt.SIGNAL('eventReceived'), value) + self.eventReceived.emit(value) ################################################## @@ -894,10 +875,9 @@ def setPowerOn(self): def setModel(self, model): # Handle User/Expert view - self.disconnect(self.taurusValueBuddy(), Qt.SIGNAL( - 'expertViewChanged(bool)'), self.setExpertView) - self.disconnect(self.btn_poweron, Qt.SIGNAL( - 'clicked()'), self.setPowerOn) + self.taurusValueBuddy.expertViewChanged.disconnect( + self.setExpertView) + self.btn_poweron.clicked.disconnect(self.setPowerOn) if model in (None, ''): self.lbl_alias.setModel(model) TaurusWidget.setModel(self, model) @@ -905,10 +885,10 @@ def setModel(self, model): self.lbl_alias.taurusValueBuddy = self.taurusValueBuddy self.lbl_alias.setModel(model) TaurusWidget.setModel(self, model + '/Status') - self.connect(self.taurusValueBuddy(), Qt.SIGNAL( - 'expertViewChanged(bool)'), self.setExpertView) + self.taurusValueBuddy.expertViewChanged.connect( + self.setExpertView) # Handle Power ON/OFF - self.connect(self.btn_poweron, Qt.SIGNAL('clicked()'), self.setPowerOn) + self.btn_poweron.clicked.connect(self.setPowerOn) self.setExpertView(self.taurusValueBuddy()._expertView) def calculateExtendedTooltip(self, cache=False): @@ -935,22 +915,21 @@ def contextMenuEvent(self, event): action_expert_view.setCheckable(True) action_expert_view.setChecked(self.taurusValueBuddy()._expertView) menu.addAction(action_expert_view) - self.connect(action_expert_view, Qt.SIGNAL( - 'toggled(bool)'), self.taurusValueBuddy().setExpertView) + action_expert_view.toggled.connect( + self.taurusValueBuddy().setExpertView) action_tango_attributes = Qt.QAction(self) action_tango_attributes.setIcon( getIcon(':/categories/preferences-system.svg')) action_tango_attributes.setText('Tango Attributes') menu.addAction(action_tango_attributes) - self.connect(action_tango_attributes, Qt.SIGNAL( - 'triggered()'), self.taurusValueBuddy().showTangoAttributes) + action_tango_attributes.triggered.connect( + self.taurusValueBuddy().showTangoAttributes) cm_action = menu.addAction("Compact") cm_action.setCheckable(True) cm_action.setChecked(self.taurusValueBuddy().isCompact()) - self.connect(cm_action, Qt.SIGNAL("toggled(bool)"), - self.taurusValueBuddy().setCompact) + cm_action.toggled.connect(self.taurusValueBuddy().setCompact) menu.exec_(event.globalPos()) event.accept() @@ -1022,7 +1001,7 @@ def __init__(self, parent=None, designMode=False): self.btn_stop.setIcon(getIcon(':/actions/media_playback_stop.svg')) self.layout().addWidget(self.btn_stop, 0, 2) - self.connect(self.btn_stop, Qt.SIGNAL('clicked()'), self.abort) + self.btn_stop.clicked.connect(self.abort) # WITH COMPACT VIEW, WE NEED TO FORWARD DOUBLE CLICK EVENT self.lbl_read.installEventFilter(self) @@ -1096,8 +1075,8 @@ def prepare_button(self, btn): def setModel(self, model): if hasattr(self, 'taurusValueBuddy'): - self.disconnect(self.taurusValueBuddy(), Qt.SIGNAL( - 'expertViewChanged(bool)'), self.setExpertView) + self.taurusValueBuddy().expertViewChanged.disconnect( + self.setExpertView) if model in (None, ''): TaurusWidget.setModel(self, model) self.lbl_read.setModel(model) @@ -1108,8 +1087,8 @@ def setModel(self, model): self.lbl_enc_read.setModel(model + '/Encoder') # Handle User/Expert view self.setExpertView(self.taurusValueBuddy()._expertView) - self.connect(self.taurusValueBuddy(), Qt.SIGNAL( - 'expertViewChanged(bool)'), self.setExpertView) + self.taurusValueBuddy().expertViewChanged.connect( + self.setExpertView) ################################################## # WRITE WIDGET # @@ -1164,8 +1143,8 @@ def __init__(self, parent=None, designMode=False): self.layout().addWidget(self.qw_write_relative, 0, 0) self.cbAbsoluteRelative = Qt.QComboBox() - self.connect(self.cbAbsoluteRelative, Qt.SIGNAL( - 'currentIndexChanged(QString)'), self.cbAbsoluteRelativeChanged) + self.cbAbsoluteRelative.currentIndexChanged.connect( + self.cbAbsoluteRelativeChanged) self.cbAbsoluteRelative.addItems(['Abs', 'Rel']) self.layout().addWidget(self.cbAbsoluteRelative, 0, 1) @@ -1219,19 +1198,15 @@ def __init__(self, parent=None, designMode=False): self.layout().addLayout(btns_layout, 1, 0, 1, 3) - self.connect(self.btn_step_down, Qt.SIGNAL('clicked()'), self.stepDown) - self.connect(self.btn_step_up, Qt.SIGNAL('clicked()'), self.stepUp) - ###self.connect(self.btn_stop, Qt.SIGNAL('clicked()'), self.abort) - self.connect(self.btn_to_neg, Qt.SIGNAL('clicked()'), self.goNegative) - self.connect(self.btn_to_neg_press, Qt.SIGNAL( - 'pressed()'), self.goNegative) - self.connect(self.btn_to_neg_press, - Qt.SIGNAL('released()'), self.abort) - self.connect(self.btn_to_pos, Qt.SIGNAL('clicked()'), self.goPositive) - self.connect(self.btn_to_pos_press, Qt.SIGNAL( - 'pressed()'), self.goPositive) - self.connect(self.btn_to_pos_press, - Qt.SIGNAL('released()'), self.abort) + self.btn_step_down.clicked.connect(self.stepDown) + self.btn_step_up.clicked.connect(self.stepUp) + ###self.btn_stop.clicked.connect(self.abort) + self.btn_to_neg.clicked.connect(self.goNegative) + self.btn_to_neg_press.pressed.connect(self.goNegative) + self.btn_to_neg_press.released.connect(self.abort) + self.btn_to_pos.clicked.connect(self.goPositive) + self.btn_to_pos_press.pressed.connect(self.goPositive) + self.btn_to_pos_press.released.connect(self.abort) # Align everything on top self.layout().addItem(Qt.QSpacerItem( @@ -1249,20 +1224,11 @@ def __init__(self, parent=None, designMode=False): # IN EXPERT VIEW, WE HAVE TO FORWARD THE ''editingFinished()' SIGNAL # FROM TaurusValueLineEdit TO Switcher - try: - self.connect(self.le_write_absolute, Qt.SIGNAL( - TaurusBaseWritableWidget.appliedSignalSignature), self.emitEditingFinished) - except AttributeError: - # TODO: For Taurus 4 adaptation - self.le_write_absolute.applied.connect(self.emitEditingFinished) - self.connect(self.btn_step_down, Qt.SIGNAL( - "clicked()"), self.emitEditingFinished) - self.connect(self.btn_step_up, Qt.SIGNAL( - "clicked()"), self.emitEditingFinished) - self.connect(self.btn_to_neg, Qt.SIGNAL( - "clicked()"), self.emitEditingFinished) - self.connect(self.btn_to_pos, Qt.SIGNAL( - "clicked()"), self.emitEditingFinished) + self.le_write_absolute.applied.connect(self.emitEditingFinished) + self.btn_step_down.clicked.connect(self.emitEditingFinished) + self.btn_step_up.clicked.connect(self.emitEditingFinished) + self.btn_to_neg.clicked.connect(self.emitEditingFinished) + self.btn_to_pos.clicked.connect(self.emitEditingFinished) # list of widgets used for edition editingWidgets = (self.le_write_absolute, self.cbAbsoluteRelative, @@ -1361,8 +1327,8 @@ def setExpertView(self, expertView): def setModel(self, model): if hasattr(self, 'taurusValueBuddy'): - self.disconnect(self.taurusValueBuddy(), Qt.SIGNAL( - 'expertViewChanged(bool)'), self.setExpertView) + self.taurusValueBuddy.expertViewChanged.disconnect( + self.setExpertView) if model in (None, ''): TaurusWidget.setModel(self, model) self.le_write_absolute.setModel(model) @@ -1372,8 +1338,8 @@ def setModel(self, model): # Handle User/Expert View self.setExpertView(self.taurusValueBuddy()._expertView) - self.connect(self.taurusValueBuddy(), Qt.SIGNAL( - 'expertViewChanged(bool)'), self.setExpertView) + self.taurusValueBuddy().expertViewChanged.connect( + self.setExpertView) def keyPressEvent(self, key_event): if key_event.key() == Qt.Qt.Key_Escape: @@ -1382,11 +1348,7 @@ def keyPressEvent(self, key_event): TaurusWidget.keyPressEvent(self, key_event) def emitEditingFinished(self): - try: - self.emit(Qt.SIGNAL(TaurusBaseWritableWidget.appliedSignalSignature)) - except AttributeError: - # TODO: For Taurus 4 adaptation - self.applied.emit() + self.applied.emit() ################################################## @@ -1436,7 +1398,7 @@ def __init__(self, parent=None, designMode=False): def setExpertView(self, expertView): self._expertView = expertView - self.emit(Qt.SIGNAL('expertViewChanged(bool)'), expertView) + self.expertViewChanged.emit(expertView) def minimumHeight(self): return None # @todo: UGLY HACK to avoid subwidgets being forced to minimumheight=20 @@ -1446,17 +1408,17 @@ def setModel(self, model): try: # disconnect signals if self.limits_listener is not None: - self.disconnect(self.limits_listener, Qt.SIGNAL( - 'eventReceived'), self.updateLimits) + self.limits_listener.eventReceived.disconnect( + self.updateLimits) if self.poweron_listener is not None: - self.disconnect(self.poweron_listener, Qt.SIGNAL( - 'eventReceived'), self.updatePowerOn) + self.poweron_listener.eventReceived.disconnect( + self.updatePowerOn) if self.status_listener is not None: - self.disconnect(self.status_listener, Qt.SIGNAL( - 'eventReceived'), self.updateStatus) + self.status_listener.eventReceived.disconnect( + self.updateStatus) if self.position_listener is not None: - self.disconnect(self.position_listener, Qt.SIGNAL( - 'eventReceived'), self.updatePosition) + self.position_listener.eventReceived.disconnect( + self.updatePosition) # remove listeners if self.motor_dev is not None: @@ -1479,8 +1441,8 @@ def setModel(self, model): # CONFIGURE A LISTENER IN ORDER TO UPDATE LIMIT SWITCHES STATES self.limits_listener = TaurusAttributeListener() if self.hasHwLimits(): - self.connect(self.limits_listener, Qt.SIGNAL( - 'eventReceived'), self.updateLimits) + self.limits_listener.eventReceived.connect( + self.updateLimits) self.motor_dev.getAttribute( 'Limit_Switches').addListener(self.limits_listener) @@ -1488,23 +1450,23 @@ def setModel(self, model): # True/False EXPERT OPERATION self.poweron_listener = TaurusAttributeListener() if self.hasPowerOn(): - self.connect(self.poweron_listener, Qt.SIGNAL( - 'eventReceived'), self.updatePowerOn) + self.poweron_listener.eventReceived.connect( + self.updatePowerOn) self.motor_dev.getAttribute( 'PowerOn').addListener(self.poweron_listener) # CONFIGURE AN EVENT RECEIVER IN ORDER TO UPDATED STATUS TOOLTIP self.status_listener = TaurusAttributeListener() - self.connect(self.status_listener, Qt.SIGNAL( - 'eventReceived'), self.updateStatus) + self.status_listener.eventReceived.connect( + self.updateStatus) self.motor_dev.getAttribute( 'Status').addListener(self.status_listener) # CONFIGURE AN EVENT RECEIVER IN ORDER TO ACTIVATE LIMIT BUTTONS ON # SOFTWARE LIMITS self.position_listener = TaurusAttributeListener() - self.connect(self.position_listener, Qt.SIGNAL( - 'eventReceived'), self.updatePosition) + self.position_listener.eventReceived.connect( + self.updatePosition) self.motor_dev.getAttribute( 'Position').addListener(self.position_listener) From 59a1c1307b9977e474712f83cf64b80411df81c6 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Mon, 14 Jan 2019 14:34:53 +0100 Subject: [PATCH 476/652] Use begin/endResetModel instead of reset Use new pyqt begin/endResetModel instead of reset --- .../favouriteseditor/model.py | 3 ++- .../customeditors/senv.py | 3 ++- .../macroparameterseditor/model.py | 18 ++++++++++++------ .../sequenceeditor/model.py | 9 ++++++--- .../sequenceeditor/sequenceeditor.py | 3 ++- 5 files changed, 24 insertions(+), 12 deletions(-) mode change 100644 => 100755 src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/model.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/model.py index fadf8ab422..606f1a0cd8 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/model.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/model.py @@ -96,9 +96,10 @@ def toXmlString(self, pretty=False): return xmlString def fromXmlString(self, xmlString): + self.beginResetModel() listElement = etree.fromstring(xmlString) for childElement in listElement.iterchildren("macro"): macroNode = macro.MacroNode() macroNode.fromXml(childElement) self.list.append(macroNode) - self.reset() + self.endResetModel() diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py index 0156307f33..6b328a1da2 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py @@ -283,8 +283,9 @@ def __init__(self, columns=None): self.__columns = columns def setColumns(self, columns): + self.beginResetModel() self.__columns = columns - self.reset() + self.endResetModel() def columns(self): return self.__columns diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py index b497d545e9..53d1775b11 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py @@ -48,10 +48,11 @@ def root(self): return self._root def setRoot(self, node=None): + self.beginResetModel() if node is None: node = macro.MacroNode() self._root = node - self.reset() + self.endResetModel() def flags(self, index): if index.column() == 0: @@ -123,7 +124,8 @@ def addRepeat(self, index, callReset=True): paramRepeatNode = self.nodeFromIndex(index) paramRepeatNode.addRepeat() if callReset: - self.reset() + self.beginResetModel() + self.endResetModel() def delRepeat(self, index, callReset=True): branchIndex = self.parent(index) @@ -131,7 +133,8 @@ def delRepeat(self, index, callReset=True): child = self.nodeFromIndex(index) branch.removeChild(child) if callReset: - self.reset() + self.beginResetModel() + self.endResetModel() def upRepeat(self, index, callReset=True): branchIndex = self.parent(index) @@ -139,7 +142,8 @@ def upRepeat(self, index, callReset=True): child = self.nodeFromIndex(index) branch.upChild(child) if callReset: - self.reset() + self.beginResetModel() + self.endResetModel() def downRepeat(self, index, callReset=True): branchIndex = self.parent(index) @@ -147,7 +151,8 @@ def downRepeat(self, index, callReset=True): child = self.nodeFromIndex(index) branch.downChild(child) if callReset: - self.reset() + self.beginResetModel() + self.endResetModel() def DuplicateRepeat(self, index, callReset=True): branchIndex = self.parent(index) @@ -155,7 +160,8 @@ def DuplicateRepeat(self, index, callReset=True): child = self.nodeFromIndex(index) branch.downChild(child) if callReset: - self.reset() + self.beginResetModel() + self.endResetModel() def rowCount(self, index): node = self.nodeFromIndex(index) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py index 8033bacd75..eb8803342f 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py @@ -46,8 +46,9 @@ def root(self): return self._root def setRoot(self, root): + self.beginResetModel() self._root = root - self.reset() + self.endResetModel() def clearSequence(self): self.setRoot(macro.SequenceNode()) @@ -243,18 +244,20 @@ def toXmlString(self, pretty=False, withId=True): return xmlString def fromXmlString(self, xmlString): + self.beginResetModel() xmlElement = etree.fromstring(xmlString) newRoot = macro.SequenceNode(None) newRoot.fromXml(xmlElement) self.setRoot(newRoot) - self.reset() + self.endResetModel() return newRoot def fromPlainText(self, text): + self.beginResetModel() newRoot = macro.SequenceNode(None) newRoot.fromPlainText(text) self.setRoot(newRoot) - self.reset() + self.endResetModel() return newRoot def assignIds(self): diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py old mode 100644 new mode 100755 index ff1bbf6c12..2226c930cd --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py @@ -209,8 +209,9 @@ def root(self): return self.model().root() def setRoot(self, root): + self.model().beginResetModel() self.model().setRoot(root) - self.model().reset() + self.model().endResetModel() def addMacro(self, macroNode): node, proxyIndex = self.selectedNodeAndIndex() From e4198d6551f969c788e12e7694781e76f6d24f64 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Mon, 14 Jan 2019 14:37:14 +0100 Subject: [PATCH 477/652] Fix signal connect Force 'QString' signature in the connect --- src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py index 441d782433..aaa9fa771b 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py @@ -174,7 +174,7 @@ def initComponents(self): self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) - self.macroServerComboBox.currentIndexChanged.connect( + self.macroServerComboBox.currentIndexChanged['QString'].connect( self.onMacroServerComboBoxChanged) self.selectMacroServer(self.initMacroServer) self.selectDoor(self.initDoor) From 1ed9ba859b261b1b5b1de9f3a28d8c76be11bb3b Mon Sep 17 00:00:00 2001 From: cfalcon Date: Tue, 15 Jan 2019 09:25:27 +0100 Subject: [PATCH 478/652] Fix flake8 errors Fix flake8 errors in `sardana.taurus.qt.qtgui.extra_hkl` modules. Fix some missing '(' --- .../qt/qtgui/extra_hkl/diffractometeralignment.py | 12 ++++++++---- src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py | 10 ++++++---- src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py | 12 ++++++++---- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py b/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py index 0c564ae6ae..b5a742400d 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py @@ -80,11 +80,14 @@ def __init__(self, parent=None, designMode=False): self.selectsignal = SelectSignal() self._ui.AlignmentStopButton.clicked.connect(self.stop_movements) - self._ui.AlignmentStoreReflectionButton.clicked.connect(self.store_reflection) + self._ui.AlignmentStoreReflectionButton.clicked.connect( + self.store_reflection) - self._ui.MacroServerConnectionButton.clicked.connect(self.open_macroserver_connection_panel) + self._ui.MacroServerConnectionButton.clicked.connect( + self.open_macroserver_connection_panel) - self._ui.SelectSignalButton.clicked.connect(self.open_selectsignal_panel) + self._ui.SelectSignalButton.clicked.connect( + self.open_selectsignal_panel) # Create a global SharedDataManager Qt.qApp.SDM = SharedDataManager(self) @@ -199,7 +202,8 @@ def setModel(self, model): self.enginemodescombobox.loadEngineModeNames(self.device.hklmodelist) - self.enginemodescombobox.currentIndexChanged.connect(self.onModeChanged) + self.enginemodescombobox.currentIndexChanged.connect( + self.onModeChanged) # Add dynamically the scan buttons, range inputs and 'to max' buttons diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py b/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py index c1064ff548..4a247905b6 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py @@ -76,9 +76,10 @@ def __init__(self, parent=None, designMode=False): self.loadUi(filename="hklscan.ui") self._ui.hklStartScanButton.clicked.connect(self.start_hklscan) - self._ui.hklStopScanButton.clicked.connectself.stop_hklscan) - self._ui.hklDisplayAnglesButton.clicked.connectself.display_angles) - self._ui.MacroServerConnectionButton.clicked.connect(self.open_macroserver_connection_panel) + self._ui.hklStopScanButton.clicked.connect(self.stop_hklscan) + self._ui.hklDisplayAnglesButton.clicked.connect(self.display_angles) + self._ui.MacroServerConnectionButton.clicked.connect( + self.open_macroserver_connection_panel) # Create a global SharedDataManager Qt.qApp.SDM = SharedDataManager(self) @@ -178,7 +179,8 @@ def setModel(self, model): self.enginemodescombobox.loadEngineModeNames(self.device.hklmodelist) - self.enginemodescombobox.currentIndexChanged.connect(self.onModeChanged) + self.enginemodescombobox.currentIndexChanged.connect( + self.onModeChanged) def onModeChanged(self, modename): if self.device.engine != "hkl": diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py b/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py index d9e1ea816d..7fa9335099 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py @@ -76,8 +76,10 @@ def __init__(self, parent=None, designMode=False): self._ui.UpdateButton.clicked.connect(self.update_values) self._ui.ComputeUButton.clicked.connect(self.compute_ub) - self._ui.ReflectionsListButton.clicked.connect(self.reflections_list_window) - self._ui.EditReflectionsButton.clicked.connect(self.edit_reflections_window) + self._ui.ReflectionsListButton.clicked.connect( + self.reflections_list_window) + self._ui.EditReflectionsButton.clicked.connect( + self.edit_reflections_window) self._ui.AffineButton.clicked.connect(self.affine) self._ui.AddCrystalButton.clicked.connect(self.add_select_crystal) # self._ui.alattice_value.textEdited.connect(self.on_alattice_value_textEdited) @@ -162,7 +164,8 @@ def setModel(self, model): self.enginemodescombobox.loadItems(self.device.enginemodelist) - self.enginemodescombobox.currentIndexChanged.connect(self.onModeChanged) + self.enginemodescombobox.currentIndexChanged.connect( + self.onModeChanged) # Set model to crystal @@ -175,7 +178,8 @@ def setModel(self, model): self.crystalscombobox.loadItems(self.device.crystallist) - self.crystalscombobox.currentIndexChanged.connect(self.onCrystalChanged) + self.crystalscombobox.currentIndexChanged.connect( + self.onCrystalChanged) def onEngineChanged(self, enginename): self.device.write_attribute("engine", str(enginename)) From 4d545153d04974d7112f9c2db2dee75517f08825 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Tue, 15 Jan 2019 09:24:01 +0100 Subject: [PATCH 479/652] Fix flake8 --- .../qt/qtgui/extra_macroexecutor/macrobutton.py | 2 +- src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py | 4 ++-- .../taurus/qt/qtgui/extra_sardana/controllertree.py | 11 +++++------ .../taurus/qt/qtgui/extra_sardana/expdescription.py | 5 +++-- .../taurus/qt/qtgui/extra_sardana/measurementgroup.py | 3 ++- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py index 11c899abbc..9be8efa522 100755 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py @@ -258,7 +258,7 @@ def connectArgEditors(self, signals): :param signals: (seq) An ordered sequence of signals """ - _pyqtsignals = [] + for i, signal in enumerate(signals): # TODO: if possible, better check that this is not a pyqtsignal if isinstance(signal, (tuple, list, set)): diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index 88ad2b9afe..65622cc8fd 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -568,7 +568,7 @@ def buildContextMenu(self, point): action_stop_move.toggled.connect(self.toggleStopMove) action_homing.toggled.connect(self.toggleHoming) action_config.toggled.connect(self.toggleConfig) - action_statu.stoggled.connect(self.toggleStatus) + action_status.stoggled.connect(self.toggleStatus) menu.popup(self.cursor().pos()) @@ -1200,7 +1200,7 @@ def __init__(self, parent=None, designMode=False): self.btn_step_down.clicked.connect(self.stepDown) self.btn_step_up.clicked.connect(self.stepUp) - ###self.btn_stop.clicked.connect(self.abort) + # self.btn_stop.clicked.connect(self.abort) self.btn_to_neg.clicked.connect(self.goNegative) self.btn_to_neg_press.pressed.connect(self.goNegative) self.btn_to_neg_press.released.connect(self.abort) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py b/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py index 43749a6d6b..d49fd19c48 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/controllertree.py @@ -122,13 +122,13 @@ class ControllerBaseModel(TaurusBaseModel): ColumnRoles = (PoolControllerView.ControllerModule, PoolControllerView.ControllerModule, PoolControllerView.ControllerClass), - - def setDataSource(self, pool): if self._data_src is not None: - self._data_src.controllerClassesUpdated.disconnect(self.controllerClassesUpdated) + self._data_src.controllerClassesUpdated.disconnect( + self.controllerClassesUpdated) if pool is not None: - pool.controllerClassesUpdated.connect(self.controllerClassesUpdated) + pool.controllerClassesUpdated.connect( + self.controllerClassesUpdated) TaurusBaseModel.setDataSource(self, pool) def controllerClassesUpdated(self): @@ -277,11 +277,10 @@ def getModelClass(self): class ControllerClassSelectionDialog(Qt.QDialog): - __pyqtSignals__ = ["accepted", "rejected"] - + def __init__(self, parent=None, designMode=False, model_name=None, perspective=None): Qt.QDialog.__init__(self, parent) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 05c4f9a6c2..89ef13e809 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -229,7 +229,7 @@ def __init__(self, parent=None, door=None, plotsButton=True, preScanList = self.ui.preScanList preScanList.dataChanged.connect( self.onPreScanSnapshotChanged) - + if hasattr(preScanList, "dataChangedSignal"): preScanList.dataChangedSignal.connect( self.onPreScanSnapshotChanged) @@ -404,7 +404,8 @@ def setModel(self, model): msname = door.macro_server.getFullName() self.ui.taurusModelTree.setModel(tghost) self.ui.sardanaElementTree.setModel(msname) - door.experimentConfigurationChanged.connect(self._experimentConfigurationChanged) + door.experimentConfigurationChanged.connect( + self._experimentConfigurationChanged) def _reloadConf(self, force=False): if not force and self.isDataChanged(): diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py index 33b18ba3ca..18974d5d6d 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py @@ -684,7 +684,8 @@ class MntGrpChannelModel(BaseMntGrpChannelModel): def setDataSource(self, mg): if self._data_src is not None: - self._data_src.configurationChanged.disconnect(self.configurationChanged) + self._data_src.configurationChanged.disconnect( + self.configurationChanged) if mg is not None: mg.configurationChanged.connect(self.configurationChanged) BaseMntGrpChannelModel.setDataSource(self, mg) From 8310e9f12f298274b5b2cb4dbd5383a10ce2f8a9 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Tue, 15 Jan 2019 09:41:56 +0100 Subject: [PATCH 480/652] Fix flake8 --- src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py b/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py index 4a247905b6..9a62d168d0 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py @@ -79,7 +79,7 @@ def __init__(self, parent=None, designMode=False): self._ui.hklStopScanButton.clicked.connect(self.stop_hklscan) self._ui.hklDisplayAnglesButton.clicked.connect(self.display_angles) self._ui.MacroServerConnectionButton.clicked.connect( - self.open_macroserver_connection_panel) + self.open_macroserver_connection_panel) # Create a global SharedDataManager Qt.qApp.SDM = SharedDataManager(self) From 21f8932ac5afdd31cfbe35d37c32a292ebf44ccc Mon Sep 17 00:00:00 2001 From: mrosanes Date: Tue, 15 Jan 2019 10:35:52 +0100 Subject: [PATCH 481/652] Fix signal clicked --- src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index 65622cc8fd..73d163f442 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -398,7 +398,7 @@ def just_ctrl_status_line(evt_src, evt_type, evt_value): self.ui.btnStop.clicked.connect(self.abort) # ALSO UPDATE THE WIDGETS EVERYTIME THE FORM HAS TO BE SHOWN - self.ui.btnCfg.clicke.connect(taurus_attr_form._updateAttrWidgets) + self.ui.btnCfg.clicked.connect(taurus_attr_form._updateAttrWidgets) self.ui.btnCfg.clicked.connect(self.buildBetterCfgDialogTitle) ####################################################################### From 919d70ccefc4f38c77ec2a1d548dabf69086cc3b Mon Sep 17 00:00:00 2001 From: mrosanes Date: Tue, 15 Jan 2019 11:34:19 +0100 Subject: [PATCH 482/652] Add try/except to disconnect methods Add try/except to disconnect methods and add missing signal. --- .../taurus/qt/qtgui/extra_pool/poolmotor.py | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index 73d163f442..be142175c7 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -875,9 +875,15 @@ def setPowerOn(self): def setModel(self, model): # Handle User/Expert view - self.taurusValueBuddy.expertViewChanged.disconnect( - self.setExpertView) - self.btn_poweron.clicked.disconnect(self.setPowerOn) + try: + self.taurusValueBuddy().expertViewChanged.disconnect( + self.setExpertView) + except TypeError: + pass + try: + self.btn_poweron.clicked.disconnect(self.setPowerOn) + except TypeError: + pass if model in (None, ''): self.lbl_alias.setModel(model) TaurusWidget.setModel(self, model) @@ -1075,8 +1081,11 @@ def prepare_button(self, btn): def setModel(self, model): if hasattr(self, 'taurusValueBuddy'): - self.taurusValueBuddy().expertViewChanged.disconnect( - self.setExpertView) + try: + self.taurusValueBuddy().expertViewChanged.disconnect( + self.setExpertView) + except TypeError: + pass if model in (None, ''): TaurusWidget.setModel(self, model) self.lbl_read.setModel(model) @@ -1327,8 +1336,11 @@ def setExpertView(self, expertView): def setModel(self, model): if hasattr(self, 'taurusValueBuddy'): - self.taurusValueBuddy.expertViewChanged.disconnect( - self.setExpertView) + try: + self.taurusValueBuddy().expertViewChanged.disconnect( + self.setExpertView) + except TypeError: + pass if model in (None, ''): TaurusWidget.setModel(self, model) self.le_write_absolute.setModel(model) @@ -1382,6 +1394,8 @@ class PoolMotorTV(TaurusValue): @TODO expert view for read widget should include signals (indexer/encoder/inpos)... ''' + expertViewChanged = Qt.pyqtSignal(bool) + def __init__(self, parent=None, designMode=False): TaurusValue.__init__(self, parent=parent, designMode=designMode) self.setLabelWidgetClass(PoolMotorTVLabelWidget) From 2d4eb395e7a8028ea8e8dcad380dacf96e3bae2a Mon Sep 17 00:00:00 2001 From: mrosanes Date: Tue, 15 Jan 2019 11:53:38 +0100 Subject: [PATCH 483/652] Rename signal to avoid name conflict Added missing signal and rename usages of it, to avoid conflict. --- .../taurus/qt/qtgui/extra_pool/poolmotor.py | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index be142175c7..09ca827911 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -64,6 +64,8 @@ class LimitsListener(Qt.QObject): can do whatever with it. """ + updateLimits = Qt.pyqtSignal(object) + def __init__(self): Qt.QObject.__init__(self) @@ -804,6 +806,8 @@ class TaurusAttributeListener(Qt.QObject): If that is the case it emits a signal with the event's value. """ + eventReceivedSignal = Qt.pyqtSignal(object) + def __init__(self): Qt.QObject.__init__(self) @@ -811,7 +815,7 @@ def eventReceived(self, evt_src, evt_type, evt_value): if evt_type not in [TaurusEventType.Change, TaurusEventType.Periodic]: return value = evt_value.value - self.eventReceived.emit(value) + self.eventReceivedSignal.emit(value) ################################################## @@ -891,7 +895,7 @@ def setModel(self, model): self.lbl_alias.taurusValueBuddy = self.taurusValueBuddy self.lbl_alias.setModel(model) TaurusWidget.setModel(self, model + '/Status') - self.taurusValueBuddy.expertViewChanged.connect( + self.taurusValueBuddy().expertViewChanged.connect( self.setExpertView) # Handle Power ON/OFF self.btn_poweron.clicked.connect(self.setPowerOn) @@ -1422,16 +1426,16 @@ def setModel(self, model): try: # disconnect signals if self.limits_listener is not None: - self.limits_listener.eventReceived.disconnect( + self.limits_listener.eventReceivedSignal.disconnect( self.updateLimits) if self.poweron_listener is not None: - self.poweron_listener.eventReceived.disconnect( + self.poweron_listener.eventReceivedSignal.disconnect( self.updatePowerOn) if self.status_listener is not None: - self.status_listener.eventReceived.disconnect( + self.status_listener.eventReceivedSignal.disconnect( self.updateStatus) if self.position_listener is not None: - self.position_listener.eventReceived.disconnect( + self.position_listener.eventReceivedSignal.disconnect( self.updatePosition) # remove listeners @@ -1455,7 +1459,7 @@ def setModel(self, model): # CONFIGURE A LISTENER IN ORDER TO UPDATE LIMIT SWITCHES STATES self.limits_listener = TaurusAttributeListener() if self.hasHwLimits(): - self.limits_listener.eventReceived.connect( + self.limits_listener.eventReceivedSignal.connect( self.updateLimits) self.motor_dev.getAttribute( 'Limit_Switches').addListener(self.limits_listener) @@ -1464,14 +1468,14 @@ def setModel(self, model): # True/False EXPERT OPERATION self.poweron_listener = TaurusAttributeListener() if self.hasPowerOn(): - self.poweron_listener.eventReceived.connect( + self.poweron_listener.eventReceivedSignal.connect( self.updatePowerOn) self.motor_dev.getAttribute( 'PowerOn').addListener(self.poweron_listener) # CONFIGURE AN EVENT RECEIVER IN ORDER TO UPDATED STATUS TOOLTIP self.status_listener = TaurusAttributeListener() - self.status_listener.eventReceived.connect( + self.status_listener.eventReceivedSignal.connect( self.updateStatus) self.motor_dev.getAttribute( 'Status').addListener(self.status_listener) @@ -1479,7 +1483,7 @@ def setModel(self, model): # CONFIGURE AN EVENT RECEIVER IN ORDER TO ACTIVATE LIMIT BUTTONS ON # SOFTWARE LIMITS self.position_listener = TaurusAttributeListener() - self.position_listener.eventReceived.connect( + self.position_listener.eventReceivedSignal.connect( self.updatePosition) self.motor_dev.getAttribute( 'Position').addListener(self.position_listener) From 95d1b2b4c7fb750a0621c50937c02365df339190 Mon Sep 17 00:00:00 2001 From: teresa Date: Tue, 15 Jan 2019 11:59:24 +0100 Subject: [PATCH 484/652] Documenting how to add programmatic hooks keeping the general ones --- doc/source/devel/howto_macros/macros_general.rst | 12 ++++++++++++ doc/source/users/macro_hooks.rst | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 23041beec6..dfd19302ce 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -915,6 +915,18 @@ using the :meth:`~sardana.macroserver.macro.Hookable.appendHook` method:: hookable_macro.appendHook((hook_function, ["another-hook-place"])) self.runMacro(hookable_macro) +Note the following differences between using the property or the method: + +- the property :attr:`~sardana.macroserver.macro.Hookable.hooks` sets all hooks + at once, the method :meth:`~sardana.macroserver.macro.Hookable.appendHook` + appends hooks one by one. + +- the property :attr:`~sardana.macroserver.macro.Hookable.hooks` deactivate the + general hooks for the macro it is used with, the the method + :meth:`~sardana.macroserver.macro.Hookable.appendHook` keeps the general + hooks for this macro. + + .. _sardana-macro-using-external-libraries: diff --git a/doc/source/users/macro_hooks.rst b/doc/source/users/macro_hooks.rst index b3f1969204..98377d3064 100644 --- a/doc/source/users/macro_hooks.rst +++ b/doc/source/users/macro_hooks.rst @@ -24,6 +24,14 @@ All available macros can be used as a hook. .. _sardana-macros-hooks-general: +**Note:**If hooks are attached programmatically to a macro using the +:attr:`~sardana.macroserver.macro.Hookable.hooks` property +the general hooks are deactivated when running this macro. +The method :meth:`~sardana.macroserver.macro.Hookable.appendHook` +has to be used if the general hooks want to be kept. The Sequencer Hooks +do not have any effect on the general hooks, they will be run if they +are defined. + General Hooks ------------- @@ -40,6 +48,7 @@ For each hook place, several hooks can be attached, they will be run in the order they were added. The same hook can be run several times in the same place if it was added several times. + Examples: - Check motor limits in step scans (pre-scan) From 78460dff992613b027a1a46fc90201bab7a76d81 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Tue, 15 Jan 2019 13:12:00 +0100 Subject: [PATCH 485/652] Fix typo in code, define pyqtSlots - Fix typo in code - Define Qt.pyqtSlot() to indicate that they do not receive any argument coming from the signal clicked. --- .../taurus/qt/qtgui/extra_pool/poolmotor.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index 09ca827911..bd44b43905 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -105,6 +105,7 @@ def moveMotor(self, pos): def moveInc(self, inc): self.moveMotor(self.motor_dev['position'].value + inc) + @Qt.pyqtSlot() def jogNeg(self): neg_limit = -((self.maxint_in_32_bits / 2) - 1) # THERE IS A BUG IN THE ICEPAP THAT DOES NOT ALLOW MOVE ABSOLUTE FURTHER THAN 32 BIT @@ -119,6 +120,7 @@ def jogNeg(self): pass self.moveMotor(neg_limit) + @Qt.pyqtSlot() def jogPos(self): pos_limit = (self.maxint_in_32_bits / 2) - 1 # THERE IS A BUG IN THE ICEPAP THAT DOES NOT ALLOW MOVE ABSOLUTE FURTHER THAN 32 BIT @@ -133,9 +135,11 @@ def jogPos(self): pass self.moveMotor(pos_limit) + @Qt.pyqtSlot() def goHome(self): pass + @Qt.pyqtSlot() def abort(self): self.motor_dev.abort() @@ -485,9 +489,11 @@ def updateLimits(self, limits): # def sizeHint(self): # return Qt.QSize(300,30) + @Qt.pyqtSlot() def goToNegInc(self): self.moveInc(-1 * self.ui.inc.value()) + @Qt.pyqtSlot() def goToPosInc(self): self.moveInc(self.ui.inc.value()) @@ -570,7 +576,7 @@ def buildContextMenu(self, point): action_stop_move.toggled.connect(self.toggleStopMove) action_homing.toggled.connect(self.toggleHoming) action_config.toggled.connect(self.toggleConfig) - action_status.stoggled.connect(self.toggleStatus) + action_status.toggled.connect(self.toggleStatus) menu.popup(self.cursor().pos()) @@ -870,6 +876,7 @@ def setExpertView(self, expertView): btn_poweron_visible = expertView and self.taurusValueBuddy().hasPowerOn() self.btn_poweron.setVisible(btn_poweron_visible) + @Qt.pyqtSlot() @ProtectTaurusMessageBox(msg='An error occurred trying to write PowerOn Attribute.') def setPowerOn(self): motor_dev = self.taurusValueBuddy().motor_dev @@ -1055,6 +1062,7 @@ def eventFilter(self, obj, event): pass return True + @Qt.pyqtSlot() @ProtectTaurusMessageBox(msg='An error occurred trying to abort the motion.') def abort(self): motor_dev = self.taurusValueBuddy().motor_dev @@ -1156,7 +1164,7 @@ def __init__(self, parent=None, designMode=False): self.layout().addWidget(self.qw_write_relative, 0, 0) self.cbAbsoluteRelative = Qt.QComboBox() - self.cbAbsoluteRelative.currentIndexChanged.connect( + self.cbAbsoluteRelative.currentIndexChanged['QString'].connect( self.cbAbsoluteRelativeChanged) self.cbAbsoluteRelative.addItems(['Abs', 'Rel']) self.layout().addWidget(self.cbAbsoluteRelative, 0, 1) @@ -1276,9 +1284,11 @@ def cbAbsoluteRelativeChanged(self, abs_rel_option): self.le_write_absolute.setVisible(abs_visible) self.qw_write_relative.setVisible(rel_visible) + @Qt.pyqtSlot() def stepDown(self): self.goRelative(-1) + @Qt.pyqtSlot() def stepUp(self): self.goRelative(+1) @@ -1291,6 +1301,7 @@ def goRelative(self, direction): target_position = position + increment motor_dev.getAttribute('Position').write(target_position) + @Qt.pyqtSlot() @ProtectTaurusMessageBox(msg='An error occurred trying to move the motor.') def goNegative(self): motor_dev = self.taurusValueBuddy().motor_dev @@ -1298,6 +1309,7 @@ def goNegative(self): min_value = float(motor_dev.getAttribute('Position').min_value) motor_dev.getAttribute('Position').write(min_value) + @Qt.pyqtSlot() @ProtectTaurusMessageBox(msg='An error occurred trying to move the motor.') def goPositive(self): motor_dev = self.taurusValueBuddy().motor_dev @@ -1305,6 +1317,7 @@ def goPositive(self): max_value = float(motor_dev.getAttribute('Position').max_value) motor_dev.getAttribute('Position').write(max_value) + @Qt.pyqtSlot() @ProtectTaurusMessageBox(msg='An error occurred trying to abort the motion.') def abort(self): motor_dev = self.taurusValueBuddy().motor_dev @@ -1363,6 +1376,7 @@ def keyPressEvent(self, key_event): key_event.accept() TaurusWidget.keyPressEvent(self, key_event) + @Qt.pyqtSlot() def emitEditingFinished(self): self.applied.emit() From 8a477ae725ddcafe9d0d0cc4b4a12cbe47b2d093 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Tue, 15 Jan 2019 15:09:33 +0100 Subject: [PATCH 486/652] Remove usages of QVariant in Sardana Avoid calling QVariant from sardana (use the python objects directly). --- .../favouriteseditor/model.py | 4 +-- .../extra_macroexecutor/macroexecutor.py | 18 +++++------ .../customeditors/senv.py | 30 +++++++++---------- .../macroparameterseditor/delegate.py | 2 +- .../macroparameterseditor/model.py | 13 ++++---- .../macroparameterseditor/parameditors.py | 2 +- .../sequenceeditor/delegate.py | 4 +-- .../sequenceeditor/model.py | 18 +++++------ .../sequenceeditor/sequenceeditor.py | 2 +- .../qtgui/extra_sardana/measurementgroup.py | 29 +++++++++--------- 10 files changed, 59 insertions(+), 63 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/model.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/model.py index 606f1a0cd8..449cb30681 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/model.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/model.py @@ -45,9 +45,9 @@ def rowCount(self, parent=Qt.QModelIndex()): def data(self, index, role): if index.isValid() and role == Qt.Qt.DisplayRole: macroNode = self.list[index.row()] - return Qt.QVariant(self.list[index.row()].toSpockCommand()) + return self.list[index.row()].toSpockCommand() else: - return Qt.QVariant() + return None def index(self, row, column=0, parent=Qt.QModelIndex()): if self.rowCount(): diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index afdb711156..7f6f5bb48d 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -280,9 +280,9 @@ def validateAllExpresion(self, secValidation=False): propValue = mlist[counter] try: self.validateOneValue(propValue) - self.model().setData(self.currentIndex, Qt.QVariant(propValue)) + self.model().setData(self.currentIndex, propValue) except Exception as e: - self.model().setData(self.currentIndex, Qt.QVariant('None')) + self.model().setData(self.currentIndex, 'None') txt = str(Qt.from_qvariant( ix.sibling(ix.row(), 0).data(), str)) message = "" + txt + " " + e[0] @@ -291,8 +291,7 @@ def validateAllExpresion(self, secValidation=False): param_info = macro_params_info[counter-1] # Skip validation in case of optional parameters if param_info['default_value'] == Optional: - self.model().setData(self.currentIndex, - Qt.QVariant(None)) + self.model().setData(self.currentIndex, None) else: txt = str(Qt.from_qvariant( ix.sibling(ix.row(), 0).data(), str)) @@ -300,8 +299,7 @@ def validateAllExpresion(self, secValidation=False): data = str(Qt.from_qvariant(ix.data(), str)) if data != 'None': - self.model().setData(self.currentIndex, - Qt.QVariant('None')) + self.model().setData(self.currentIndex, 'None') counter += 1 ix = self.getIndex() self.currentIndex = ix @@ -473,7 +471,7 @@ def controlDownAction(self): value = self.prevValue("") self.backspace() self.insert(value) - self.model().setData(self.currentIndex, Qt.QVariant(value)) + self.model().setData(self.currentIndex, value) else: self.currentIndex = self.getIndex(len(elementsNum) - 1) if not self.currentIndex.isValid(): @@ -485,7 +483,7 @@ def controlDownAction(self): c = c - (sel[1] - len(str(value))) self.insert(value) self.setCursorPosition(c) - self.model().setData(self.currentIndex, Qt.QVariant(value)) + self.model().setData(self.currentIndex, value) def controlUpAction(self): c = self.cursorPosition() @@ -515,7 +513,7 @@ def controlUpAction(self): value = self.nextValue("") self.backspace() self.insert(value) - self.model().setData(self.currentIndex, Qt.QVariant(value)) + self.model().setData(self.currentIndex, value) else: self.currentIndex = self.getIndex(len(elementsNum) - 1) if not self.currentIndex.isValid(): @@ -527,7 +525,7 @@ def controlUpAction(self): c = c - (sel[1] - len(str(value))) self.insert(value) self.setCursorPosition(c) - self.model().setData(self.currentIndex, Qt.QVariant(value)) + self.model().setData(self.currentIndex, value) def getParamItems(self, index): # Returns list of items that can be chosen for the node corresponding diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py index 6b328a1da2..0c969f0a0a 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py @@ -245,9 +245,9 @@ def setModelData(self, editor, model, index): taurusTreeAttributeItem = selectedItems[0] itemData = taurusTreeAttributeItem.itemData() if isinstance(itemData, TaurusAttrInfo): - model.setData(index, Qt.QVariant(itemData.fullName())) + model.setData(index, itemData.fullName()) elif column == 2: - model.setData(index, Qt.QVariant(editor.currentText())) + model.setData(index, editor.currentText()) else: Qt.QItemDelegate.setModelData(self, editor, model, index) @@ -298,37 +298,37 @@ def columnCount(self, index=Qt.QModelIndex()): def data(self, index, role=Qt.Qt.DisplayRole): if not index.isValid() or not (0 <= index.row() < self.rowCount()): - return Qt.QVariant() + return None row = index.row() column = index.column() # Display Role if role == Qt.Qt.DisplayRole: if column == 0: - return Qt.QVariant(Qt.QString(self.__columns[row]['label'])) + return Qt.QString(self.__columns[row]['label']) elif column == 1: - return Qt.QVariant(Qt.QString(self.__columns[row]['model'])) + return Qt.QString(self.__columns[row]['model']) elif column == 2: - return Qt.QVariant(Qt.QString(self.__columns[row]['instrument'])) - return Qt.QVariant() + return Qt.QString(self.__columns[row]['instrument']) + return None def headerData(self, section, orientation, role=Qt.Qt.DisplayRole): if role == Qt.Qt.TextAlignmentRole: if orientation == Qt.Qt.Horizontal: - return Qt.QVariant(int(Qt.Qt.AlignLeft | Qt.Qt.AlignVCenter)) - return Qt.QVariant(int(Qt.Qt.AlignRight | Qt.Qt.AlignVCenter)) + return int(Qt.Qt.AlignLeft | Qt.Qt.AlignVCenter) + return int(Qt.Qt.AlignRight | Qt.Qt.AlignVCenter) if role != Qt.Qt.DisplayRole: - return Qt.QVariant() + return None # So this is DisplayRole... if orientation == Qt.Qt.Horizontal: if section == 0: - return Qt.QVariant("Label") + return "Label" elif section == 1: - return Qt.QVariant("Attribute") + return "Attribute" elif section == 2: - return Qt.QVariant("Instrument") - return Qt.QVariant() + return "Instrument" + return None else: - return Qt.QVariant(Qt.QString.number(section + 1)) + return Qt.QString.number(section + 1) def flags(self, index): flags = Qt.Qt.ItemIsEnabled | Qt.Qt.ItemIsSelectable diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/delegate.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/delegate.py index 0645d2d18d..3a42807321 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/delegate.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/delegate.py @@ -102,7 +102,7 @@ def setEditorData(self, editor, index): def setModelData(self, editor, model, index): if index.column() == 1: - model.setData(index, Qt.QVariant(editor.getValue())) + model.setData(index, editor.getValue()) else: Qt.QStyledItemDelegate.setModelData(self, editor, model, index) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py index 53d1775b11..082ce8e98e 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py @@ -174,16 +174,15 @@ def columnCount(self, parent): def data(self, index, role): if not index.isValid() or not (0 <= index.row() < self.rowCount(index.parent())): - return Qt.QVariant() + return None if role == Qt.Qt.DisplayRole: node = self.nodeFromIndex(index) if index.column() == 0: - return Qt.QVariant(node.name()) + return node.name() elif index.column() == 1: - return Qt.QVariant(str(node.value())) - - return Qt.QVariant() + return str(node.value()) + return None def setData(self, index, value, role=Qt.Qt.EditRole): node = self.nodeFromIndex(index) @@ -196,8 +195,8 @@ def setData(self, index, value, role=Qt.Qt.EditRole): def headerData(self, section, orientation, role): if orientation == Qt.Qt.Horizontal and role == Qt.Qt.DisplayRole: - return Qt.QVariant(self.headers[section]) - return Qt.QVariant() + return self.headers[section] + return None def index(self, row, column, parent): if not parent.isValid(): diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py index 5326074ca2..8552859018 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py @@ -70,7 +70,7 @@ def setIndex(self, index): def onModelChanged(self): model = self.index().model() - model.setData(self.index(), Qt.QVariant(self.getValue())) + model.setData(self.index(), self.getValue()) class ComboBoxBoolean(ParamBase, Qt.QComboBox): diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py index e6d9d46ac0..d5add7e866 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py @@ -75,7 +75,7 @@ def setEditorData(self, editor, index): def setModelData(self, editor, model, index): if index.column() == 3: - model.setData(index, Qt.QVariant(editor.isChecked())) + model.setData(index, editor.isChecked()) class MacroParametersProxyDelegate(Qt.QItemDelegate): @@ -131,7 +131,7 @@ def setEditorData(self, editor, index): def setModelData(self, editor, model, index): if index.column() == 1: - model.setData(index, Qt.QVariant(editor.getValue())) + model.setData(index, editor.getValue()) def sizeHint(self, option, index): if index.column() == 0: diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py index eb8803342f..c6ea1278e0 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py @@ -170,19 +170,19 @@ def data(self, index, role): if role == Qt.Qt.DisplayRole: node = self.nodeFromIndex(index) if index.column() == 0: - return Qt.QVariant(node.name()) + return node.name() elif index.column() == 1: - return Qt.QVariant(str(node.value())) + return str(node.value()) elif index.column() == 2: if isinstance(node, macro.MacroNode): - return Qt.QVariant(node.progress()) + return node.progress() elif role == Qt.Qt.DecorationRole: node = self.nodeFromIndex(index) if index.column() == 3: if isinstance(node, macro.MacroNode): if node.isPause(): - return Qt.QVariant(Qt.QIcon(":/actions/media-playback-pause.svg")) - return Qt.QVariant() + return Qt.QIcon(":/actions/media-playback-pause.svg") + return None def setData(self, index, value, role=Qt.Qt.EditRole): node = self.nodeFromIndex(index) @@ -208,8 +208,8 @@ def setData(self, index, value, role=Qt.Qt.EditRole): def headerData(self, section, orientation, role): if orientation == Qt.Qt.Horizontal and role == Qt.Qt.DisplayRole: - return Qt.QVariant(self.headers[section]) - return Qt.QVariant() + return self.headers[section] + return None def index(self, row, column, parent): assert self.root() is not None @@ -393,8 +393,8 @@ def __getattr__(self, name): def headerData(self, section, orientation, role): if orientation == Qt.Qt.Horizontal and role == Qt.Qt.DisplayRole: - return Qt.QVariant(self.headers[section]) - return Qt.QVariant() + return self.headers[section] + return None def nodeFromIndex(self, index): sourceIndex = self.mapToSource(index) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py index 2226c930cd..5df641faa9 100755 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py @@ -296,7 +296,7 @@ def setProgressForMacro(self, macroId, progress): return progressIndex = persistentIndex.sibling(persistentIndex.row(), 2) index = Qt.QModelIndex(progressIndex) - self.model().setData(index, Qt.QVariant(progress)) + self.model().setData(index, progress) def setRangeForMacro(self, macroId, range): persistentIndex = self._idIndexDict.get(macroId, None) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py index 18974d5d6d..56fac4c0be 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py @@ -514,12 +514,12 @@ def data(self, index, role=Qt.Qt.DisplayRole): " in favor of synchronization. Re-apply" " configuration in order to upgrade.") self.warning(msg) - return Qt.QVariant(AcqSynchType[synchronization]) + return AcqSynchType[synchronization] elif taurus_role in (ChannelView.Timer, ChannelView.Monitor): ch_name, ch_data = index.internalPointer().itemData() ctrlname = ch_data['_controller_name'] if ctrlname.startswith("__"): - return Qt.QVariant() + return None ch_info = self.getAvailableChannels()[ch_name] if ch_info['type'] in ('CTExpChannel', 'OneDExpChannel', 'TwoDExpChannel'): unitdict = self.getPyData(ctrlname=ctrlname) @@ -529,10 +529,10 @@ def data(self, index, role=Qt.Qt.DisplayRole): key = taurus_role == ChannelView.Timer and 'timer' or 'monitor' master_full_name = self._mgconfig.get(key, None) if master_full_name is None: - return Qt.QVariant() + return None else: master_info = self.getAvailableChannels()[master_full_name] - return Qt.QVariant(master_info['name']) + return master_info['name'] elif taurus_role == ChannelView.Synchronizer: ch_name, ch_data = index.internalPointer().itemData() ctrlname = ch_data['_controller_name'] @@ -541,12 +541,12 @@ def data(self, index, role=Qt.Qt.DisplayRole): trigger_fullname = ctrl_data.get(key, None) all_triggers = self.getAvailableTriggers() if trigger_fullname is None: - return Qt.QVariant() + return None else: trigger_name = all_triggers[trigger_fullname] - return Qt.QVariant(trigger_name['name']) + return trigger_name['name'] - return Qt.QVariant() + return None def setData(self, index, qvalue, role=Qt.Qt.EditRole): # For those things which are at the unit level, we handle them here @@ -804,17 +804,16 @@ def setEditorData(self, editor, index): if all_channels[ch_name]['type'] in ('CTExpChannel', 'OneDExpChannel', 'TwoDExpChannel'): for full_name, channel_data in ctrl_dict: editor.addItem( - channel_data['name'], Qt.QVariant(full_name)) + channel_data['name'], full_name) current = Qt.from_qvariant(model.data(index), str) editor.setCurrentIndex(editor.findText(current)) else: for ctrl_data in dataSource['controllers'].values(): if key in ctrl_data: channel = all_channels[ctrl_data[key]] - editor.addItem(channel['name'], - Qt.QVariant(channel['full_name'])) + editor.addItem(channel['name'], channel['full_name']) current = dataSource.get(key) # current global timer/monitor - editor.setCurrentIndex(editor.findData(Qt.QVariant(current))) + editor.setCurrentIndex(editor.findData(current)) elif taurus_role == ChannelView.Synchronization: editor.addItems(AcqSynchType.keys()) current = Qt.from_qvariant(model.data(index), str) @@ -829,7 +828,7 @@ def setEditorData(self, editor, index): # add the triggergates to the editor all_triggers = model.getAvailableTriggers() for full_name, tg_data in all_triggers.items(): - editor.addItem(tg_data['name'], Qt.QVariant(full_name)) + editor.addItem(tg_data['name'], full_name) current = Qt.from_qvariant(model.data(index), str) editor.setCurrentIndex(editor.findText(current)) else: @@ -839,7 +838,7 @@ def setModelData(self, editor, model, index): taurus_role = model.role(index.column()) dataSource = model.dataSource() if taurus_role in (ChannelView.Channel, ChannelView.PlotType, ChannelView.Normalization): - data = Qt.QVariant(editor.currentText()) + data = editor.currentText() model.setData(index, data) elif taurus_role == ChannelView.Synchronization: old_value = Qt.from_qvariant(model.data(index), str) @@ -857,7 +856,7 @@ def setModelData(self, editor, model, index): Qt.QMessageBox.Yes | Qt.QMessageBox.Cancel) if op != Qt.QMessageBox.Yes: return - data = Qt.QVariant(new_value) + data = new_value model.setData(index, data) elif taurus_role in (ChannelView.Timer, ChannelView.Monitor): key = taurus_role == ChannelView.Timer and 'timer' or 'monitor' @@ -915,7 +914,7 @@ def setModelData(self, editor, model, index): return model.setData(index, selected_master) elif taurus_role == ChannelView.PlotAxes: - data = Qt.QVariant(editor.text()) + data = editor.text() model.setData(index, data) elif taurus_role == ChannelView.Synchronizer: old_value = Qt.from_qvariant(model.data(index), str) From 10755e92ee89ba4ac5c3bcfdb3622bcadbec065b Mon Sep 17 00:00:00 2001 From: mrosanes Date: Tue, 15 Jan 2019 15:35:57 +0100 Subject: [PATCH 487/652] Remove all usages of from_qvariant in Sardana from_qvariant is deprecated and does not have any effect. Avoid calling it from sardana --- .../extra_macroexecutor/macroexecutor.py | 8 ++-- .../customeditors/senv.py | 7 +-- .../macroparameterseditor/delegate.py | 6 +-- .../macroparameterseditor/model.py | 2 +- .../sequenceeditor/delegate.py | 6 +-- .../sequenceeditor/model.py | 7 ++- .../qtgui/extra_sardana/measurementgroup.py | 44 +++++++++---------- 7 files changed, 33 insertions(+), 47 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index 7f6f5bb48d..297b7c0662 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -283,8 +283,7 @@ def validateAllExpresion(self, secValidation=False): self.model().setData(self.currentIndex, propValue) except Exception as e: self.model().setData(self.currentIndex, 'None') - txt = str(Qt.from_qvariant( - ix.sibling(ix.row(), 0).data(), str)) + txt = str(ix.sibling(ix.row(), 0).data()) message = "" + txt + " " + e[0] problems.append(message) except IndexError: @@ -293,11 +292,10 @@ def validateAllExpresion(self, secValidation=False): if param_info['default_value'] == Optional: self.model().setData(self.currentIndex, None) else: - txt = str(Qt.from_qvariant( - ix.sibling(ix.row(), 0).data(), str)) + txt = str(ix.sibling(ix.row(), 0).data()) problems.append("" + txt + " is missing!") - data = str(Qt.from_qvariant(ix.data(), str)) + data = str(ix.data(), str) if data != 'None': self.model().setData(self.currentIndex, 'None') counter += 1 diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py index 0c969f0a0a..eb9dd31122 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py @@ -230,8 +230,7 @@ def createEditor(self, parent, option, index): def setEditorData(self, editor, index): if index.column() == 2: - text = Qt.from_qvariant(index.model().data( - index, Qt.Qt.DisplayRole), str) + text = index.model().data(index, Qt.Qt.DisplayRole) editor.setCurrentText(text) else: Qt.QItemDelegate.setEditorData(self, editor, index) @@ -254,8 +253,7 @@ def setModelData(self, editor, model, index): def sizeHint(self, option, index): if index.column() == 0: fm = option.fontMetrics - text = Qt.from_qvariant(index.model().data( - index, Qt.Qt.DisplayRole), str) + text = index.model().data(index, Qt.Qt.DisplayRole) document = Qt.QTextDocument() document.setDefaultFont(option.font) document.setHtml(text) @@ -342,7 +340,6 @@ def setData(self, index, value=None, role=Qt.Qt.EditRole): if index.isValid() and (0 <= index.row() < self.rowCount()): row = index.row() column = index.column() - value = Qt.from_qvariant(value, str) if column == 0: self.__columns[row]['label'] = value elif column == 1: diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/delegate.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/delegate.py index 3a42807321..5f584a7271 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/delegate.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/delegate.py @@ -79,8 +79,7 @@ def createEditor(self, parent, option, index): def setEditorData(self, editor, index): if index.column() == 1: - text = Qt.from_qvariant(index.model().data( - index, Qt.Qt.DisplayRole), str) + text = index.model().data(index, Qt.Qt.DisplayRole) if text == "None" or text == "" or text is None: Qt.QStyledItemDelegate.setEditorData(self, editor, index) else: @@ -109,8 +108,7 @@ def setModelData(self, editor, model, index): def sizeHint(self, option, index): if index.column() == 0: fm = option.fontMetrics - text = Qt.from_qvariant(index.model().data( - index, Qt.Qt.DisplayRole), str) + text = index.model().data(index, Qt.Qt.DisplayRole) document = Qt.QTextDocument() document.setDefaultFont(option.font) document.setHtml(text) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py index 082ce8e98e..6cf78837f8 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/model.py @@ -188,7 +188,7 @@ def setData(self, index, value, role=Qt.Qt.EditRole): node = self.nodeFromIndex(index) # if index.isValid() and 0 <= index.row() < len(node.parent()): if index.column() == 1: - node.setValue(Qt.from_qvariant(value, str)) + node.setValue(value) self.dataChanged.emit(index, index) return True return False diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py index d5add7e866..34695648d5 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py @@ -104,8 +104,7 @@ def createEditor(self, parent, option, index): def setEditorData(self, editor, index): if index.column() == 1: - text = Qt.from_qvariant(index.model().data( - index, Qt.Qt.DisplayRole), str) + text = index.model().data(index, Qt.Qt.DisplayRole) if text in ["None", "", None]: Qt.QItemDelegate.setEditorData(self, editor, index) else: @@ -136,8 +135,7 @@ def setModelData(self, editor, model, index): def sizeHint(self, option, index): if index.column() == 0: fm = option.fontMetrics - text = Qt.from_qvariant(index.model().data( - index, Qt.Qt.DisplayRole), str) + text = index.model().data(index, Qt.Qt.DisplayRole) document = Qt.QTextDocument() document.setDefaultFont(option.font) document.setHtml(text) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py index c6ea1278e0..e2f40456c0 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py @@ -188,7 +188,7 @@ def setData(self, index, value, role=Qt.Qt.EditRole): node = self.nodeFromIndex(index) if index.column() == 1: if isinstance(node, macro.SingleParamNode): - node.setValue(Qt.from_qvariant(value, str)) + node.setValue(value) self.dataChanged.emit(index, index) while True: index = index.parent() @@ -198,11 +198,10 @@ def setData(self, index, value, role=Qt.Qt.EditRole): index.row(), self.columnCount(index) - 1)) break elif index.column() == 2: - progress = Qt.from_qvariant(value, float) - node.setProgress(progress) + node.setProgress(value) self.dataChanged.emit(index, index) elif index.column() == 3: - node.setPause(Qt.from_qvariant(value, bool)) + node.setPause(value) self.dataChanged.emit(index, index) return True diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py index 56fac4c0be..ad88c1b13b 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py @@ -331,20 +331,18 @@ def data(self, index): def setData(self, index, qvalue): taurus_role = index.model().role(index.column()) - str_value = Qt.from_qvariant(qvalue, str) if taurus_role in (ChannelView.Channel, ChannelView.Conditioning, - ChannelView.NXPath, ChannelView.DataType): - data = str_value - elif taurus_role in (ChannelView.Enabled, ChannelView.Output): - data = Qt.from_qvariant(qvalue, bool) + ChannelView.NXPath, ChannelView.DataType, + ChannelView.Enabled, ChannelView.Output): + data = qvalue elif taurus_role == ChannelView.PlotType: - data = PlotType[str_value] + data = PlotType[qvalue] elif taurus_role == ChannelView.Normalization: - data = Normalization[str_value] + data = Normalization[qvalue] elif taurus_role == ChannelView.PlotAxes: - data = [a for a in str_value.split('|')] + data = [a for a in qvalue.split('|')] elif taurus_role == ChannelView.Shape: - s = str_value + s = qvalue try: data = eval(s, {}, {}) if not isinstance(data, (tuple, list)): @@ -556,8 +554,7 @@ def setData(self, index, qvalue, role=Qt.Qt.EditRole): ch_info = self.getAvailableChannels()[ch_name] ctrl_data = self.getPyData(ctrlname=ch_data['_controller_name']) key = self.data_keys_map[taurus_role] - data = Qt.from_qvariant(qvalue, str) - + data = qvalue self._dirty = True self.beginResetModel() is_settable = ch_info['type'] in ( @@ -575,16 +572,15 @@ def setData(self, index, qvalue, role=Qt.Qt.EditRole): self._mgconfig[key] = data self.endResetModel() return True - if taurus_role == ChannelView.Synchronizer: + elif taurus_role == ChannelView.Synchronizer: ch_name, ch_data = index.internalPointer().itemData() ctrlname = ch_data['_controller_name'] key = self.data_keys_map[taurus_role] - data = Qt.from_qvariant(qvalue, str) self._dirty = True self.beginResetModel() ctrl_data = self.getPyData(ctrlname=ctrlname) - ctrl_data[key] = data - self._mgconfig[key] = data + ctrl_data[key] = qvalue + self._mgconfig[key] = qvalue self.endResetModel() return True # for the rest, we use the regular TaurusBaseModel item-oriented approach @@ -788,11 +784,11 @@ def setEditorData(self, editor, index): taurus_role = model.role(index.column()) if taurus_role == ChannelView.PlotType: editor.addItems(PlotType.keys()) - current = Qt.from_qvariant(model.data(index), str) + current = model.data(index) editor.setCurrentIndex(editor.findText(current)) elif taurus_role == ChannelView.Normalization: editor.addItems(Normalization.keys()) - current = Qt.from_qvariant(model.data(index), str) + current = model.data(index) editor.setCurrentIndex(editor.findText(current)) elif taurus_role in (ChannelView.Timer, ChannelView.Monitor): key = taurus_role == ChannelView.Timer and 'timer' or 'monitor' @@ -805,7 +801,7 @@ def setEditorData(self, editor, index): for full_name, channel_data in ctrl_dict: editor.addItem( channel_data['name'], full_name) - current = Qt.from_qvariant(model.data(index), str) + current = model.data(index) editor.setCurrentIndex(editor.findText(current)) else: for ctrl_data in dataSource['controllers'].values(): @@ -816,20 +812,20 @@ def setEditorData(self, editor, index): editor.setCurrentIndex(editor.findData(current)) elif taurus_role == ChannelView.Synchronization: editor.addItems(AcqSynchType.keys()) - current = Qt.from_qvariant(model.data(index), str) + current = model.data(index) editor.setCurrentIndex(editor.findText(current)) elif taurus_role == ChannelView.PlotAxes: selectables = ['', ''] + \ [n for n, d in getChannelConfigs(dataSource)] editor.setChoices(selectables) - current = Qt.from_qvariant(model.data(index), str) + current = model.data(index) editor.setCurrentChoices(current) elif taurus_role == ChannelView.Synchronizer: # add the triggergates to the editor all_triggers = model.getAvailableTriggers() for full_name, tg_data in all_triggers.items(): editor.addItem(tg_data['name'], full_name) - current = Qt.from_qvariant(model.data(index), str) + current = model.data(index) editor.setCurrentIndex(editor.findText(current)) else: Qt.QStyledItemDelegate.setEditorData(self, editor, index) @@ -841,7 +837,7 @@ def setModelData(self, editor, model, index): data = editor.currentText() model.setData(index, data) elif taurus_role == ChannelView.Synchronization: - old_value = Qt.from_qvariant(model.data(index), str) + old_value = model.data(index) new_value = str(editor.currentText()) if new_value == old_value: return @@ -860,7 +856,7 @@ def setModelData(self, editor, model, index): model.setData(index, data) elif taurus_role in (ChannelView.Timer, ChannelView.Monitor): key = taurus_role == ChannelView.Timer and 'timer' or 'monitor' - old_value = Qt.from_qvariant(model.data(index), str) + old_value = model.data(index) new_value = str(editor.currentText()) if new_value == old_value: return @@ -917,7 +913,7 @@ def setModelData(self, editor, model, index): data = editor.text() model.setData(index, data) elif taurus_role == ChannelView.Synchronizer: - old_value = Qt.from_qvariant(model.data(index), str) + old_value = model.data(index) new_value = str(editor.currentText()) if new_value == old_value: return From d4126f1aacede0faaf20394684c4cad3c5d4df92 Mon Sep 17 00:00:00 2001 From: teresa Date: Wed, 16 Jan 2019 08:44:12 +0100 Subject: [PATCH 488/652] Correcting typo --- doc/source/devel/howto_macros/macros_general.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index dfd19302ce..8e23fc1309 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -922,7 +922,7 @@ Note the following differences between using the property or the method: appends hooks one by one. - the property :attr:`~sardana.macroserver.macro.Hookable.hooks` deactivate the - general hooks for the macro it is used with, the the method + general hooks for the macro it is used with, the method :meth:`~sardana.macroserver.macro.Hookable.appendHook` keeps the general hooks for this macro. From da18345365fef5a41c23b263c91676b8a758a5b1 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Wed, 16 Jan 2019 10:00:33 +0100 Subject: [PATCH 489/652] Fix new style signal adaptation Remove conflicted connect since troubles between signal and slot `preScanList.dataChanged.connect(self.onPreScanSnapshotChanged)` Add missing signal Fix connect signature --- .../taurus/qt/qtgui/extra_sardana/expdescription.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 89ef13e809..b1dc84ecb6 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -173,6 +173,7 @@ class ExpDescriptionEditor(Qt.QWidget, TaurusBaseWidget): ''' createExpConfChangedDialog = Qt.pyqtSignal() + experimentConfigurationChanged = Qt.pyqtSignal(object) def __init__(self, parent=None, door=None, plotsButton=True, autoUpdate=False): @@ -210,7 +211,7 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.createExpConfChangedDialog.connect( self._createExpConfChangedDialog) - self.ui.activeMntGrpCB.activated.connect( + self.ui.activeMntGrpCB.activated['QString'].connect( self.changeActiveMntGrp) self.ui.createMntGrpBT.clicked.connect( self.createMntGrp) @@ -227,12 +228,7 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.ui.channelEditor.getQModel().modelReset.connect( self._updateButtonBox) preScanList = self.ui.preScanList - preScanList.dataChanged.connect( - self.onPreScanSnapshotChanged) - - if hasattr(preScanList, "dataChangedSignal"): - preScanList.dataChangedSignal.connect( - self.onPreScanSnapshotChanged) + preScanList.dataChangedSignal.connect(self.onPreScanSnapshotChanged) self.ui.choosePathBT.clicked.connect( self.onChooseScanDirButtonClicked) @@ -530,8 +526,8 @@ def writeExperimentConfiguration(self, ask=True): self.experimentConfigurationChanged.emit(copy.deepcopy(conf)) return True + @Qt.pyqtSlot('QString') def changeActiveMntGrp(self, activeMntGrpName): - activeMntGrpName = str(activeMntGrpName) if self._localConfig is None: return if activeMntGrpName == self._localConfig['ActiveMntGrp']: From 2c4aea2efcfe5d1c536c530d5da73d3f2c739d37 Mon Sep 17 00:00:00 2001 From: teresa Date: Wed, 16 Jan 2019 10:10:04 +0100 Subject: [PATCH 490/652] Correcting typo --- .../taurus/qt/qtgui/extra_hkl/diffractometeralignment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py b/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py index b5a742400d..e348e4df58 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py @@ -245,7 +245,7 @@ def setModel(self, model): self.tomax_buttons[i].setText(QtGui.QApplication.translate( "DiffractometerAlignment", 'n.n.', None, QtGui.QApplication.UnicodeUTF8)) - self.tomax_buttons[i].clicked().connect(tomax_functions[i]) + self.tomax_buttons[i].clicked.connect(tomax_functions[i]) def exec_scan1(self): self.exec_scan(0) From b78ba694f187469acd9468a71bc8bea4efeaf19a Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 16 Jan 2019 10:38:57 +0100 Subject: [PATCH 491/652] Remove deprecated QString --- .../qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py index 34695648d5..43e027ac68 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py @@ -54,7 +54,7 @@ def paint(self, painter, option, index): percent = macroNode.progress() opts.progress = percent # opts.text = Qt.QString('Unavailable' if percent == 0 else '%d%%'%percent) - opts.text = Qt.QString('%d%%' % percent) + opts.text = str('%d%%' % percent) # opts.text = Qt.QString(percent) Qt.QApplication.style().drawControl(Qt.QStyle.CE_ProgressBar, opts, painter) else: From 33883c20894554480a8205cfcce762c704eb0523 Mon Sep 17 00:00:00 2001 From: teresa Date: Wed, 16 Jan 2019 10:44:29 +0100 Subject: [PATCH 492/652] Removing deprecated QApplication::UnicodeUTF8 --- .../extra_hkl/diffractometeralignment.py | 11 ++++------ .../taurus/qt/qtgui/extra_hkl/hklscan.py | 4 ++-- .../qt/qtgui/extra_hkl/reflectionseditor.py | 2 +- .../taurus/qt/qtgui/extra_hkl/ubmatrix.py | 22 +++++++++---------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py b/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py index e348e4df58..cb5502da98 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py @@ -172,8 +172,7 @@ def setModel(self, model): alname = "angleslabel" + str(i) angles_labels[i].setObjectName(alname) angles_labels[i].setText(QtGui.QApplication.translate( - "HKLScan", self.angles_names[i], None, - QtGui.QApplication.UnicodeUTF8)) + "HKLScan", self.angles_names[i], None)) angles_taurus_label.append(TaurusLabel(self)) angles_taurus_label[i].setGeometry( @@ -226,8 +225,7 @@ def setModel(self, model): wname = "scanbutton" + str(i) scan_buttons[i].setObjectName(wname) scan_buttons[i].setText(QtGui.QApplication.translate( - "DiffractometerAlignment", self.angles_names[i], None, - QtGui.QApplication.UnicodeUTF8)) + "DiffractometerAlignment", self.angles_names[i], None)) scan_buttons[i].clicked.connect(exec_functions[i]) self.range_inputs.append(QtGui.QLineEdit(self)) @@ -243,8 +241,7 @@ def setModel(self, model): wname = "tomaxbutton" + str(i) self.tomax_buttons[i].setObjectName(wname) self.tomax_buttons[i].setText(QtGui.QApplication.translate( - "DiffractometerAlignment", 'n.n.', None, - QtGui.QApplication.UnicodeUTF8)) + "DiffractometerAlignment", 'n.n.', None)) self.tomax_buttons[i].clicked.connect(tomax_functions[i]) def exec_scan1(self): @@ -290,7 +287,7 @@ def exec_scan(self, imot): if output_values[i] == "Position to move": self.tomax_buttons[imot].setText(QtGui.QApplication.translate( "DiffractometerAlignment", str(output_values[i + 1]), - None, QtGui.QApplication.UnicodeUTF8)) + None)) def tomax_scan1(self): self.tomax_scan(0) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py b/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py index 9a62d168d0..1efcf6e1a8 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py @@ -146,7 +146,7 @@ def setModel(self, model): alname = "angleslabel" + str(i) angles_labels[i].setObjectName(alname) angles_labels[i].setText(QtGui.QApplication.translate( - "HKLScan", angles_names[i], None, QtGui.QApplication.UnicodeUTF8)) + "HKLScan", angles_names[i], None)) angles_taurus_label.append(TaurusLabel(self)) angles_taurus_label[i].setGeometry( QtCore.QRect(50 + gap_x * i, 320, 81, 19)) @@ -256,7 +256,7 @@ def display_angles(self): label_name = "dsa_label_" + str(i) dsa_label[i].setObjectName(label_name) dsa_label[i].setText(QtGui.QApplication.translate( - "Form", angles_names[i], None, QtGui.QApplication.UnicodeUTF8)) + "Form", angles_names[i], None)) start_hkl = [] stop_hkl = [] diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/reflectionseditor.py b/src/sardana/taurus/qt/qtgui/extra_hkl/reflectionseditor.py index e5b470a35f..5dd213e0fc 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/reflectionseditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/reflectionseditor.py @@ -128,7 +128,7 @@ def setModel(self, model): object_name = "anglelabel" + str(i) self.angle_labels[i].setObjectName(object_name) self.angle_labels[i].setText(QtGui.QApplication.translate( - "Form", angle_names[i], None, QtGui.QApplication.UnicodeUTF8)) + "Form", angle_names[i], None)) self.angle_values.append([]) for jref in range(0, 10): self.angle_values[i].append(QtGui.QLineEdit(self)) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py b/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py index 7fa9335099..668b5956a3 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py @@ -293,13 +293,13 @@ def reflections_list_window(self): # 4circles diffractometer if len(ref) == 10: self.rl_label1_7.setText(QtGui.QApplication.translate( - "Form", self.angle_names[0], None, QtGui.QApplication.UnicodeUTF8)) + "Form", self.angle_names[0], None)) self.rl_label1_8.setText(QtGui.QApplication.translate( - "Form", self.angle_names[1], None, QtGui.QApplication.UnicodeUTF8)) + "Form", self.angle_names[1], None)) self.rl_label1_9.setText(QtGui.QApplication.translate( - "Form", self.angle_names[2], None, QtGui.QApplication.UnicodeUTF8)) + "Form", self.angle_names[2], None)) self.rl_label1_10.setText(QtGui.QApplication.translate( - "Form", self.angle_names[3], None, QtGui.QApplication.UnicodeUTF8)) + "Form", self.angle_names[3], None)) # 6 circles diffractometer elif len(ref) == 12: self.rl_label1_11 = QtGui.QLabel(w) @@ -311,17 +311,17 @@ def reflections_list_window(self): QtCore.QRect(xangle6 + 20, 70, 41, 20)) self.rl_label1_12.setObjectName("rl_label1_12") self.rl_label1_7.setText(QtGui.QApplication.translate( - "Form", self.angle_names[0], None, QtGui.QApplication.UnicodeUTF8)) + "Form", self.angle_names[0], None)) self.rl_label1_8.setText(QtGui.QApplication.translate( - "Form", self.angle_names[1], None, QtGui.QApplication.UnicodeUTF8)) + "Form", self.angle_names[1], None)) self.rl_label1_9.setText(QtGui.QApplication.translate( - "Form", self.angle_names[2], None, QtGui.QApplication.UnicodeUTF8)) + "Form", self.angle_names[2], None)) self.rl_label1_10.setText(QtGui.QApplication.translate( - "Form", self.angle_names[3], None, QtGui.QApplication.UnicodeUTF8)) + "Form", self.angle_names[3], None)) self.rl_label1_11.setText(QtGui.QApplication.translate( - "Form", self.angle_names[4], None, QtGui.QApplication.UnicodeUTF8)) + "Form", self.angle_names[4], None)) self.rl_label1_12.setText(QtGui.QApplication.translate( - "Form", self.angle_names[5], None, QtGui.QApplication.UnicodeUTF8)) + "Form", self.angle_names[5], None)) self.taurusValueIndex.append(TaurusValueLineEdit(w)) self.taurusValueIndex[nb_ref].setGeometry( @@ -436,7 +436,7 @@ def reflections_list_window(self): self.rl_label_nor.setFont(font) self.rl_label_nor.setObjectName("rl_label_nor") self.rl_label_nor.setText(QtGui.QApplication.translate( - "Form", "NO REFLECTIONS", None, QtGui.QApplication.UnicodeUTF8)) + "Form", "NO REFLECTIONS", None)) w.show() w.show() From 6132ad1d5f0aa237530984cba8ed0ddc0442020e Mon Sep 17 00:00:00 2001 From: cfalcon Date: Wed, 16 Jan 2019 10:47:55 +0100 Subject: [PATCH 493/652] Fix buggy cast --- .../taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index 297b7c0662..653bfa3511 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -295,7 +295,7 @@ def validateAllExpresion(self, secValidation=False): txt = str(ix.sibling(ix.row(), 0).data()) problems.append("" + txt + " is missing!") - data = str(ix.data(), str) + data = str(ix.data()) if data != 'None': self.model().setData(self.currentIndex, 'None') counter += 1 From c653457c93da5a75036b425b7ec05eec7b6ba7cd Mon Sep 17 00:00:00 2001 From: cfalcon Date: Wed, 16 Jan 2019 10:56:41 +0100 Subject: [PATCH 494/652] Remove unnecessary signal connect Remove `onCurrentIndexChanged` connection in all parameditors combobox. This work is done by ParamEditorDelegate. --- .../macroparameterseditor/parameditors.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py index 8552859018..310eb5c026 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py @@ -80,7 +80,6 @@ def __init__(self, parent=None, paramModel=None): ParamBase.__init__(self, paramModel) self.addItems(['True', 'False']) - self.currentIndexChanged.connect(self.onCurrentIndexChanged) def getValue(self): return str(self.currentText()) @@ -93,16 +92,12 @@ def setValue(self, value): else: self.setCurrentIndex(idx) - def onCurrentIndexChanged(self): - self.onModelChanged() - class ComboBoxParam(ParamBase, Qt.QComboBox): def __init__(self, parent=None, paramModel=None): Qt.QComboBox.__init__(self, parent) ParamBase.__init__(self, paramModel) - self.currentIndexChanged.connect(self.onCurrentIndexChanged) def getValue(self): return str(self.currentText()) @@ -115,9 +110,6 @@ def setValue(self, value): else: self.setCurrentIndex(idx) - def onCurrentIndexChanged(self): - self.onModelChanged() - class MSAttrListComboBoxParam(ParamBase, MSAttrListComboBox): @@ -126,7 +118,6 @@ def __init__(self, parent=None, paramModel=None): ParamBase.__init__(self, paramModel) # self.setUseParentModel(True) # self.setModel("/" + self.paramModel().type() + "List") - self.currentIndexChanged.connect(self.onCurrentIndexChanged) def getValue(self): return str(self.currentText()) @@ -134,9 +125,6 @@ def getValue(self): def setValue(self, value): self.setCurrentText(value) - def onCurrentIndexChanged(self): - self.onModelChanged() - class AttrListComboBoxParam(ParamBase, TaurusAttrListComboBox): From d5bbeaaede4df0822793783804a0918f249ceecb Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 16 Jan 2019 11:09:23 +0100 Subject: [PATCH 495/652] Define _defValue to None Variable _defValue is not defined in init method if param is None. Define _defValue to None in init method. This solves a bug when loading sequences in macrosequencer. --- src/sardana/taurus/core/tango/sardana/macro.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py index 8c6b45935a..238f6eac5e 100755 --- a/src/sardana/taurus/core/tango/sardana/macro.py +++ b/src/sardana/taurus/core/tango/sardana/macro.py @@ -485,6 +485,7 @@ class SingleParamNode(ParamNode): def __init__(self, parent=None, param=None): ParamNode.__init__(self, parent, param) + self._defValue = None if param is None: return self.setType(str(param.get('type'))) From a904cb147db461fae84abc1b44b5cf9b2d02db77 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Wed, 16 Jan 2019 11:26:04 +0100 Subject: [PATCH 496/652] Fix bug in sardanaeditor During new stryle signal changes a try/execpt block was removed and sardanaeditor can not be launched. The code is not well adapted Fix it --- src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py b/src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py index 8d6ae8b5f0..5bb434590a 100755 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py @@ -202,7 +202,7 @@ def createMenuActions(self): def register_editorstack(self, editorstack): TaurusBaseEditor.register_editorstack(self, editorstack) - self.editorstack.refresh_save_all_action.connect( + editorstack.refresh_save_all_action.connect( self.refresh_save_and_apply_action) def refresh_save_and_apply_action(self): From bd68ed03a4038c2f8ca064215138fbd80cc6ba1e Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 16 Jan 2019 12:09:36 +0100 Subject: [PATCH 497/652] Use keyword args in mixin classes Use keyword args instead of positional args in mixin classes. PyQt5 and PyQt4 differ in the way they treat the multiple inheritance. This is causing exceptions when instantiating classes that inherit from a Qt class and a mixin class. A workaround seems to be to use only kwargs in the init of the mixins. TODO: This requires more attention to check if everything is really working as it should. --- src/sardana/taurus/qt/qtcore/tango/sardana/pool.py | 4 ++-- .../extra_macroexecutor/favouriteseditor/favouriteseditor.py | 2 +- .../extra_macroexecutor/favouriteseditor/historyviewer.py | 2 +- .../taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py index 6a14816a23..071ebb4c0c 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py @@ -40,7 +40,7 @@ class QPool(Qt.QObject, TangoDevice): - def __init__(self, name, qt_parent=None, **kw): + def __init__(self, name='', qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) self.call__init__(TangoDevice, name, **kw) @@ -49,7 +49,7 @@ class QMeasurementGroup(Qt.QObject, TangoDevice): configurationChanged = Qt.pyqtSignal() - def __init__(self, name, qt_parent=None, **kw): + def __init__(self, name='', qt_parent=None, **kw): self.call__init__wo_kw(Qt.QObject, qt_parent) self.call__init__(TangoDevice, name, **kw) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/favouriteseditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/favouriteseditor.py index 6b73926833..d1d763811c 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/favouriteseditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/favouriteseditor.py @@ -105,7 +105,7 @@ class FavouritesMacrosList(Qt.QListView, BaseConfigurableClass): favouriteSelected = Qt.pyqtSignal(object) - def __init__(self, parent): + def __init__(self, parent=None): Qt.QListView.__init__(self, parent) self.setSelectionMode(Qt.QListView.ExtendedSelection) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/historyviewer.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/historyviewer.py index e76455cd34..4f2a3406ec 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/historyviewer.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/favouriteseditor/historyviewer.py @@ -116,7 +116,7 @@ class HistoryMacrosList(Qt.QListView, BaseConfigurableClass): historySelected = Qt.pyqtSignal(object) - def __init__(self, parent): + def __init__(self, parent=None): Qt.QListView.__init__(self, parent) self.setSelectionMode(Qt.QListView.SingleSelection) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index 653bfa3511..a310fadab7 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -65,7 +65,7 @@ class SpockCommandWidget(Qt.QLineEdit, TaurusBaseContainer): setHistoryFocus = Qt.pyqtSignal() expandTree = Qt.pyqtSignal() - def __init__(self, name, parent=None, designMode=False): + def __init__(self, name='', parent=None, designMode=False): # self.newValue - is used as a flag to indicate whether a controlUp controlDown actions are used to iterate existing element or put new one # self.disableEditMode - flag, used to disable edition, when user enters name of the macro which is not valid (not allowed to edit in the yellow line) # switches off validation From a6e9316d633e85236367d14fe902307f43e4cbe2 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Wed, 16 Jan 2019 12:21:50 +0100 Subject: [PATCH 498/652] Replace pyqtSignature decorator Replace pyqtSignature for pyqtSlot equivalent decorator. --- .../taurus/qt/qtgui/extra_pool/motor.py | 48 +++++++++---------- .../taurus/qt/qtgui/extra_pool/poolmotor.py | 24 +++++----- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/motor.py b/src/sardana/taurus/qt/qtgui/extra_pool/motor.py index f1d3c0521b..01ff41587f 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/motor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/motor.py @@ -73,27 +73,27 @@ def getQtDesignerPluginInfo(cls): #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # QT properties #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- - @Qt.pyqtSignature("getModel()") + @Qt.pyqtSlot() def getModel(self): return self.ui.TaurusGroupBox.getModel() - @Qt.pyqtSignature("setModel(QString)") + @Qt.pyqtSlot("QString") def setModel(self, model): self.ui.TaurusGroupBox.setModel(model) - @Qt.pyqtSignature("resetModel()") + @Qt.pyqtSlot() def resetModel(self): self.ui.TaurusGroupBox.resetModel() - @Qt.pyqtSignature("getShowText()") + @Qt.pyqtSlot() def getShowText(self): return self.ui.TaurusGroupBox.getShowText() - @Qt.pyqtSignature("setShowText(bool)") + @Qt.pyqtSlot(bool) def setShowText(self, showText): self.ui.TaurusGroupBox.setShowText(showText) - @Qt.pyqtSignature("resetShowText()") + @Qt.pyqtSlot() def resetShowText(self): self.ui.TaurusGroupBox.resetShowText() @@ -131,27 +131,27 @@ def getQtDesignerPluginInfo(cls): #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # QT properties #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- - @Qt.pyqtSignature("getModel()") + @Qt.pyqtSlot() def getModel(self): return self.ui.TaurusGroupBox.getModel() - @Qt.pyqtSignature("setModel(QString)") + @Qt.pyqtSlot("QString") def setModel(self, model): self.ui.TaurusGroupBox.setModel(model) - @Qt.pyqtSignature("resetModel()") + @Qt.pyqtSlot() def resetModel(self): self.ui.TaurusGroupBox.resetModel() - @Qt.pyqtSignature("getShowText()") + @Qt.pyqtSlot() def getShowText(self): return self.ui.TaurusGroupBox.getShowText() - @Qt.pyqtSignature("setShowText(bool)") + @Qt.pyqtSlot(bool) def setShowText(self, showText): self.ui.TaurusGroupBox.setShowText(showText) - @Qt.pyqtSignature("resetShowText()") + @Qt.pyqtSlot() def resetShowText(self): self.ui.TaurusGroupBox.resetShowText() @@ -189,27 +189,27 @@ def getQtDesignerPluginInfo(cls): #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # QT properties #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- - @Qt.pyqtSignature("getModel()") + @Qt.pyqtSlot() def getModel(self): return self.ui.TaurusGroupBox.getModel() - @Qt.pyqtSignature("setModel(QString)") + @Qt.pyqtSlot("QString") def setModel(self, model): self.ui.TaurusGroupBox.setModel(model) - @Qt.pyqtSignature("resetModel()") + @Qt.pyqtSlot() def resetModel(self): self.ui.TaurusGroupBox.resetModel() - @Qt.pyqtSignature("getShowText()") + @Qt.pyqtSlot() def getShowText(self): return self.ui.TaurusGroupBox.getShowText() - @Qt.pyqtSignature("setShowText(bool)") + @Qt.pyqtSlot(bool) def setShowText(self, showText): self.ui.TaurusGroupBox.setShowText(showText) - @Qt.pyqtSignature("resetShowText()") + @Qt.pyqtSlot() def resetShowText(self): self.ui.TaurusGroupBox.resetShowText() @@ -243,27 +243,27 @@ def getQtDesignerPluginInfo(cls): #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # QT properties #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- - @Qt.pyqtSignature("getModel()") + @Qt.pyqtSlot() def getModel(self): return self.ui.TaurusGroupBox.getModel() - @Qt.pyqtSignature("setModel(QString)") + @Qt.pyqtSlot("QString") def setModel(self, model): self.ui.TaurusGroupBox.setModel(model) - @Qt.pyqtSignature("resetModel()") + @Qt.pyqtSlot() def resetModel(self): self.ui.TaurusGroupBox.resetModel() - @Qt.pyqtSignature("getShowText()") + @Qt.pyqtSlot() def getShowText(self): return self.ui.TaurusGroupBox.getShowText() - @Qt.pyqtSignature("setShowText(bool)") + @Qt.pyqtSlot(bool) def setShowText(self, showText): self.ui.TaurusGroupBox.setShowText(showText) - @Qt.pyqtSignature("resetShowText()") + @Qt.pyqtSlot() def resetShowText(self): self.ui.TaurusGroupBox.resetShowText() diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index bd44b43905..d6394c4724 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -681,11 +681,11 @@ def hideEvent(self, event): #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # QT properties #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- - @Qt.pyqtSignature("getModel()") + @Qt.pyqtSlot() def getModel(self): return self.ui.motorGroupBox.getModel() - @Qt.pyqtSignature("setModel(QString)") + @Qt.pyqtSlot("QString") def setModel(self, model): # DUE TO A BUG IN TAUGROUPBOX, WE NEED THE FULL MODEL NAME try: @@ -754,43 +754,43 @@ def setModel(self, model): (model, repr(e))) self.traceback() - @Qt.pyqtSignature("resetModel()") + @Qt.pyqtSlot() def resetModel(self): self.ui.motorGroupBox.resetModel() - @Qt.pyqtSignature("getShowContextMenu()") + @Qt.pyqtSlot() def getShowContextMenu(self): return self.show_context_menu - @Qt.pyqtSignature("setShowContextMenu(bool)") + @Qt.pyqtSlot() def setShowContextMenu(self, showContextMenu): self.show_context_menu = showContextMenu - @Qt.pyqtSignature("resetShowContextMenu()") + @Qt.pyqtSlot() def resetShowContextMenu(self): self.show_context_menu = True - @Qt.pyqtSignature("getStepSize()") + @Qt.pyqtSlot() def getStepSize(self): return self.ui.inc.value() - @Qt.pyqtSignature("setStepSize(double)") + @Qt.pyqtSlot(float) def setStepSize(self, stepSize): self.ui.inc.setValue(stepSize) - @Qt.pyqtSignature("resetStepSize()") + @Qt.pyqtSlot() def resetStepSize(self): self.setStepSize(1) - @Qt.pyqtSignature("getStepSizeIncrement()") + @Qt.pyqtSlot() def getStepSizeIncrement(self): return self.ui.inc.singleStep() - @Qt.pyqtSignature("setStepSizeIncrement(double)") + @Qt.pyqtSlot(float) def setStepSizeIncrement(self, stepSizeIncrement): self.ui.inc.setSingleStep(stepSizeIncrement) - @Qt.pyqtSignature("resetStepSizeIncrement()") + @Qt.pyqtSlot() def resetStepSizeIncrement(self): self.setStepSizeIncrement(1) From e9023380f523c776271a59109dd5996504d8a902 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Wed, 16 Jan 2019 12:29:42 +0100 Subject: [PATCH 499/652] Avoid calling obsolete QLayout.setMargin method --- src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index d6394c4724..d56246e31e 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -842,7 +842,7 @@ class PoolMotorTVLabelWidget(TaurusWidget): def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) self.setLayout(Qt.QGridLayout()) - self.layout().setMargin(0) + self.layout().setContentsMargins(0, 0, 0, 0) self.layout().setSpacing(0) self.lbl_alias = DefaultLabelWidget(parent, designMode) @@ -982,11 +982,11 @@ def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) self.setLayout(Qt.QGridLayout()) - self.layout().setMargin(0) + self.layout().setContentsMargins(0, 0, 0, 0) self.layout().setSpacing(0) limits_layout = Qt.QHBoxLayout() - limits_layout.setMargin(0) + limits_layout.setContentsMargins(0, 0, 0, 0) limits_layout.setSpacing(0) self.btn_lim_neg = Qt.QPushButton() @@ -1128,7 +1128,7 @@ class PoolMotorTVWriteWidget(TaurusWidget): def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) self.setLayout(Qt.QGridLayout()) - self.layout().setMargin(0) + self.layout().setContentsMargins(0, 0, 0, 0) self.layout().setSpacing(0) self.le_write_absolute = TaurusValueLineEdit() @@ -1136,7 +1136,7 @@ def __init__(self, parent=None, designMode=False): self.qw_write_relative = Qt.QWidget() self.qw_write_relative.setLayout(Qt.QHBoxLayout()) - self.qw_write_relative.layout().setMargin(0) + self.qw_write_relative.layout().setContentsMargins(0, 0, 0, 0) self.qw_write_relative.layout().setSpacing(0) self.cb_step = Qt.QComboBox() @@ -1178,7 +1178,7 @@ def __init__(self, parent=None, designMode=False): #self.layout().addWidget(self.btn_stop, 0, 2) btns_layout = Qt.QHBoxLayout() - btns_layout.setMargin(0) + btns_layout.setContentsMargins(0, 0, 0, 0) btns_layout.setSpacing(0) btns_layout.addItem(Qt.QSpacerItem( From 7d6e22c7ac773933bc332e1befd64d2c93f46b0b Mon Sep 17 00:00:00 2001 From: teresa Date: Wed, 16 Jan 2019 12:51:41 +0100 Subject: [PATCH 500/652] Change index to change text signal --- .../taurus/qt/qtgui/extra_hkl/selectsignal.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py index 81cd0737dc..d2a6ee7ad7 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py @@ -47,7 +47,7 @@ class SignalComboBox(Qt.QComboBox, TaurusBaseWidget): def __init__(self, parent=None): name = self.__class__.__name__ self.call__init__wo_kw(Qt.QComboBox, parent) - self.call__init__(TaurusBaseWidget, name) + self.call__init__(TaurusBaseWidget, name='') self.setSizeAdjustPolicy(Qt.QComboBox.AdjustToContentsOnFirstShow) self.setToolTip("Choose a signal ...") QtCore.QMetaObject.connectSlotsByName(self) @@ -61,7 +61,7 @@ def loadSignals(self, signals): class SelectSignal(TaurusWidget): def __init__(self, parent=None, designMode=False): - TaurusWidget.__init__(self, parent, designMode=designMode) + TaurusWidget.__init__(self, parent=None, designMode=designMode) self.loadUi(filename="selectsignal.ui") @@ -69,7 +69,7 @@ def __init__(self, parent=None, designMode=False): self.signalComboBox.setGeometry(QtCore.QRect(70, 50, 161, 27)) self.signalComboBox.setObjectName("SignalcomboBox") - self.signalComboBox.currentIndexChanged.connect(self.onSignalChanged) + self.signalComboBox.currentTextChanged.connect(self.onSignalChanged) self.doorName = None self.door_device = None @@ -85,7 +85,7 @@ def getQtDesignerPluginInfo(cls): ret['container'] = False return ret - def update_signals(self, doorname): + def update_signals(self, doorname=''): if self.doorName != doorname: self.doorName = doorname self.door_device = taurus.Device(self.doorName) @@ -95,9 +95,9 @@ def update_signals(self, doorname): signals = [] conf = self.door_device.getExperimentConfiguration() mg_name = conf['ActiveMntGrp'] - mg = taurus.Device(mg_name) + mg = PyTango.DeviceProxy('mntgrp04') signals = mg.ElementList - + self.signalComboBox.loadSignals(signals) def onSignalChanged(self, signalname): From fc73c79de8f3cda4a9a49d06551cb64a541256a3 Mon Sep 17 00:00:00 2001 From: teresa Date: Wed, 16 Jan 2019 12:58:22 +0100 Subject: [PATCH 501/652] Correcting hardcoded name added for tests --- src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py index d2a6ee7ad7..bc3ad6f5a2 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py @@ -95,7 +95,7 @@ def update_signals(self, doorname=''): signals = [] conf = self.door_device.getExperimentConfiguration() mg_name = conf['ActiveMntGrp'] - mg = PyTango.DeviceProxy('mntgrp04') + mg = PyTango.DeviceProxy(mg_name) signals = mg.ElementList self.signalComboBox.loadSignals(signals) From 8b925f758268614998e9f3adb7664d4d0292ddb5 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Wed, 16 Jan 2019 13:13:03 +0100 Subject: [PATCH 502/652] Fix drag and drop in PMTV drag start method does not exist in QT5 adapt the code to be QT4 and QT5 compatible --- src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index d56246e31e..aa6d34dabb 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -159,7 +159,7 @@ def mouseMoveEvent(self, event): drag = Qt.QDrag(self) drag.setMimeData(mimeData) drag.setHotSpot(event.pos() - self.rect().topLeft()) - drag.start(Qt.Qt.CopyAction) + drag.exec_(Qt.Qt.CopyAction, Qt.Qt.CopyAction) class PoolMotorConfigurationForm(TaurusAttrForm): @@ -963,7 +963,7 @@ def mouseMoveEvent(self, event): drag = Qt.QDrag(self) drag.setMimeData(mimeData) drag.setHotSpot(event.pos() - self.rect().topLeft()) - drag.start(Qt.Qt.CopyAction) + drag.exec_(Qt.Qt.CopyAction, Qt.Qt.CopyAction) ################################################## # READ WIDGET # @@ -1469,7 +1469,6 @@ def setModel(self, model): self.motor_dev = None return self.motor_dev = taurus.Device(model) - # CONFIGURE A LISTENER IN ORDER TO UPDATE LIMIT SWITCHES STATES self.limits_listener = TaurusAttributeListener() if self.hasHwLimits(): @@ -1501,7 +1500,6 @@ def setModel(self, model): self.updatePosition) self.motor_dev.getAttribute( 'Position').addListener(self.position_listener) - self.motor_dev.getAttribute('Position').enablePolling(force=True) self.setExpertView(self._expertView) From e998b8f7a4bbb3da5c2ec28e235f1a0d02284f64 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Wed, 16 Jan 2019 14:54:57 +0100 Subject: [PATCH 503/652] Remove obsolete Qt.QStyleOptionProgressBarV2 Remove Qt.QStyleOptionProgressBarV2 which is obsolete in PyQt5. --- .../qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py index 43e027ac68..6880180b01 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/delegate.py @@ -45,7 +45,7 @@ def __init__(self, parent=None): def paint(self, painter, option, index): if index.column() == 2: macroNode = index.model().nodeFromIndex(index) - opts = Qt.QStyleOptionProgressBarV2() + opts = Qt.QStyleOptionProgressBar() opts.rect = option.rect range = macroNode.range() opts.minimum = range[0] From 16a3336ab69702295b1f054e1a12b9204af79e0c Mon Sep 17 00:00:00 2001 From: cfalcon Date: Wed, 16 Jan 2019 16:15:26 +0100 Subject: [PATCH 504/652] Adapt PMTV setFormat method to QT5 Since qt5 raises an error if you try to disconnect from a non connected signal setModel method current implementation fails. Fix it splitting the disconnect in try/except blocks --- .../taurus/qt/qtgui/extra_pool/poolmotor.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index aa6d34dabb..03ec5e9627 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -1437,21 +1437,37 @@ def minimumHeight(self): def setModel(self, model): TaurusValue.setModel(self, model) + + # disconnect signals try: - # disconnect signals if self.limits_listener is not None: self.limits_listener.eventReceivedSignal.disconnect( self.updateLimits) + except TypeError: + pass + + try: if self.poweron_listener is not None: self.poweron_listener.eventReceivedSignal.disconnect( self.updatePowerOn) + except TypeError: + pass + + try: if self.status_listener is not None: self.status_listener.eventReceivedSignal.disconnect( self.updateStatus) + except TypeError: + pass + + try: if self.position_listener is not None: self.position_listener.eventReceivedSignal.disconnect( self.updatePosition) - + except TypeError: + pass + + try: # remove listeners if self.motor_dev is not None: if self.hasHwLimits(): From cb1e6e67498a97285f1346cfc748ba682e9bbd84 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Wed, 16 Jan 2019 16:20:22 +0100 Subject: [PATCH 505/652] Fix TODO: use bytes --- src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index 03ec5e9627..cea2c8f758 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -148,7 +148,7 @@ class LabelWidgetDragsDeviceAndAttribute(DefaultLabelWidget): """ Offer richer mime data with taurus-device, taurus-attribute, and plain-text. """ def mouseMoveEvent(self, event): - model = self.taurusValueBuddy().getModelName() # TODO: use bytes + model = self.taurusValueBuddy().getModelName().encode('utf-8') mimeData = Qt.QMimeData() mimeData.setText(self.text()) attr_name = model @@ -955,7 +955,7 @@ def mouseMoveEvent(self, event): model = self.taurusValueBuddy().getModelObj() mimeData = Qt.QMimeData() mimeData.setText(self.lbl_alias.text()) - dev_name = model.getFullName() # TODO: Use bytes + dev_name = model.getFullName().encode('utf-8') attr_name = dev_name + b'/Position' mimeData.setData(TAURUS_DEV_MIME_TYPE, dev_name) mimeData.setData(TAURUS_ATTR_MIME_TYPE, attr_name) From 2ffea786563fd5fc6e0e2c648513e690239f5393 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Thu, 17 Jan 2019 08:30:20 +0100 Subject: [PATCH 506/652] Invert constructor calls QMeasurementGroup and QPool inherited from Qt and Taurus object. Due to a qt5 problem QMeasurementGroup and QPool constructors calls have been inverted. Call first taurus class and then QT class --- src/sardana/taurus/qt/qtcore/tango/sardana/pool.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py index 071ebb4c0c..cabe8c9775 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/pool.py @@ -41,8 +41,8 @@ class QPool(Qt.QObject, TangoDevice): def __init__(self, name='', qt_parent=None, **kw): - self.call__init__wo_kw(Qt.QObject, qt_parent) self.call__init__(TangoDevice, name, **kw) + self.call__init__wo_kw(Qt.QObject, qt_parent) class QMeasurementGroup(Qt.QObject, TangoDevice): @@ -50,8 +50,8 @@ class QMeasurementGroup(Qt.QObject, TangoDevice): configurationChanged = Qt.pyqtSignal() def __init__(self, name='', qt_parent=None, **kw): - self.call__init__wo_kw(Qt.QObject, qt_parent) self.call__init__(TangoDevice, name, **kw) + self.call__init__wo_kw(Qt.QObject, qt_parent) self._config = None self.__configuration = self.getAttribute("Configuration") From 4f6e12c68df23c927203ccf609a4bcc4187977ce Mon Sep 17 00:00:00 2001 From: cfalcon Date: Thu, 17 Jan 2019 10:41:51 +0100 Subject: [PATCH 507/652] Disable show/hide scan expconf button The scan trend must be adapted to QT5. This feature will be temporarily disabled when QT5 is used. --- .../qt/qtgui/extra_sardana/expdescription.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index b1dc84ecb6..4f23cd48f0 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -233,8 +233,20 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.onChooseScanDirButtonClicked) self.__plotManager = None + tooltip = "Show/Hide plots" + + # TODO: Disable show scan button since scan plot have to be + # adapted to support QT5 + # -------------------------------------------------------------------- + import os + if os.getenv('QT_API') == 'pyqt5': + self.debug('Show plots is not ready for QT5') + plotsButton = False + tooltip = "Show/Hide plots is not ready for QT5" + # -------------------------------------------------------------------- + icon = resource.getIcon(":/actions/view.svg") - self.togglePlotsAction = Qt.QAction(icon, "Show/Hide plots", self) + self.togglePlotsAction = Qt.QAction(icon, tooltip, self) self.togglePlotsAction.setCheckable(True) self.togglePlotsAction.setChecked(False) self.togglePlotsAction.setEnabled(plotsButton) From 935405d6c0df82084f0c4acfb16e51af1cb07be6 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Thu, 17 Jan 2019 12:05:15 +0100 Subject: [PATCH 508/652] Emit experimentConfigurationChanged also on external changes --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 32ae56f1d1..330a4f00d0 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -441,6 +441,8 @@ def _reloadConf(self, force=False): for tg_info in tg_elements.values(): avail_triggers[tg_info.full_name] = tg_info.getData() self.ui.channelEditor.getQModel().setAvailableTriggers(avail_triggers) + self.emit(Qt.SIGNAL('experimentConfigurationChanged'), + copy.deepcopy(conf)) def _setDirty(self, dirty): self._dirty = dirty From 42385c48af50e20e4db9a53960de8f412df9ec9d Mon Sep 17 00:00:00 2001 From: cfalcon Date: Fri, 18 Jan 2019 15:31:06 +0100 Subject: [PATCH 509/652] Do compatible PoolMotorTVWriteWidget with Taurus3x and Taurus4 --- .../taurus/qt/qtgui/extra_pool/poolmotor.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index cea2c8f758..f66638c922 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -1115,18 +1115,22 @@ def setModel(self, model): # WRITE WIDGET # ################################################## - class PoolMotorTVWriteWidget(TaurusWidget): layoutAlignment = Qt.Qt.AlignTop - try: - # TODO: For Taurus 4 compatibility - applied = Qt.pyqtSignal() - except AttributeError: - pass + + applied = Qt.pyqtSignal() def __init__(self, parent=None, designMode=False): TaurusWidget.__init__(self, parent, designMode) + + # ------------------------------------------------------------ + # Workaround for Taurus3 support + if int(taurus.Release.version.split('.')[0]) < 4: + from taurus.qt.qtgui.base.taurusbase import baseOldSignal + self.applied = baseOldSignal('applied', self) + # ------------------------------------------------------------ + self.setLayout(Qt.QGridLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().setSpacing(0) From d5a4c42cdb1528067d82df30ba427b637a3eb5cd Mon Sep 17 00:00:00 2001 From: cfalcon Date: Fri, 18 Jan 2019 15:44:47 +0100 Subject: [PATCH 510/652] Use new style signals Adapt new emit to use new style PyQt signals --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 2ed50dcca2..33c4044f58 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -441,8 +441,8 @@ def _reloadConf(self, force=False): for tg_info in tg_elements.values(): avail_triggers[tg_info.full_name] = tg_info.getData() self.ui.channelEditor.getQModel().setAvailableTriggers(avail_triggers) - self.emit(Qt.SIGNAL('experimentConfigurationChanged'), - copy.deepcopy(conf)) + self.experimentConfigurationChanged.emit(copy.deepcopy(conf)) + def _setDirty(self, dirty): self._dirty = dirty From 629f844a8ff82a50bf5c781a06776380652ab5b4 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Mon, 21 Jan 2019 09:56:53 +0100 Subject: [PATCH 511/652] Move macrolistener submodule from taurus to sardana The macrolistener module belongs to sardana, but for historical reasons was still in taurus. Move taurus.qt.qtgui.taurusgui.macrolistener to sardana.taurus.qt.qtgui.macrolistener --- .../qt/qtgui/extra_sardana/expdescription.py | 2 +- .../taurus/qt/qtgui/macrolistener/__init__.py | 31 + .../qt/qtgui/macrolistener/macrolistener.py | 604 ++++++++++++++++++ 3 files changed, 636 insertions(+), 1 deletion(-) create mode 100755 src/sardana/taurus/qt/qtgui/macrolistener/__init__.py create mode 100644 src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 33c4044f58..542cbc2d27 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -664,7 +664,7 @@ def onPreScanSnapshotChanged(self, items): def onPlotsButtonToggled(self, checked): if checked: - from taurus.qt.qtgui.taurusgui.macrolistener import \ + from sardana.taurus.qt.qtgui.macrolistener import \ DynamicPlotManager self.__plotManager = DynamicPlotManager(self) self.__plotManager.setModel(self.getModelName()) diff --git a/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py b/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py new file mode 100755 index 0000000000..7aa40454fd --- /dev/null +++ b/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +############################################################################## +## +# This file is part of Sardana +## +# http://www.sardana-controls.org/ +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Sardana 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. +## +# Sardana 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 Sardana. If not, see . +## +############################################################################## + +"""This package contains a collection of taurus widgets designed to connect +to sardana""" + +__docformat__ = 'restructuredtext' + +from .macrolistener import * \ No newline at end of file diff --git a/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py b/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py new file mode 100644 index 0000000000..5946164cbc --- /dev/null +++ b/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py @@ -0,0 +1,604 @@ +#!/usr/bin/env python + +############################################################################## +## +# This file is part of Sardana +## +# http://www.sardana-controls.org/ +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Sardana 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. +## +# Sardana 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 Sardana. If not, see . +## +############################################################################## + +""" +This module provides objects to manage macro-related tasks. Its primary use is +to be used within a TaurusGui for managing panels for: +- setting preferences in the sardana control system for data I/O +- displaying results of macro executions, including creating/removing panels for + plotting results of scans +- editing macros + +.. note:: This module was originally implemented in taurus as + `taurus.qt.qtgui.taurusgui.macrolistener` +""" + +from __future__ import print_function + +from builtins import object + +import datetime + +from taurus.core.util.containers import CaselessList +from taurus.external.qt import Qt +from taurus.qt.qtgui.base import TaurusBaseComponent + + +__all__ = ['MacroBroker', 'DynamicPlotManager'] +__docformat__ = 'restructuredtext' + + +class ChannelFilter(object): + + def __init__(self, chlist): + self.chlist = tuple(chlist) + + def __call__(self, x): + return x in self.chlist + + +class DynamicPlotManager(Qt.QObject, TaurusBaseComponent): + '''This is a manager of plots related to the execution of macros. + It dynamically creates/removes plots according to the configuration made by + an ExperimentConfiguration widget. + + Currently it supports only 1D scan trends (2D scans are only half-baked) + + To use it simply instantiate it and pass it a door name as a model. You may + want to call :meth:`onExpConfChanged` to update the configuration being + used. + ''' + + newShortMessage = Qt.pyqtSignal('QString') + + def __init__(self, parent=None): + Qt.QObject.__init__(self, parent) + TaurusBaseComponent.__init__(self, self.__class__.__name__) + + self.__panels = {} + + self._trends1d = {} + self._trends2d = {} + + def setModel(self, doorname): + '''reimplemented from :meth:`TaurusBaseComponent` + + :param doorname: (str) device name corresponding to a Door device. + ''' + TaurusBaseComponent.setModel(self, doorname) + # self._onDoorChanged(doorname) + if not doorname: + return + door = self.getModelObj() + if not isinstance(door, Qt.QObject): + msg = "Unexpected type (%s) for %s" % (repr(type(door)), doorname) + Qt.QMessageBox.critical( + self.parent(), 'Door connection error', msg) + return + + self._checkJsonRecorder() + + # read the expconf + expconf = door.getExperimentConfiguration() + self.onExpConfChanged(expconf) + + def _checkJsonRecorder(self): + '''Checks if JsonRecorder env var is set and offers to set it''' + door = self.getModelObj() + if 'JsonRecorder' not in door.getEnvironment(): + msg = ('JsonRecorder environment variable is not set, but it ' + + 'is needed for displaying trend plots.\n' + + 'Enable it globally for %s?') % door.fullname + result = Qt.QMessageBox.question(self.parent(), + 'JsonRecorder not set', msg, + Qt.QMessageBox.Yes | Qt.QMessageBox.No) + if result == Qt.QMessageBox.Yes: + door.putEnvironment('JsonRecorder', True) + self.info('JsonRecorder Enabled for %s' % door.fullname) + + def onExpConfChanged(self, expconf): + ''' + Slot to be called when experimental configuration changes. It should + remove the temporary panels and create the new ones needed. + + :param expconf: (dict) An Experiment Description dictionary. See + :meth:`sardana.taurus.qt.qtcore.tango.sardana. + QDoor.getExperimentDescription` + for more details + ''' + + from sardana.taurus.core.tango.sardana import PlotType + from sardana.taurus.core.tango.sardana.pool import getChannelConfigs + activeMntGrp = expconf['ActiveMntGrp'] + if activeMntGrp is None: + return + if activeMntGrp not in expconf['MntGrpConfigs']: + self.warning( + "ActiveMntGrp '%s' is not defined" % + activeMntGrp) + return + mgconfig = expconf['MntGrpConfigs'][activeMntGrp] + channels = dict(getChannelConfigs(mgconfig, sort=False)) + + # classify by type of plot: + trends1d = {} + trends2d = {} + plots1d = {} + images = {} + + for chname, chdata in channels.items(): + ptype = chdata['plot_type'] + if ptype == PlotType.No: + continue + elif ptype == PlotType.Spectrum: + axes = tuple(chdata['plot_axes']) + # TODO: get default value from the channel. + ndim = chdata.get('ndim', 0) or 0 + if ndim == 0: # this is a trend + if axes in trends1d: + trends1d[axes].append(chname) + else: + trends1d[axes] = CaselessList([chname]) + elif ndim == 1: # a 1D plot (e.g. a spectrum) + pass # TODO: implement + else: + self.warning('Cannot create plot for %s', chname) + + elif ptype == PlotType.Image: + axes = tuple(chdata['plot_axes']) + # TODO: get default value from the channel. + ndim = chdata.get('ndim', 1) + if ndim == 0: # a mesh-like plot? + pass # TODO implement + elif ndim == 1: # a 2D trend + if axes in trends2d: + trends2d[axes].append(chname) + else: + trends2d[axes] = CaselessList([chname]) + elif ndim == 2: # a 2D plot (e.g. an image) + pass # TODO: implement + else: + self.warning('Cannot create plot for %s', chname) + + new1d, removed1d = self._updateTemporaryTrends1D(trends1d) + self.newShortMessage.emit("Changed panels (%i new, %i removed)" % (len(new1d), + len(removed1d))) +# self._updateTemporaryTrends2D(trends2d) + + def _updateTemporaryTrends1D(self, trends1d): + '''adds necessary trend1D panels and removes no longer needed ones + + :param trends1d: (dict) A dict whose keys are tuples of axes and + whose values are list of model names to plot + + :returns: (tuple) two lists new,rm:new contains the names of the new + panels and rm contains the names of the removed panels + ''' + from taurus.qt.qtgui.plot import TaurusTrend # TODO: use tpg instead! + newpanels = [] + for axes, plotables in trends1d.items(): + if not axes: + continue + if axes not in self._trends1d: + w = TaurusTrend() + w.setXIsTime(False) + w.setScanDoor(self.getModelObj().fullname) + # TODO: use a standard key for and + w.setScansXDataKey(axes[0]) + pname = u'Trend1D - %s' % ":".join(axes) + panel = self.createPanel(w, pname, registerconfig=False, + permanent=False) + try: # if the panel is a dockwidget, raise it + panel.raise_() + except: + pass + self._trends1d[axes] = pname + newpanels.append(pname) + + widget = self.getPanelWidget(self._trends1d[axes]) + flt = ChannelFilter(plotables) + widget.onScanPlotablesFilterChanged(flt) + + # remove trends that are no longer configured + removedpanels = [] + olditems = list(self._trends1d.items()) + for axes, name in olditems: + if axes not in trends1d: + removedpanels.append(name) + self.removePanel(name) + self._trends1d.pop(axes) + + return newpanels, removedpanels + + def _updateTemporaryTrends2D(self, trends2d): + '''adds necessary trend2D panels and removes no longer needed ones + + :param trends2d: (dict) A dict whose keys are tuples of axes and + whose values are list of model names to plot + + :returns: (tuple) two lists new,rm:new contains the names of the new + panels and rm contains the names of the removed panels + + ..note:: Not fully implemented yet + ''' + try: + from taurus.qt.qtgui.extra_guiqwt.taurustrend2d import \ + TaurusTrend2DDialog + from taurus.qt.qtgui.extra_guiqwt.image import TaurusTrend2DScanItem + except: + self.info('guiqwt extension cannot be loaded. ' + + '2D Trends will not be created') + raise + return + + for axes, plotables in trends2d.items(): + for chname in plotables: + pname = u'Trend2D - %s' % chname + if pname in self._trends2d: + self._trends2d[pname].widget().trendItem.clearTrend() + else: + axis = axes[0] + w = TaurusTrend2DDialog(stackMode='event') + plot = w.get_plot() + t2d = TaurusTrend2DScanItem(chname, axis, + self.getModelObj().fullname) + plot.add_item(t2d) + self.createPanel(w, pname, registerconfig=False, + permanent=False) + self._trends2d[(axes, chname)] = pname + + def createPanel(self, widget, name, **kwargs): + '''Creates a "panel" from a widget. In this basic implementation this + means that the widgets is shown as a non-modal top window + + :param widget: (QWidget) widget to be used for the panel + :param name: (str) name of the panel. Must be unique. + + Note: for backawards compatibility, this implementation accepts + arbitrary keyword arguments which are just ignored + ''' + widget.setWindowTitle(name) + widget.show() + self.__panels[name] = widget + + def getPanelWidget(self, name): + '''Returns the widget associated to a panel name + + :param name: (str) name of the panel. KeyError is raised if not found + + :return: (QWidget) + ''' + return self.__panels[name] + + def removePanel(self, name): + '''stop managing the given panel + + :param name: (str) name of the panel''' + widget = self.__panels.pop(name) + if hasattr(widget, 'setModel'): + widget.setModel(None) + widget.setParent(None) + widget.close() + + def removePanels(self, names=None): + '''removes panels. + + :param names: (seq) names of the panels to be removed. If None is + given (default), all the panels are removed. + ''' + if names is None: + names = list(self._trends1d.values()) + list(self._trends2d.values()) + # TODO: do the same for other temporary panels + for pname in names: + self.removePanel(pname) + + +class MacroBroker(DynamicPlotManager): + '''A manager of all macro-related panels of a TaurusGui. + + It creates, destroys and manages connections for the following objects: + + - Macro Configuration dialog + - Experiment Configuration panel + - Macro Executor panel + - Sequencer panel + - Macro description viewer + - Door output, result and debug panels + - Macro editor + - Macro "panic" button (to abort macros) + - Dynamic plots (see :class:`DynamicPlotManager`) + ''' + + def __init__(self, parent): + '''Passing the parent object (the main window) is mandatory''' + DynamicPlotManager.__init__(self, parent) + + self._createPermanentPanels() + + # connect the broker to shared data + Qt.qApp.SDM.connectReader("doorName", self.setModel) + Qt.qApp.SDM.connectReader("expConfChanged", self.onExpConfChanged) + Qt.qApp.SDM.connectWriter("shortMessage", self, 'newShortMessage') + + def setModel(self, doorname): + ''' Reimplemented from :class:`DynamicPlotManager`.''' + # disconnect the previous door + door = self.getModelObj() + if door is not None: # disconnect it from *all* shared data providing + SDM = Qt.qApp.SDM + try: + SDM.disconnectWriter("macroStatus", door, "macroStatusUpdated") + except: + self.info("Could not disconnect macroStatusUpdated") + try: + SDM.disconnectWriter("doorOutputChanged", door, "outputUpdated") + except: + self.info("Could not disconnect outputUpdated") + try: + SDM.disconnectWriter("doorInfoChanged", door, "infoUpdated") + except: + self.info("Could not disconnect infoUpdated") + try: + SDM.disconnectWriter("doorWarningChanged", door, + "warningUpdated") + except: + self.info("Could not disconnect warningUpdated") + try: + SDM.disconnectWriter("doorErrorChanged", door, "errorUpdated") + except: + self.info("Could not disconnect errorUpdated") + try: + SDM.disconnectWriter("doorDebugChanged", door, "debugUpdated") + except: + self.info("Could not disconnect debugUpdated") + try: + SDM.disconnectWriter("doorResultChanged", door, "resultUpdated") + except: + self.info("Could not disconnect resultUpdated") + try: + SDM.disconnectWriter("expConfChanged", door, + "experimentConfigurationChanged") + except: + self.info("Could not disconnect experimentConfigurationChanged") + # set the model + DynamicPlotManager.setModel(self, doorname) + + # connect the new door + door = self.getModelObj() + if door is not None: + SDM = Qt.qApp.SDM + SDM.connectWriter("macroStatus", door, "macroStatusUpdated") + SDM.connectWriter("doorOutputChanged", door, "outputUpdated") + SDM.connectWriter("doorInfoChanged", door, "infoUpdated") + SDM.connectWriter("doorWarningChanged", door, "warningUpdated") + SDM.connectWriter("doorErrorChanged", door, "errorUpdated") + SDM.connectWriter("doorDebugChanged", door, "debugUpdated") + SDM.connectWriter("doorResultChanged", door, "resultUpdated") + SDM.connectWriter("expConfChanged", door, + "experimentConfigurationChanged") + + def _createPermanentPanels(self): + '''creates panels on the main window''' + from sardana.taurus.qt.qtgui.extra_macroexecutor import \ + TaurusMacroExecutorWidget, TaurusSequencerWidget, \ + TaurusMacroConfigurationDialog, TaurusMacroDescriptionViewer, \ + DoorOutput, DoorDebug, DoorResult + + from sardana.taurus.qt.qtgui.extra_sardana import \ + ExpDescriptionEditor, SardanaEditor + + mainwindow = self.parent() + + # Create macroconfiguration dialog & action + self.__macroConfigurationDialog = \ + TaurusMacroConfigurationDialog(mainwindow) + self.macroConfigurationAction = mainwindow.taurusMenu.addAction( + Qt.QIcon.fromTheme("preferences-system-session"), + "Macro execution configuration...", + self.__macroConfigurationDialog.show) + + SDM = Qt.qApp.SDM + SDM.connectReader("macroserverName", + self.__macroConfigurationDialog.selectMacroServer) + SDM.connectReader("doorName", + self.__macroConfigurationDialog.selectDoor) + SDM.connectWriter("macroserverName", self.__macroConfigurationDialog, + 'macroserverNameChanged') + SDM.connectWriter("doorName", self.__macroConfigurationDialog, + 'doorNameChanged') + + # Create ExpDescriptionEditor dialog + self.__expDescriptionEditor = ExpDescriptionEditor(plotsButton=False) + SDM.connectReader("doorName", self.__expDescriptionEditor.setModel) + mainwindow.createPanel(self.__expDescriptionEditor, + 'Experiment Config', + registerconfig=True, + icon=Qt.QIcon.fromTheme('preferences-system'), + permanent=True) + ############################### + # TODO: These lines can be removed once the door does emit + # "experimentConfigurationChanged" signals + SDM.connectWriter("expConfChanged", self.__expDescriptionEditor, + "experimentConfigurationChanged") + ################################ + + # put a Macro Executor + self.__macroExecutor = TaurusMacroExecutorWidget() + SDM.connectReader("macroserverName", self.__macroExecutor.setModel) + SDM.connectReader("doorName", self.__macroExecutor.onDoorChanged) + SDM.connectReader("macroStatus", + self.__macroExecutor.onMacroStatusUpdated) + SDM.connectWriter("macroName", self.__macroExecutor, + "macroNameChanged") + SDM.connectWriter("executionStarted", self.__macroExecutor, + "macroStarted") + SDM.connectWriter("plotablesFilter", self.__macroExecutor, + "plotablesFilterChanged") + SDM.connectWriter("shortMessage", self.__macroExecutor, + "shortMessageEmitted") + mainwindow.createPanel(self.__macroExecutor, 'Macros', + registerconfig=True, permanent=True) + + # put a Sequencer + self.__sequencer = TaurusSequencerWidget() + SDM.connectReader("macroserverName", self.__sequencer.setModel) + SDM.connectReader("doorName", self.__sequencer.onDoorChanged) + SDM.connectReader("macroStatus", self.__sequencer.onMacroStatusUpdated) + SDM.connectWriter("macroName", self.__sequencer.tree, + "macroNameChanged") + SDM.connectWriter("macroName", self.__sequencer, + "macroNameChanged") + SDM.connectWriter("executionStarted", self.__sequencer, + "macroStarted") + SDM.connectWriter("plotablesFilter", self.__sequencer, + "plotablesFilterChanged") + SDM.connectWriter("shortMessage", self.__sequencer, + "shortMessageEmitted") + mainwindow.createPanel(self.__sequencer, 'Sequences', + registerconfig=True, permanent=True) + + # puts a macrodescriptionviewer + self.__macroDescriptionViewer = TaurusMacroDescriptionViewer() + SDM.connectReader("macroserverName", + self.__macroDescriptionViewer.setModel) + SDM.connectReader("macroName", + self.__macroDescriptionViewer.onMacroNameChanged) + mainwindow.createPanel(self.__macroDescriptionViewer, + 'MacroDescription', registerconfig=True, + permanent=True) + + # puts a doorOutput + self.__doorOutput = DoorOutput() + SDM.connectReader("doorOutputChanged", + self.__doorOutput.onDoorOutputChanged) + SDM.connectReader("doorInfoChanged", + self.__doorOutput.onDoorInfoChanged) + SDM.connectReader("doorWarningChanged", + self.__doorOutput.onDoorWarningChanged) + SDM.connectReader("doorErrorChanged", + self.__doorOutput.onDoorErrorChanged) + mainwindow.createPanel(self.__doorOutput, 'DoorOutput', + registerconfig=False, permanent=True) + + # puts doorDebug + self.__doorDebug = DoorDebug() + SDM.connectReader("doorDebugChanged", + self.__doorDebug.onDoorDebugChanged) + mainwindow.createPanel(self.__doorDebug, 'DoorDebug', + registerconfig=False, permanent=True) + + # puts doorResult + self.__doorResult = DoorResult(mainwindow) + SDM.connectReader("doorResultChanged", + self.__doorResult.onDoorResultChanged) + mainwindow.createPanel(self.__doorResult, 'DoorResult', + registerconfig=False, permanent=True) + + # puts sardanaEditor + # self.__sardanaEditor = SardanaEditor() + # SDM.connectReader("macroserverName", self.__sardanaEditor.setModel) + # mainwindow.createPanel(self.__sardanaEditor, 'SardanaEditor', + # registerconfig=False, permanent=True) + + # add panic button for aborting the door + text = "Panic Button: stops the pool (double-click for abort)" + self.doorAbortAction = mainwindow.jorgsBar.addAction( + Qt.QIcon("actions:process-stop.svg"), + text, self.__onDoorAbort) + + # store beginning of times as a datetime + self.__lastAbortTime = datetime.datetime(1, 1, 1) + + # store doubleclick interval as a timedelta + td = datetime.timedelta(0, 0, 1000 * Qt.qApp.doubleClickInterval()) + self.__doubleclickInterval = td + + def __onDoorAbort(self): + '''slot to be called when the abort action is triggered. + It sends stop command to the pools (or abort if the action + has been triggered twice in less than self.__doubleclickInterval + + .. note:: An abort command is always preceded by an stop command + ''' + # decide whether to send stop or abort + now = datetime.datetime.now() + if now - self.__lastAbortTime < self.__doubleclickInterval: + cmd = 'abort' + else: + cmd = 'stop' + + door = self.getModelObj() + + # abort the door + door.command_inout('abort') + # send stop/abort to all pools + pools = door.macro_server.getElementsOfType('Pool') + for pool in pools.values(): + self.info('Sending %s command to %s' % (cmd, pool.getFullName())) + try: + pool.getObj().command_inout(cmd) + except: + self.info('%s command failed on %s', cmd, pool.getFullName(), + exc_info=1) + self.newShortMessage.emit("%s command sent to all pools" % + cmd) + self.__lastAbortTime = now + + def createPanel(self, widget, name, **kwargs): + ''' Reimplemented from :class:`DynamicPlotManager` to delegate panel + management to the parent widget (a TaurusGui)''' + mainwindow = self.parent() + return mainwindow.createPanel(widget, name, **kwargs) + + def getPanelWidget(self, name): + ''' Reimplemented from :class:`DynamicPlotManager` to delegate panel + management to the parent widget (a TaurusGui)''' + mainwindow = self.parent() + return mainwindow.getPanel(name).widget() + + def removePanel(self, name): + ''' Reimplemented from :class:`DynamicPlotManager` to delegate panel + management to the parent widget (a TaurusGui)''' + mainwindow = self.parent() + mainwindow.removePanel(name) + + def removeTemporaryPanels(self, names=None): + '''Remove temporary panels managed by this widget''' + # for now, the only temporary panels are the plots + DynamicPlotManager.removePanels(self, names=names) + + +if __name__ == "__main__": + import sys + from taurus.qt.qtgui.application import TaurusApplication + + app = TaurusApplication() + + b = DynamicPlotManager(None) + + b.setModel('door/cp1/1') + + print('...') + sys.exit(app.exec_()) From eed36b9176a05fd066c2d57a82ef35db99ab48d8 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Mon, 21 Jan 2019 10:21:45 +0100 Subject: [PATCH 512/652] Add try/except in macrolistener module. This solves the bug of Door connection in macrogui creation when using pyqt5. --- .../taurus/qt/qtgui/macrolistener/macrolistener.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py b/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py index 5946164cbc..37f9750388 100644 --- a/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py +++ b/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py @@ -181,10 +181,15 @@ def onExpConfChanged(self, expconf): pass # TODO: implement else: self.warning('Cannot create plot for %s', chname) - - new1d, removed1d = self._updateTemporaryTrends1D(trends1d) - self.newShortMessage.emit("Changed panels (%i new, %i removed)" % (len(new1d), - len(removed1d))) + try: + # TODO: adapt _updateTemporaryTrends1D to use tpg + new1d, removed1d = self._updateTemporaryTrends1D(trends1d) + self.newShortMessage.emit("Changed panels (%i new, %i removed)" + % (len(new1d), len(removed1d))) + except: + self.warning( + 'Plots cannot be updated. Only qwt5 is supported for now' + ) # self._updateTemporaryTrends2D(trends2d) def _updateTemporaryTrends1D(self, trends1d): From 81296987cb859405e8ea300423cbb7370c320372 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Mon, 21 Jan 2019 10:47:44 +0100 Subject: [PATCH 513/652] Fix flake8 in extra_hkl and extra_pool modules Fix flake8 in sardana extra_hkl and extra_pool modules. --- src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py | 1 - src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py index bc3ad6f5a2..3c273ce691 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py @@ -97,7 +97,6 @@ def update_signals(self, doorname=''): mg_name = conf['ActiveMntGrp'] mg = PyTango.DeviceProxy(mg_name) signals = mg.ElementList - self.signalComboBox.loadSignals(signals) def onSignalChanged(self, signalname): diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py index f66638c922..df4d4d36c8 100644 --- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py +++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py @@ -1470,7 +1470,7 @@ def setModel(self, model): self.updatePosition) except TypeError: pass - + try: # remove listeners if self.motor_dev is not None: From 87063832ba6e6fea5be97b620cc8337c08f77781 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Mon, 21 Jan 2019 10:54:48 +0100 Subject: [PATCH 514/652] Update changelog adding macrolistener Added sardana.taurus.qt.qtgui.macrolistener to sardana. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 654197c18e..74631748b7 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ This file follows the formats and conventions from [keepachangelog.com] - Top LICENSE file that applies to the whole project (#938) - Document remote connection to MacroServer Python process (RConsolePort Tango property) (#984) +- sardana.taurus.qt.qtgui.macrolistener (moved from taurus.qt.qtgui.taurusgui) ### Fixed - Do not read 1D and 2D experimental channels during software acquisition loop From 17bf224cf7a71d5c5a58de44171d4b233c2ce8aa Mon Sep 17 00:00:00 2001 From: mrosanes Date: Mon, 21 Jan 2019 11:21:44 +0100 Subject: [PATCH 515/652] Fix flake8 in sardana macrolistener --- .../taurus/qt/qtgui/macrolistener/__init__.py | 3 +- .../qt/qtgui/macrolistener/macrolistener.py | 72 ++++++++++--------- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py b/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py index 7aa40454fd..0fea0853e3 100755 --- a/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py +++ b/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py @@ -28,4 +28,5 @@ __docformat__ = 'restructuredtext' -from .macrolistener import * \ No newline at end of file +from .macrolistener import * # noqa: F401,F403 + diff --git a/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py b/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py index 37f9750388..db8251773c 100644 --- a/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py +++ b/src/sardana/taurus/qt/qtgui/macrolistener/macrolistener.py @@ -27,8 +27,8 @@ This module provides objects to manage macro-related tasks. Its primary use is to be used within a TaurusGui for managing panels for: - setting preferences in the sardana control system for data I/O -- displaying results of macro executions, including creating/removing panels for - plotting results of scans +- displaying results of macro executions, including creating/removing panels + for plotting results of scans - editing macros .. note:: This module was originally implemented in taurus as @@ -108,12 +108,12 @@ def _checkJsonRecorder(self): '''Checks if JsonRecorder env var is set and offers to set it''' door = self.getModelObj() if 'JsonRecorder' not in door.getEnvironment(): - msg = ('JsonRecorder environment variable is not set, but it ' + - 'is needed for displaying trend plots.\n' + - 'Enable it globally for %s?') % door.fullname - result = Qt.QMessageBox.question(self.parent(), - 'JsonRecorder not set', msg, - Qt.QMessageBox.Yes | Qt.QMessageBox.No) + msg = ('JsonRecorder environment variable is not set, but it ' + + 'is needed for displaying trend plots.\n' + + 'Enable it globally for %s?') % door.fullname + result = Qt.QMessageBox.question( + self.parent(), 'JsonRecorder not set', msg, + Qt.QMessageBox.Yes | Qt.QMessageBox.No) if result == Qt.QMessageBox.Yes: door.putEnvironment('JsonRecorder', True) self.info('JsonRecorder Enabled for %s' % door.fullname) @@ -145,8 +145,6 @@ def onExpConfChanged(self, expconf): # classify by type of plot: trends1d = {} trends2d = {} - plots1d = {} - images = {} for chname, chdata in channels.items(): ptype = chdata['plot_type'] @@ -186,7 +184,7 @@ def onExpConfChanged(self, expconf): new1d, removed1d = self._updateTemporaryTrends1D(trends1d) self.newShortMessage.emit("Changed panels (%i new, %i removed)" % (len(new1d), len(removed1d))) - except: + except Exception: self.warning( 'Plots cannot be updated. Only qwt5 is supported for now' ) @@ -217,7 +215,7 @@ def _updateTemporaryTrends1D(self, trends1d): permanent=False) try: # if the panel is a dockwidget, raise it panel.raise_() - except: + except Exception: pass self._trends1d[axes] = pname newpanels.append(pname) @@ -251,10 +249,11 @@ def _updateTemporaryTrends2D(self, trends2d): try: from taurus.qt.qtgui.extra_guiqwt.taurustrend2d import \ TaurusTrend2DDialog - from taurus.qt.qtgui.extra_guiqwt.image import TaurusTrend2DScanItem - except: - self.info('guiqwt extension cannot be loaded. ' + - '2D Trends will not be created') + from taurus.qt.qtgui.extra_guiqwt.image import ( + TaurusTrend2DScanItem) + except Exception: + self.info('guiqwt extension cannot be loaded. ' + + '2D Trends will not be created') raise return @@ -314,7 +313,8 @@ def removePanels(self, names=None): given (default), all the panels are removed. ''' if names is None: - names = list(self._trends1d.values()) + list(self._trends2d.values()) + names = (list(self._trends1d.values()) + + list(self._trends2d.values())) # TODO: do the same for other temporary panels for pname in names: self.removePanel(pname) @@ -354,39 +354,43 @@ def setModel(self, doorname): if door is not None: # disconnect it from *all* shared data providing SDM = Qt.qApp.SDM try: - SDM.disconnectWriter("macroStatus", door, "macroStatusUpdated") - except: + SDM.disconnectWriter("macroStatus", door, + "macroStatusUpdated") + except Exception: self.info("Could not disconnect macroStatusUpdated") try: - SDM.disconnectWriter("doorOutputChanged", door, "outputUpdated") - except: + SDM.disconnectWriter("doorOutputChanged", door, + "outputUpdated") + except Exception: self.info("Could not disconnect outputUpdated") try: SDM.disconnectWriter("doorInfoChanged", door, "infoUpdated") - except: + except Exception: self.info("Could not disconnect infoUpdated") try: SDM.disconnectWriter("doorWarningChanged", door, "warningUpdated") - except: + except Exception: self.info("Could not disconnect warningUpdated") try: SDM.disconnectWriter("doorErrorChanged", door, "errorUpdated") - except: + except Exception: self.info("Could not disconnect errorUpdated") try: SDM.disconnectWriter("doorDebugChanged", door, "debugUpdated") - except: + except Exception: self.info("Could not disconnect debugUpdated") try: - SDM.disconnectWriter("doorResultChanged", door, "resultUpdated") - except: + SDM.disconnectWriter("doorResultChanged", door, + "resultUpdated") + except Exception: self.info("Could not disconnect resultUpdated") try: SDM.disconnectWriter("expConfChanged", door, "experimentConfigurationChanged") - except: - self.info("Could not disconnect experimentConfigurationChanged") + except Exception: + self.info( + "Could not disconnect experimentConfigurationChanged") # set the model DynamicPlotManager.setModel(self, doorname) @@ -412,7 +416,7 @@ def _createPermanentPanels(self): DoorOutput, DoorDebug, DoorResult from sardana.taurus.qt.qtgui.extra_sardana import \ - ExpDescriptionEditor, SardanaEditor + ExpDescriptionEditor mainwindow = self.parent() @@ -470,7 +474,8 @@ def _createPermanentPanels(self): self.__sequencer = TaurusSequencerWidget() SDM.connectReader("macroserverName", self.__sequencer.setModel) SDM.connectReader("doorName", self.__sequencer.onDoorChanged) - SDM.connectReader("macroStatus", self.__sequencer.onMacroStatusUpdated) + SDM.connectReader("macroStatus", + self.__sequencer.onMacroStatusUpdated) SDM.connectWriter("macroName", self.__sequencer.tree, "macroNameChanged") SDM.connectWriter("macroName", self.__sequencer, @@ -564,11 +569,10 @@ def __onDoorAbort(self): self.info('Sending %s command to %s' % (cmd, pool.getFullName())) try: pool.getObj().command_inout(cmd) - except: + except Exception: self.info('%s command failed on %s', cmd, pool.getFullName(), exc_info=1) - self.newShortMessage.emit("%s command sent to all pools" % - cmd) + self.newShortMessage.emit("%s command sent to all pools" % cmd) self.__lastAbortTime = now def createPanel(self, widget, name, **kwargs): From b6c8c88caf6ae88046260f83f0b03acc3369881e Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Mon, 21 Jan 2019 11:17:36 +0100 Subject: [PATCH 516/652] Fix signal connections in SardanaEnvironmentModel A previous commit for adapting signals to new-style introduced a bug in SardanaEnvironmentModel.setDataSource. Fix it. --- src/sardana/taurus/qt/qtcore/tango/sardana/model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/model.py b/src/sardana/taurus/qt/qtcore/tango/sardana/model.py index 9f33b6f88e..0719bea8c1 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/model.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/model.py @@ -391,9 +391,9 @@ def __init__(self, parent=None, data=None): def setDataSource(self, data_source): old_ds = self.dataSource() if old_ds is not None: - old_ds.environmentChanged(self.on_environment_changed) + old_ds.environmentChanged.disconnect(self.on_environment_changed) if data_source is not None: - data_source.environmentChanged(self.on_environment_changed) + data_source.environmentChanged.connect(self.on_environment_changed) TaurusBaseModel.setDataSource(self, data_source) def on_environment_changed(self): From eb6e1da71059ecc0de1c6b6aedb7c26c7e1670a3 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Mon, 21 Jan 2019 12:08:54 +0100 Subject: [PATCH 517/652] Select overloaded signals explicitly in extra_hkl Some connections in the extra_hkl module are not properly selecting the desired overloaded signal, which leads to hard to debug errors. Make explicit selections of the overloaded signals and use pyqtSlot decorators in the corrsponding slots. --- .../qt/qtgui/extra_hkl/diffractometeralignment.py | 3 ++- src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py | 3 ++- src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py | 10 +++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py b/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py index cb5502da98..560e4986ba 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/diffractometeralignment.py @@ -201,7 +201,7 @@ def setModel(self, model): self.enginemodescombobox.loadEngineModeNames(self.device.hklmodelist) - self.enginemodescombobox.currentIndexChanged.connect( + self.enginemodescombobox.currentIndexChanged['QString'].connect( self.onModeChanged) # Add dynamically the scan buttons, range inputs and 'to max' buttons @@ -313,6 +313,7 @@ def tomax_scan(self, imot): macro_command = ["mv", motor, position] self.door_device.RunMacro(macro_command) + @Qt.pyqtSlot('QString') def onModeChanged(self, modename): if self.device.engine != "hkl": self.device.write_attribute("engine", "hkl") diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py b/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py index 1efcf6e1a8..3300f8f36e 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/hklscan.py @@ -179,9 +179,10 @@ def setModel(self, model): self.enginemodescombobox.loadEngineModeNames(self.device.hklmodelist) - self.enginemodescombobox.currentIndexChanged.connect( + self.enginemodescombobox.currentIndexChanged['QString'].connect( self.onModeChanged) + @Qt.pyqtSlot('QString') def onModeChanged(self, modename): if self.device.engine != "hkl": self.device.write_attribute("engine", "hkl") diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py b/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py index 668b5956a3..ce8f82a7ba 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py @@ -153,7 +153,8 @@ def setModel(self, model): self.enginescombobox.loadItems(self.device.enginelist) - self.enginescombobox.currentIndexChanged.connect(self.onEngineChanged) + self.enginescombobox.currentIndexChanged['QString'].connect( + self.onEngineChanged) enginemodemodel = model + '/enginemode' self._ui.taurusLabelEngineMode.setModel(enginemodemodel) @@ -164,7 +165,7 @@ def setModel(self, model): self.enginemodescombobox.loadItems(self.device.enginemodelist) - self.enginemodescombobox.currentIndexChanged.connect( + self.enginemodescombobox.currentIndexChanged['QString'].connect( self.onModeChanged) # Set model to crystal @@ -178,15 +179,18 @@ def setModel(self, model): self.crystalscombobox.loadItems(self.device.crystallist) - self.crystalscombobox.currentIndexChanged.connect( + self.crystalscombobox.currentIndexChanged['QString'].connect( self.onCrystalChanged) + Qt.pyqtSlot('Qstring') def onEngineChanged(self, enginename): self.device.write_attribute("engine", str(enginename)) + Qt.pyqtSlot('Qstring') def onModeChanged(self, modename): self.device.write_attribute("enginemode", str(modename)) + Qt.pyqtSlot('Qstring') def onCrystalChanged(self, crystalname): if str(crystalname) != "": self.device.write_attribute("crystal", str(crystalname)) From 8385b1b89e2d02c7e68b78e64897001c3e1cbc76 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Mon, 21 Jan 2019 12:09:58 +0100 Subject: [PATCH 518/652] Fix syntax error in signal connection --- src/sardana/taurus/qt/qtgui/extra_hkl/computeu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/computeu.py b/src/sardana/taurus/qt/qtgui/extra_hkl/computeu.py index 2134d98d9c..3c4046ecbf 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/computeu.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/computeu.py @@ -42,7 +42,7 @@ def __init__(self, parent=None, designMode=False): self.loadUi(filename="computeu.ui") - self._ui.ComputeButton.clicked().connect(self.compute_u) + self._ui.ComputeButton.clicked.connect(self.compute_u) @classmethod def getQtDesignerPluginInfo(cls): From 68893b17dafd78ed80afa87b9334f1515fbfdc73 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Mon, 21 Jan 2019 14:19:18 +0100 Subject: [PATCH 519/652] Fix syntax error in signal signature A previous commit introduced a syntax error ('Qstring' instead of 'QString'). Fix it --- src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py b/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py index ce8f82a7ba..bdb8a85d3e 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/ubmatrix.py @@ -182,15 +182,15 @@ def setModel(self, model): self.crystalscombobox.currentIndexChanged['QString'].connect( self.onCrystalChanged) - Qt.pyqtSlot('Qstring') + Qt.pyqtSlot('QString') def onEngineChanged(self, enginename): self.device.write_attribute("engine", str(enginename)) - Qt.pyqtSlot('Qstring') + Qt.pyqtSlot('QString') def onModeChanged(self, modename): self.device.write_attribute("enginemode", str(modename)) - Qt.pyqtSlot('Qstring') + Qt.pyqtSlot('QString') def onCrystalChanged(self, crystalname): if str(crystalname) != "": self.device.write_attribute("crystal", str(crystalname)) From d542a92d04c1a5a788e9d472d82bb8ed5521053a Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 21 Jan 2019 15:55:50 +0100 Subject: [PATCH 520/652] Using taurus.Device. Changing to IndexChanged with QString argument --- src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py index 3c273ce691..506ad7f3af 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py @@ -69,7 +69,7 @@ def __init__(self, parent=None, designMode=False): self.signalComboBox.setGeometry(QtCore.QRect(70, 50, 161, 27)) self.signalComboBox.setObjectName("SignalcomboBox") - self.signalComboBox.currentTextChanged.connect(self.onSignalChanged) + self.signalComboBox.currentIndexChanged['QString'].connect(self.onSignalChanged) self.doorName = None self.door_device = None @@ -95,7 +95,7 @@ def update_signals(self, doorname=''): signals = [] conf = self.door_device.getExperimentConfiguration() mg_name = conf['ActiveMntGrp'] - mg = PyTango.DeviceProxy(mg_name) + mg = taurus.Device(mg_name) signals = mg.ElementList self.signalComboBox.loadSignals(signals) From 154b91e92c508f3bf6024fbb59ebbfc5a74b4f95 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Tue, 22 Jan 2019 09:53:41 +0100 Subject: [PATCH 521/652] Fix PC broken in SEP18 - clear buffers before each acquisition Physical elements of the pseudo counters need to clear the buffers before each acquisition. In SEP18 this was moved to the acqusition preparation, but needs to be done in the acqusition start, otherwise step scans does not works. --- src/sardana/pool/poolacquisition.py | 31 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 825e1e663c..527935bae1 100755 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -371,21 +371,6 @@ def prepare(self, config, acq_mode, value, synchronization=None, ctrls_sw = [] ctrls_sw_start = [] - for elem in self.get_elements(): - elem.put_state(None) - # TODO: temporarily clear value buffers at the beginning of the - # acquisition instead of doing it in the finish hook of each - # acquisition sub-actions. See extensive explanation in the - # constructor of PoolAcquisitionBase. - try: - elem.clear_value_buffer() - except AttributeError: - continue - # clean also the pseudo counters, even the ones that do not - # participate directly in the acquisition - for pseudo_elem in elem.get_pseudo_elements(): - pseudo_elem.clear_value_buffer() - repetitions = synchronization.repetitions latency = synchronization.passive_time # Prepare controllers synchronized by hardware @@ -501,6 +486,22 @@ def is_running(self): def run(self, *args, **kwargs): """Runs acquisition according to previous preparation.""" + + for elem in self.get_elements(): + elem.put_state(None) + # TODO: temporarily clear value buffers at the beginning of the + # acquisition instead of doing it in the finish hook of each + # acquisition sub-actions. See extensive explanation in the + # constructor of PoolAcquisitionBase. + try: + elem.clear_value_buffer() + except AttributeError: + continue + # clean also the pseudo counters, even the ones that do not + # participate directly in the acquisition + for pseudo_elem in elem.get_pseudo_elements(): + pseudo_elem.clear_value_buffer() + if self._hw_acq_args is not None: self._hw_acq.run(*self._hw_acq_args.args, **self._hw_acq_args.kwargs) From d3f60003b13a5a52a8f72406fe7df33431ffc004 Mon Sep 17 00:00:00 2001 From: cfalcon Date: Tue, 22 Jan 2019 10:40:32 +0100 Subject: [PATCH 522/652] Fix issue with experimentConfigurationChanged signal The signal has a wrong signature and it is not well used. Fix it --- .../taurus/qt/qtcore/tango/sardana/macroserver.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index a5ca37efdb..066aca32c7 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -28,6 +28,7 @@ __all__ = ["QDoor", "QMacroServer", "MacroServerMessageErrorHandler", "registerExtensions"] +import copy from taurus.core.taurusbasetypes import TaurusEventType from taurus.external.qt import Qt @@ -52,7 +53,7 @@ class QDoor(BaseDoor, Qt.QObject): infoUpdated = Qt.pyqtSignal(object) outputUpdated = Qt.pyqtSignal(object) debugUpdated = Qt.pyqtSignal(object) - experimentConfigurationChanged = Qt.pyqtSignal() + experimentConfigurationChanged = Qt.pyqtSignal(object) elementsChanged = Qt.pyqtSignal() environmentChanged = Qt.pyqtSignal() @@ -98,7 +99,7 @@ def _prepare_connections(self): if not self._use_experiment_configuration and \ not self._connections_prepared: self.macro_server.environmentChanged.connect( - self._experimentConfigurationChanged) + self._onExperimentConfigurationChanged) self.macro_server.elementsChanged.connect(self._elementsChanged) self._elementsChanged() self._connections_prepared = True @@ -113,15 +114,16 @@ def _elementsChanged(self): mntgrp_changed = True # this measurement group is new obj = mg.getObj() obj.configurationChanged.connect( - self._experimentConfigurationChanged) + self._onExperimentConfigurationChanged) new_mntgrp_connected.append(name) self._mntgrp_connected = new_mntgrp_connected if mntgrp_changed: - self.experimentConfigurationChanged.emit() + self._onExperimentConfigurationChanged() - def _experimentConfigurationChanged(self, *args): - self.experimentConfigurationChanged.emit() + def _onExperimentConfigurationChanged(self, *args): + conf = copy.deepcopy(BaseDoor.getExperimentConfiguration(self)) + self.experimentConfigurationChanged.emit(conf) def getExperimentConfigurationObj(self): self._prepare_connections() From 190852bfc6001a4a72abc026d91f22ddf14a6619 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Tue, 22 Jan 2019 11:50:38 +0100 Subject: [PATCH 523/652] Fix exception messages format --- src/sardana/sardanabuffer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/sardanabuffer.py b/src/sardana/sardanabuffer.py index ba747c3da2..1b93fc5539 100644 --- a/src/sardana/sardanabuffer.py +++ b/src/sardana/sardanabuffer.py @@ -128,7 +128,7 @@ def get_value_obj(self, idx): try: return self._buffer[idx] except KeyError: - msg = "value with %s index is not in buffer" + msg = "value with %s index is not in buffer" % idx if self.next_idx > idx: raise LateValueException(msg) else: @@ -191,7 +191,7 @@ def remove(self, idx): try: return self._buffer.pop(idx) except KeyError: - msg = "value with %s index is not in buffer" + msg = "value with %s index is not in buffer" % idx raise KeyError(msg) def fire_add_event(self, propagate=1): From 1522e64ec951b9dd59ab498a13baf5b787006335 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Tue, 22 Jan 2019 13:28:34 +0100 Subject: [PATCH 524/652] Fix bad syntax in DoorAttrListener DoorAttrListener is a deprecated and unused class that wil soon be removed. Its old code (using old-style signals) emitted a signal called doorChanged. An attempt to port it to new-style signals was done in a previous copmmit, but it is not ok. remove the signal emit altogether (not worth wasting time in this class that will be removed). --- .../taurus/qt/qtgui/extra_macroexecutor/dooroutput.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py index c9008bb17e..1a9af58a31 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/dooroutput.py @@ -182,14 +182,14 @@ def contextMenuEvent(self, event): #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- class DoorAttrListener(Qt.QObject): + """Deprecated. Do not use""" def __init__(self, attrName): Qt.QObject.__init__(self) from taurus.core.util.log import deprecated - deprecated(msg="Do not use", rel="Jan19") + deprecated(dep="DoorAttrListener", rel="2.5.1") self.attrName = attrName self.attrObj = None - setattr(self, 'door%sChanged' % self.attrName, Qt.pyqtSignal('object')) def setDoorName(self, doorName): if not self.attrObj is None: @@ -202,9 +202,12 @@ def eventReceived(self, src, type, value): type == taurus.core.taurusbasetypes.TaurusEventType.Config): return + # The old code (using old-style signals) emitted a signal called + # doorChanged . Emulating this with new-style signasl + # is problematic, and in this case it is not worth it since this class + # is unused, deprecated and will disappear soon # self.emit(Qt.SIGNAL('door%sChanged' % self.attrName), value.value) - signal = getattr(self, 'door%sChanged' % self.attrName) - signal.emit(value.value) + if __name__ == "__main__": From 7cfb13321af6c65c0073669f46ed41a21e8cd54d Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Tue, 22 Jan 2019 13:32:52 +0100 Subject: [PATCH 525/652] Improve check of whether an object is a pyqtSignal Some tech dept was left in a previous commit regarding how to differentiate a pyqtSignal from an iterable. Pay the debt. --- .../qtgui/extra_macroexecutor/macrobutton.py | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py index 9be8efa522..80407dfa0d 100755 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py @@ -260,14 +260,28 @@ def connectArgEditors(self, signals): """ for i, signal in enumerate(signals): - # TODO: if possible, better check that this is not a pyqtsignal - if isinstance(signal, (tuple, list, set)): - obj, sig = signal - msg = "Old style PyQt signals is deprecated: %s" - self.deprecated(msg) - signal = getattr(obj, sig.split('(')[0]) + if not self.__isSignal(signal): + # bck-compat: (sender, sig) tuples used instead of pyqtsignals + sender, sig = signal + msg = "Old style signals are deprecated: " + self.deprecated( + dep='Passing (sender, signature) tuples', + alt='pyqtSignal objects', + rel='2.5.1' + ) + signal = getattr(sender, sig.split('(')[0]) signal.connect(functools.partial(self.updateMacroArgument, i)) + @staticmethod + def __isSignal(obj): + if not hasattr(obj, 'emit'): + return False + if not hasattr(obj, 'connect'): + return False + if not hasattr(obj, 'disconnect'): + return False + return True + def _onButtonClicked(self): if self.ui.button.isChecked(): self.runMacro() From eb97976aec3497f27ed0f3db69d57c9232051758 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Tue, 22 Jan 2019 13:35:33 +0100 Subject: [PATCH 526/652] Improve import error message for Qsci Provide some more meaningful error when attempting to import Qsci from PyQt4. --- .../taurus/qt/qtgui/extra_macroexecutor/macroeditor.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py index 42f3bd4eaa..0f293d776b 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py @@ -24,7 +24,13 @@ ############################################################################## from taurus.external.qt import Qt, compat -from PyQt4 import Qsci + +try: + # TODO: Check if qscintilla can be used with other bindings + from PyQt4 import Qsci +except Exception as e: + raise ImportError('MacroEditor requires Qsci (qscintilla): %r', e) + from taurus.qt.qtgui.resource import getThemeIcon From 4e8e263d9a6b44cad0df906b3c2bf83597688986 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Tue, 22 Jan 2019 13:37:30 +0100 Subject: [PATCH 527/652] Use 'QString' instead of str for a signal signature Using str in signatures is problematic because it does not account for the various string types. Use 'QString' instead. --- .../taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index a310fadab7..3eeeca9531 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -59,7 +59,7 @@ def __init__(self, parent=None): class SpockCommandWidget(Qt.QLineEdit, TaurusBaseContainer): pressedReturn = Qt.pyqtSignal() - spockComboBox = Qt.pyqtSignal(str) + spockComboBox = Qt.pyqtSignal('Qstring') elementUp = Qt.pyqtSignal() elementDown = Qt.pyqtSignal() setHistoryFocus = Qt.pyqtSignal() From 15427b6f2e3bb9ffc0d8cd93b9fd557ecd463005 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Tue, 22 Jan 2019 13:39:53 +0100 Subject: [PATCH 528/652] Improve check of used Qt API Change a check from using the QT_API environment variable to using the from taurus.external.qt.PYQT4 variable (which is more robust) --- .../taurus/qt/qtgui/extra_sardana/expdescription.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 542cbc2d27..a9013ace50 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -238,11 +238,11 @@ def __init__(self, parent=None, door=None, plotsButton=True, # TODO: Disable show scan button since scan plot have to be # adapted to support QT5 # -------------------------------------------------------------------- - import os - if os.getenv('QT_API') == 'pyqt5': - self.debug('Show plots is not ready for QT5') + from taurus.external.qt import PYQT4, QT_API + if not PYQT4: + self.debug('Show plots is only supported with PyQt4 for now') plotsButton = False - tooltip = "Show/Hide plots is not ready for QT5" + tooltip = "Show/Hide plots is not ready for %s" % QT_API # -------------------------------------------------------------------- icon = resource.getIcon(":/actions/view.svg") From 590f8963b00244ca69479fd8ff2277b658f3e971 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Tue, 22 Jan 2019 13:41:27 +0100 Subject: [PATCH 529/652] Use explicit signature for overloaded signal A connection is done using the default overload of currentIndexChanged implicitly. Change it to use it explicitly to facilitate debugging. --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index a9013ace50..0fc6ef99e4 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -217,7 +217,7 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.createMntGrp) self.ui.deleteMntGrpBT.clicked.connect( self.deleteMntGrp) - self.ui.compressionCB.currentIndexChanged.connect( + self.ui.compressionCB.currentIndexChanged['int'].connect( self.onCompressionCBChanged) self.ui.pathLE.textEdited.connect( self.onPathLEEdited) @@ -631,6 +631,7 @@ def deleteMntGrp(self): self.ui.channelEditor.getQModel().setDataSource({}) self._setDirty(True) + @Qt.pyqtSlot('int') def onCompressionCBChanged(self, idx): if self._localConfig is None: return From d2f436a8e7a1a02509bb6844256f54c5f395936b Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Tue, 22 Jan 2019 13:42:28 +0100 Subject: [PATCH 530/652] Avoid using QString API QString is not available in APIv2. Use python str instead. --- .../macroparameterseditor/customeditors/senv.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py index eb9dd31122..0ad5dfa871 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/customeditors/senv.py @@ -75,6 +75,7 @@ def setModel(self, model): self.setRootIndex(Qt.QModelIndex()) def onNameComboBoxChanged(self, index): + # note that the index parameter is ignored! text = str(self.nameComboBox.currentText()) if self.valueWidget is not None: label = self.layout().labelForField(self.valueWidget) @@ -326,7 +327,7 @@ def headerData(self, section, orientation, role=Qt.Qt.DisplayRole): return "Instrument" return None else: - return Qt.QString.number(section + 1) + return str(section + 1) def flags(self, index): flags = Qt.Qt.ItemIsEnabled | Qt.Qt.ItemIsSelectable From 5527e0dc29af0f71139206669570fab69c7d7eaf Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Tue, 22 Jan 2019 13:43:20 +0100 Subject: [PATCH 531/652] (m) a couple of PEP8 and minor style changes --- .../taurus/qt/qtgui/extra_macroexecutor/macroeditor.py | 4 ++-- .../extra_macroexecutor/sequenceeditor/sequenceeditor.py | 4 ++-- src/sardana/taurus/qt/qtgui/extra_sardana/macrotree.py | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py index 0f293d776b..042eed69e3 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroeditor.py @@ -193,7 +193,7 @@ def maybeSave(self): def loadFile(self, fileName): try: fileHandle = open(fileName, 'r') - except IOError, e: + except IOError as e: Qt.QMessageBox.warning(self, "MacroEditor", "Cannot read file %s:\n%s." % (fileName, e)) return False @@ -208,7 +208,7 @@ def loadFile(self, fileName): def __saveFile(self, fileName): try: file = open(fileName, 'w') - except IOError, e: + except IOError as e: Qt.QMessageBox.warning( self, "MacroEditor", "Cannot write file %s:\n%s." % (fileName, e)) return False diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py index 5df641faa9..04b9deeea1 100755 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py @@ -664,7 +664,7 @@ def onSaveSequence(self): file = open(fileName, "w") file.write(self.tree.toXmlString(pretty=True, withId=False)) self.setSequencesPath(str.join("/", fileName.rsplit("/")[:-1])) - except Exception, e: + except Exception as e: Qt.QMessageBox.warning( self, "Error while saving macros sequence", @@ -896,7 +896,7 @@ def fromPlainText(self, plainText): try: macroServerObj.recreateMacroNodeAndFillAdditionalInfos( macroNode) - except Exception, e: + except Exception as e: Qt.QMessageBox.warning(self, "Error while parsing the sequence", "Sequence line number %d contains " diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/macrotree.py b/src/sardana/taurus/qt/qtgui/extra_sardana/macrotree.py index 22518f9a6f..ab701163c3 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/macrotree.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/macrotree.py @@ -273,10 +273,8 @@ def __init__(self, parent=None, designMode=False, model_name=None, perspective=N self._buttonBox.setStandardButtons(bts) layout.addWidget(self._panel) layout.addWidget(self._buttonBox) - self._buttonBox.accepted.connect( - self.accept) - self._buttonBox.rejected.connect( - self.reject) + self._buttonBox.accepted.connect(self.accept) + self._buttonBox.rejected.connect(self.reject) def selectedItems(self): return self._panel.selectedItems() From 74009e2e0d012b7472adf06d2c5201f7059447f7 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Tue, 22 Jan 2019 16:16:59 +0100 Subject: [PATCH 532/652] (m) PEP8 --- src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py index 506ad7f3af..4ac80a56b5 100644 --- a/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py +++ b/src/sardana/taurus/qt/qtgui/extra_hkl/selectsignal.py @@ -69,7 +69,8 @@ def __init__(self, parent=None, designMode=False): self.signalComboBox.setGeometry(QtCore.QRect(70, 50, 161, 27)) self.signalComboBox.setObjectName("SignalcomboBox") - self.signalComboBox.currentIndexChanged['QString'].connect(self.onSignalChanged) + self.signalComboBox.currentIndexChanged['QString'].connect( + self.onSignalChanged) self.doorName = None self.door_device = None From 0991cc701d68d2c063f91a7ef835bd738f6b6d0d Mon Sep 17 00:00:00 2001 From: cfalcon Date: Tue, 22 Jan 2019 16:51:49 +0100 Subject: [PATCH 533/652] Fix flake8 --- .../taurus/qt/qtgui/extra_macroexecutor/macrobutton.py | 7 ++----- src/sardana/taurus/qt/qtgui/macrolistener/__init__.py | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py index 80407dfa0d..d159eea5c3 100755 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py @@ -264,11 +264,8 @@ def connectArgEditors(self, signals): # bck-compat: (sender, sig) tuples used instead of pyqtsignals sender, sig = signal msg = "Old style signals are deprecated: " - self.deprecated( - dep='Passing (sender, signature) tuples', - alt='pyqtSignal objects', - rel='2.5.1' - ) + self.deprecated(msg, dep='Passing (sender, signature) tuples', + alt='pyqtSignal objects', rel='2.5.1') signal = getattr(sender, sig.split('(')[0]) signal.connect(functools.partial(self.updateMacroArgument, i)) diff --git a/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py b/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py index 0fea0853e3..1dda39e783 100755 --- a/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py +++ b/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py @@ -29,4 +29,3 @@ __docformat__ = 'restructuredtext' from .macrolistener import * # noqa: F401,F403 - From e39d97f443b2229f11849908af8db0d223e720d8 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Wed, 23 Jan 2019 09:10:01 +0100 Subject: [PATCH 534/652] Revert previous commit and fix the flake8 error properly The last commit fixed a flake8 error but did it so in a wrong way. Fix it. --- src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py index d159eea5c3..b10c89b1ec 100755 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py @@ -263,8 +263,7 @@ def connectArgEditors(self, signals): if not self.__isSignal(signal): # bck-compat: (sender, sig) tuples used instead of pyqtsignals sender, sig = signal - msg = "Old style signals are deprecated: " - self.deprecated(msg, dep='Passing (sender, signature) tuples', + self.deprecated(dep='Passing (sender, signature) tuples', alt='pyqtSignal objects', rel='2.5.1') signal = getattr(sender, sig.split('(')[0]) signal.connect(functools.partial(self.updateMacroArgument, i)) From 999ebbeeac4f48dc89aa1387343c5c967166efb7 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 23 Jan 2019 11:57:39 +0100 Subject: [PATCH 535/652] Add timescan test --- src/sardana/macroserver/macros/test/test_scan.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sardana/macroserver/macros/test/test_scan.py b/src/sardana/macroserver/macros/test/test_scan.py index 8bba57aa7d..0aa51fa887 100644 --- a/src/sardana/macroserver/macros/test/test_scan.py +++ b/src/sardana/macroserver/macros/test/test_scan.py @@ -167,3 +167,9 @@ class MeshTest(RunStopMacroTestCase, unittest.TestCase): stoped. See :class:`.RunStopMacroTestCase` for requirements. """ macro_name = 'mesh' + + +@testRun(macro_params=['10', '0.1'], wait_timeout=30) +class TimescanTest(RunStopMacroTestCase, unittest.TestCase): + + macro_name = 'timescan' From 9c8c36dd83516420ebee2a0dff76f12b2ce11af9 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 23 Jan 2019 12:03:14 +0100 Subject: [PATCH 536/652] Fix count_continuous method --- src/sardana/taurus/core/tango/sardana/pool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index ac6170cde6..dd39ea57e2 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1857,7 +1857,7 @@ class on a provisional basis. Backwards incompatible changes cfg.prepare() self.setSynchronization(synchronization) self.subscribeValueBuffer(value_buffer_cb) - self.count_raw(self) + self.count_raw(start_time) self.unsubscribeValueBuffer(value_buffer_cb) state = self.getStateEG().readValue() if state == Fault: From 8180e5a8c8c46eaecb7df83978c13d040b2d7d27 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 24 Jan 2019 11:24:14 +0100 Subject: [PATCH 537/652] Fix typo in 'QString'' --- .../taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py index 3eeeca9531..7bfeee426d 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py @@ -59,7 +59,7 @@ def __init__(self, parent=None): class SpockCommandWidget(Qt.QLineEdit, TaurusBaseContainer): pressedReturn = Qt.pyqtSignal() - spockComboBox = Qt.pyqtSignal('Qstring') + spockComboBox = Qt.pyqtSignal('QString') elementUp = Qt.pyqtSignal() elementDown = Qt.pyqtSignal() setHistoryFocus = Qt.pyqtSignal() From 18200ab494dd4bd47d332e9d5610b0783ae22ab9 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 24 Jan 2019 17:03:53 +0100 Subject: [PATCH 538/652] Add test of Motor taurus extension --- .../taurus/core/tango/sardana/test/test_pool.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/sardana/taurus/core/tango/sardana/test/test_pool.py b/src/sardana/taurus/core/tango/sardana/test/test_pool.py index e99cd2a5cd..81bc08ebb7 100644 --- a/src/sardana/taurus/core/tango/sardana/test/test_pool.py +++ b/src/sardana/taurus/core/tango/sardana/test/test_pool.py @@ -80,3 +80,20 @@ def count(self, elements): def tearDown(self): SarTestTestCase.tearDown(self) + + +class TestMotor(SarTestTestCase, TestCase): + + def setUp(self): + SarTestTestCase.setUp(self) + registerExtensions() + + def test_move(self): + mot = Device("_test_mt_1_1") + _, values = mot.move(1) + + def tearDown(self): + SarTestTestCase.tearDown(self) + # TODO: This sleep is just to demonstrate API_EventTimeout. Remove it! + import time + time.sleep(20) From d1ddb598181cd0b63904e960816b00c61679a85b Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 28 Jan 2019 13:10:33 +0100 Subject: [PATCH 539/652] Correcting macros for new diffractometer types --- src/sardana/macroserver/macros/hkl.py | 262 +++++++++++--------------- 1 file changed, 114 insertions(+), 148 deletions(-) diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py index 515848af15..aec6f43a2b 100644 --- a/src/sardana/macroserver/macros/hkl.py +++ b/src/sardana/macroserver/macros/hkl.py @@ -1,25 +1,3 @@ -############################################################################## -## -# This file is part of Sardana -## -# http://www.sardana-controls.org/ -## -# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain -## -# Sardana 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. -## -# Sardana 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 Sardana. If not, see . -## -############################################################################## """ Macro library containning diffractometer related macros for the macros @@ -35,7 +13,7 @@ # using getDevice. However this getter seems to accept only the elements names # and not the full names. -__all__ = ["addreflection", "affine", "br", "ca", "caa", "ci", "computeub", +__all__ = ["addreflexion", "affine", "br", "ca", "caa", "ci", "computeub", "freeze", "getmode", "hklscan", "hscan", "kscan", "latticecal", "loadcrystal", "lscan", "newcrystal", "or0", "or1", "orswap", "pa", "savecrystal", "setaz", "setlat", "setmode", "setor0", @@ -107,25 +85,11 @@ def prepare(self): self.angle_names.append("delta") if self.nb_motors == 4: - self.labelmotor = {'Omega': self.angle_names[0], - 'Chi': self.angle_names[1], - 'Phi': self.angle_names[2], - 'Tth': self.angle_names[3]} + self.labelmotor = {'Omega': "omega", + 'Chi': "chi", 'Phi': "phi", 'Tth': "tth"} elif self.nb_motors == 6: - self.labelmotor = {'Mu': self.angle_names[0], - 'Theta': self.angle_names[1], - 'Chi': self.angle_names[2], - 'Phi': self.angle_names[3], - 'Gamma': self.angle_names[4], - 'Delta': self.angle_names[5]} - elif self.nb_motors == 7: - self.labelmotor = {'Omega_t': self.angle_names[0], - 'Mu': self.angle_names[1], - 'Omega': self.angle_names[2], - 'Chi': self.angle_names[3], - 'Phi': self.angle_names[4], - 'Gamma': self.angle_names[5], - 'Delta': self.angle_names[6]} + self.labelmotor = {'Mu': "mu", 'Theta': "omega", 'Chi': "chi", + 'Phi': "phi", 'Gamma': "gamma", 'Delta': "delta"} prop = self.diffrac.get_property(['DiffractometerType']) for v in prop['DiffractometerType']: @@ -375,17 +339,22 @@ def run(self, H, K, L, Trajectory): str_pos[self.labelmotor["Chi"]], str_pos[self.labelmotor["Phi"]])) elif self.nb_motors == 7: - self.output("%10s %11s %12s %11s %10s %11s %11s" % - ("Omega_t", "Mu", "Omega", "Chi", - "Phi", "Gamma", "Delta")) - self.output("%10s %11s %12s %11s %10s %11s %11s" % - (str_pos[self.labelmotor["Omega_t"]], - str_pos[self.labelmotor["Mu"]], - str_pos[self.labelmotor["Omega"]], - str_pos[self.labelmotor["Chi"]], - str_pos[self.labelmotor["Phi"]], - str_pos[self.labelmotor["Gamma"]], - str_pos[self.labelmotor["Delta"]])) + self.output("%10s %11s %12s %11s %11s %11s %11s" % + (self.angle_names[0], + self.angle_names[1], + self.angle_names[2], + self.angle_names[3], + self.angle_names[4], + self.angle_names[5], + self.angle_names[6])) + self.output("%10s %11s %12s %11s %11s %11s %11s" % + (str_pos[self.angle_names[0]], + str_pos[self.angle_names[1]], + str_pos[self.angle_names[2]], + str_pos[self.angle_names[3]], + str_pos[self.angle_names[4]], + str_pos[self.angle_names[5]], + str_pos[self.angle_names[6]])) @@ -439,18 +408,23 @@ class ci(Macro, _diffrac): ['phi', Type.Float, None, "Phi value"], ['gamma', Type.Float, -999, "Gamma value"], ['delta', Type.Float, -999, "Delta value"], + ['omega_t', Type.Float, -999, "Omega_t value"], ] - def prepare(self, mu, theta, chi, phi, gamma, delta): + def prepare(self, mu, theta, chi, phi, gamma, delta, omega_t): _diffrac.prepare(self) - def run(self, mu, theta, chi, phi, gamma, delta): + def run(self, mu, theta, chi, phi, gamma, delta, omega_t): if delta == -999 and self.nb_motors == 6: self.error("Six angle values are need as argument") + elif omega_t == -999 and self.nb_motors == 7: + self.error("Seven angle values are need as argument (omega_t is missed - last argument)") else: - - angles = [mu, theta, chi, phi, gamma, delta] + if self.nb_motors != 7: + angles = [mu, theta, chi, phi, gamma, delta] + else: + angles = [omega_t, mu, theta, chi, phi, gamma, delta] self.diffrac.write_attribute("computehkl", angles) @@ -639,9 +613,7 @@ def run(self): str_pos6 = "%7.5f" % self.getDevice( self.angle_device_names[self.labelmotor["Gamma"]]).Position self.output("%10s %11s %12s %11s %10s %11s" % - (self.labelmotor["Delta"], self.labelmotor["Theta"], - self.labelmotor["Chi"], self.labelmotor["Phi"], - self.labelmotor["Mu"], self.labelmotor["Gamma"])) + ("Delta", "Theta", "Chi", "Phi", "Mu", "Gamma")) self.output("%10s %11s %12s %11s %10s %11s" % (str_pos1, str_pos2, str_pos3, str_pos4, str_pos5, str_pos6)) @@ -655,33 +627,41 @@ def run(self): str_pos4 = "%7.5f" % self.getDevice( self.angle_device_names[self.labelmotor["Phi"]]).Position self.output("%10s %11s %12s %11s" % - (self.labelmotor["Tth"], self.labelmotor["Omega"], - self.labelmotor["Chi"], self.labelmotor["Phi"])) + ("Tth", "Omega", "Chi", "Phi")) self.output("%10s %11s %12s %11s" % (str_pos1, str_pos2, str_pos3, str_pos4)) elif self.nb_motors == 7: str_pos1 = "%7.5f" % self.getDevice( - self.angle_device_names[self.labelmotor["Omega_t"]]).Position + self.angle_device_names[self.angles_names[0]]).Position str_pos2 = "%7.5f" % self.getDevice( - self.angle_device_names[self.labelmotor["Mu"]]).Position + self.angle_device_names[self.angles_names[1]]).Position str_pos3 = "%7.5f" % self.getDevice( - self.angle_device_names[self.labelmotor["Omega"]]).Position + self.angle_device_names[self.angles_names[2]]).Position str_pos4 = "%7.5f" % self.getDevice( - self.angle_device_names[self.labelmotor["Chi"]]).Position + self.angle_device_names[self.angles_names[3]]).Position str_pos5 = "%7.5f" % self.getDevice( - self.angle_device_names[self.labelmotor["Phi"]]).Position + self.angle_device_names[self.angles_names[4]]).Position str_pos6 = "%7.5f" % self.getDevice( - self.angle_device_names[self.labelmotor["Gamma"]]).Position + self.angle_device_names[self.angles_names[5]]).Position str_pos7 = "%7.5f" % self.getDevice( - self.angle_device_names[self.labelmotor["Delta"]]).Position - self.output("%10s %11s %12s %11s %10s %11s %11s" % - (self.labelmotor["Omega_t"], self.labelmotor["Mu"], - self.labelmotor["Omega"], self.labelmotor["Chi"], - self.labelmotor["Phi"], self.labelmotor["Gamma"], - self.labelmotor["Delta"])) - self.output("%10s %11s %12s %11s %10s %11s %11s" % - (str_pos1, str_pos2, str_pos3, str_pos4, str_pos5, - str_pos6, str_pos7)) + self.angle_device_names[self.angles_names[6]]).Position + self.output("%10s %11s %12s %11s %11s %11s %11s" % + (self.angle_names[0], + self.angle_names[1], + self.angle_names[2], + self.angle_names[3], + self.angle_names[4], + self.angle_names[5], + self.angle_names[6])) + self.output("%10s %11s %12s %11s %11s %11s %11s" % + (str_pos1, + str_pos2, + str_pos3, + str_pos4, + str_pos5, + str_pos6, + str_pos7)) + self.setEnv('Q', [self.h_device.position, self.k_device.position, self.l_device.position, self.diffrac.WaveLength]) @@ -913,80 +893,93 @@ def run(self, H, K, L): class setor0(Macro, _diffrac): - """Set primary orientation reflection choosing hkl and angle values""" + """Set primary orientation reflection choosing hkl and angle values. + Run it without any argument to see the order real positions""" param_def = [ ['H', Type.Float, -999, "H value"], ['K', Type.Float, -999, "K value"], ['L', Type.Float, -999, "L value"], - ['mu', Type.Float, -999, "Mu value"], - ['theta', Type.Float, -999, "Theta value"], - ['chi', Type.Float, -999, "Chi value"], - ['phi', Type.Float, -999, "Phi value"], - ['gamma', Type.Float, -999, "Gamma value"], - ['delta', Type.Float, -999, "Delta value"], + ['ang1', Type.Float, -999, "Real position"], + ['ang2', Type.Float, -999, "Real position"], + ['ang3', Type.Float, -999, "Real position"], + ['ang4', Type.Float, -999, "Real position"], + ['ang5', Type.Float, -999, "Real position"], + ['ang6', Type.Float, -999, "Real position"], + ['ang7', Type.Float, -999, "Real position"], ] - def prepare(self, H, K, L, mu, theta, chi, phi, gamma, delta): + def prepare(self, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7): _diffrac.prepare(self) - def run(self, H, K, L, mu, theta, chi, phi, gamma, delta): - + def run(self, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7): setorn, pars = self.createMacro( - "setorn", 0, H, K, L, mu, theta, chi, phi, gamma, delta) + "setorn", 0, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7) self.runMacro(setorn) class setor1(Macro, _diffrac): - """Set secondary orientation reflection choosing hkl and angle values""" + """Set secondary orientation reflection choosing hkl and angle values. + Run it without any argument to see the order real positions""" param_def = [ ['H', Type.Float, -999, "H value"], ['K', Type.Float, -999, "K value"], ['L', Type.Float, -999, "L value"], - ['mu', Type.Float, -999, "Mu value"], - ['theta', Type.Float, -999, "Theta value"], - ['chi', Type.Float, -999, "Chi value"], - ['phi', Type.Float, -999, "Phi value"], - ['gamma', Type.Float, -999, "Gamma value"], - ['delta', Type.Float, -999, "Delta value"], + ['ang1', Type.Float, -999, "Real position"], + ['ang2', Type.Float, -999, "Real position"], + ['ang3', Type.Float, -999, "Real position"], + ['ang4', Type.Float, -999, "Real position"], + ['ang5', Type.Float, -999, "Real position"], + ['ang6', Type.Float, -999, "Real position"], + ['ang7', Type.Float, -999, "Real position"], ] - def prepare(self, H, K, L, mu, theta, chi, phi, gamma, delta): + def prepare(self, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7): + self.output("setor1 prepare") + self.output(ang3) + self.output(ang7) _diffrac.prepare(self) - def run(self, H, K, L, mu, theta, chi, phi, gamma, delta): - + def run(self, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7): setorn, pars = self.createMacro( - "setorn", 1, H, K, L, mu, theta, chi, phi, gamma, delta) + "setorn", 1, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7) self.runMacro(setorn) class setorn(iMacro, _diffrac): - """Set orientation reflection indicated by the index.""" + """Set orientation reflection indicated by the index. + Run it without any argument to see the order of the angles to be set""" param_def = [ ['ref_id', Type.Integer, None, "reflection index (starting at 0)"], ['H', Type.Float, -999, "H value"], ['K', Type.Float, -999, "K value"], ['L', Type.Float, -999, "L value"], - ['mu', Type.Float, -999, "Mu value"], - ['theta', Type.Float, -999, "Theta value"], - ['chi', Type.Float, -999, "Chi value"], - ['phi', Type.Float, -999, "Phi value"], - ['gamma', Type.Float, -999, "Gamma value"], - ['delta', Type.Float, -999, "Delta value"], + ['ang1', Type.Float, -999, "Real position"], + ['ang2', Type.Float, -999, "Real position"], + ['ang3', Type.Float, -999, "Real position"], + ['ang4', Type.Float, -999, "Real position"], + ['ang5', Type.Float, -999, "Real position"], + ['ang6', Type.Float, -999, "Real position"], + ['ang7', Type.Float, -999, "Real position"], ] - def prepare(self, ref_id, H, K, L, mu, theta, chi, phi, gamma, delta): + def prepare(self, ref_id, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7): _diffrac.prepare(self) - def run(self, ref_id, H, K, L, mu, theta, chi, phi, gamma, delta): + def run(self, ref_id, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7): - if (delta == -999 and self.nb_motors == 6) or ( - phi == -999 and self.nb_motors == 4): + if H == -999.0: + self.output("Order of the real motor positions to be given as argument:") + for el in self.angle_names: + self.output(el) + return + + if (ang6 == -999 and self.nb_motors == 6) or ( + ang4 == -999 and self.nb_motors == 4) or (ang7 == -999 and self.nb_motors == 7): reflections = [] try: reflections = self.diffrac.reflectionlist @@ -1021,30 +1014,10 @@ def run(self, ref_id, H, K, L, mu, theta, chi, phi, gamma, delta): ref_txt = "reflection " + str(ref_id) self.output("Enter %s angles" % ref_txt) - if self.nb_motors == 6: - delta = float(self.input(" Delta?", default_value=tmp_ref[ - "delta"], data_type=Type.String)) - - theta = float(self.input(" Theta? ", default_value=tmp_ref[ - "omega"], data_type=Type.String)) - chi = float(self.input(" Chi?", default_value=tmp_ref[ - "chi"], data_type=Type.String)) - phi = float(self.input(" Phi?", default_value=tmp_ref[ - "phi"], data_type=Type.String)) - gamma = float(self.input(" Gamma?", default_value=tmp_ref[ - "gamma"], data_type=Type.String)) - mu = float(self.input(" Mu?", default_value=tmp_ref[ - "mu"], data_type=Type.String)) - if self.nb_motors == 4: - - omega = float(self.input(" Omega?", default_value=tmp_ref[ - "omega"], data_type=Type.String)) - chi = float(self.input(" Chi?", default_value=tmp_ref[ - "chi"], data_type=Type.String)) - phi = float(self.input(" Phi?", default_value=tmp_ref[ - "phi"], data_type=Type.String)) - tth = float(self.input(" Tth?", default_value=tmp_ref[ - "omega"], data_type=Type.String)) + angles_to_set = [] + for el in self.angle_names: + angles_to_set.append(float(self.input(el+"?", default_value=tmp_ref[ + el], data_type=Type.String))) self.output("") @@ -1056,7 +1029,12 @@ def run(self, ref_id, H, K, L, mu, theta, chi, phi, gamma, delta): L = float(self.input(" L?", default_value=tmp_ref[ "l"], data_type=Type.String)) self.output("") - + else: + angles = [ang1, ang2, ang3, ang4, ang5, ang6, ang7] + angles_to_set = [] + for i in range(0, self.nb_motors): + angles_to_set.append(angles[i]) + # Check collinearity if ref_id == 0: @@ -1077,22 +1055,10 @@ def run(self, ref_id, H, K, L, mu, theta, chi, phi, gamma, delta): values = [ref_id, H, K, L] self.diffrac.write_attribute("SubstituteReflection", values) - # Adjust angles - - if self.nb_motors == 6: - self.angle_values = {"mu": mu, "omega": theta, - "chi": chi, "phi": phi, "gamma": gamma, - "delta": delta} - elif self.nb_motors == 4: - self.angle_values = {"omega": omega, "chi": chi, - "phi": phi, "tth": tth} - - values = [] values.append(ref_id) - - for angle_name in self.angle_names: - values.append(self.angle_values[angle_name]) + for el in angles_to_set: + values.append(el) self.diffrac.write_attribute("AdjustAnglesToReflection", values) From 0300c1e069f1ac2e07e88bc92e4c17c7405907f0 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 29 Jan 2019 15:57:43 +0100 Subject: [PATCH 540/652] Add proper tear down of SarTestTestCase --- src/sardana/tango/pool/test/base_sartest.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/sardana/tango/pool/test/base_sartest.py b/src/sardana/tango/pool/test/base_sartest.py index 8a4a996968..0c9531ef23 100644 --- a/src/sardana/tango/pool/test/base_sartest.py +++ b/src/sardana/tango/pool/test/base_sartest.py @@ -23,9 +23,10 @@ ## ############################################################################## -import PyTango +import taurus + from sardana.tango.pool.test import BasePoolTestCase -from sardana.tango.core.util import get_free_alias + __all__ = ['SarTestTestCase'] @@ -130,13 +131,28 @@ def tearDown(self): """ dirty_elems = [] dirty_ctrls = [] + f = taurus.Factory() for elem_name in self.elem_list: + # Cleanup eventual taurus devices. This is especially important + # if the sardana-taurus extensions are in use since this + # devices are created and destroyed within the testsuite. + # Persisting taurus device may react on API_EventTimeouts, enabled + # polling, etc. + if elem_name in f.tango_alias_devs: + taurus.Device(elem_name).cleanUp() try: self.pool.DeleteElement(elem_name) except: dirty_elems.append(elem_name) for ctrl_name in self.ctrl_list: + # Cleanup eventual taurus devices. This is especially important + # if the sardana-taurus extensions are in use since this + # devices are created and destroyed within the testsuite. + # Persisting taurus device may react on API_EventTimeouts, enabled + # polling, etc. + if elem_name in f.tango_alias_devs: + taurus.Device(elem_name).cleanUp() try: self.pool.DeleteElement(ctrl_name) except: From df29e8737151c3c11e46b2e3c7c80e42068dba5b Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 29 Jan 2019 15:59:33 +0100 Subject: [PATCH 541/652] Add MeasuremenGroup (taurus extension) cleanup In the cleanup remove the configuration attribute in order to avoid circular references and allow to destroy unreferenced measurement groups. --- src/sardana/taurus/core/tango/sardana/pool.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 4ecbcd193f..bc797e75f6 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -1528,6 +1528,11 @@ def __init__(self, name, **kw): self._value_buffer_cb = None self._codec = CodecFactory().getCodec("json") + def cleanUp(self): + PoolElement.cleanUp(self) + f = self.factory() + f.removeExistingAttribute(self.__cfg_attr) + def _create_str_tuple(self): channel_names = ", ".join(self.getChannelNames()) return self.getName(), self.getTimerName(), channel_names From e4487b221dc9009d30e2fa602e964a6168cf8629 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 29 Jan 2019 16:01:01 +0100 Subject: [PATCH 542/652] Cleaup measurement group in test to avoid API_EventTimeouts --- src/sardana/taurus/core/tango/sardana/test/test_pool.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sardana/taurus/core/tango/sardana/test/test_pool.py b/src/sardana/taurus/core/tango/sardana/test/test_pool.py index 81bc08ebb7..b07b2080d9 100644 --- a/src/sardana/taurus/core/tango/sardana/test/test_pool.py +++ b/src/sardana/taurus/core/tango/sardana/test/test_pool.py @@ -76,6 +76,7 @@ def count(self, elements): msg = "Value for %s is not numerical" % channel self.assertTrue(is_numerical(value), msg) finally: + self.mg.cleanUp() self.pool.DeleteElement(self.mg_name) def tearDown(self): From f5951007f8c1fcf1d9c868dcaeeba5bbe7aa7e14 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 29 Jan 2019 16:03:58 +0100 Subject: [PATCH 543/652] Simplify measurement group test Use local variables instead of incence members. --- .../taurus/core/tango/sardana/test/test_pool.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/test/test_pool.py b/src/sardana/taurus/core/tango/sardana/test/test_pool.py index b07b2080d9..7fe75d8729 100644 --- a/src/sardana/taurus/core/tango/sardana/test/test_pool.py +++ b/src/sardana/taurus/core/tango/sardana/test/test_pool.py @@ -63,21 +63,21 @@ class TestMeasurementGroup(SarTestTestCase, TestCase): def setUp(self): SarTestTestCase.setUp(self) - self.mg_name = str(uuid.uuid1()) registerExtensions() def count(self, elements): - argin = [self.mg_name] + elements + mg_name = str(uuid.uuid1()) + argin = [mg_name] + elements self.pool.CreateMeasurementGroup(argin) try: - self.mg = Device(self.mg_name) - _, values = self.mg.count(1) + mg = Device(mg_name) + _, values = mg.count(1) for channel, value in values.iteritems(): msg = "Value for %s is not numerical" % channel self.assertTrue(is_numerical(value), msg) finally: - self.mg.cleanUp() - self.pool.DeleteElement(self.mg_name) + mg.cleanUp() + self.pool.DeleteElement(mg_name) def tearDown(self): SarTestTestCase.tearDown(self) From 4a03abb2c886bdd44dfcc3994978e47b2985cd1c Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 29 Jan 2019 16:25:08 +0100 Subject: [PATCH 544/652] Remove demonstration sleep --- src/sardana/taurus/core/tango/sardana/test/test_pool.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/test/test_pool.py b/src/sardana/taurus/core/tango/sardana/test/test_pool.py index 7fe75d8729..a53f3840e8 100644 --- a/src/sardana/taurus/core/tango/sardana/test/test_pool.py +++ b/src/sardana/taurus/core/tango/sardana/test/test_pool.py @@ -95,6 +95,3 @@ def test_move(self): def tearDown(self): SarTestTestCase.tearDown(self) - # TODO: This sleep is just to demonstrate API_EventTimeout. Remove it! - import time - time.sleep(20) From 2747aaeaeb0f9f690fbeabadaf17547a97997a57 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 29 Jan 2019 17:39:23 +0100 Subject: [PATCH 545/652] Bump Taurus requirement to >=3.10 (T3) and >=4.5 (T4) --- setup.py | 6 ++++-- src/sardana/requirements.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index af32f712f3..fcaf26cac1 100644 --- a/setup.py +++ b/setup.py @@ -65,8 +65,10 @@ def get_release_info(): install_requires = [ 'PyTango>=7.2.3', 'itango>=0.0.1', - # for Taurus3 requires >= 3.7.5; for Taurus4 requires >= 4.4.0 - 'taurus>=3.7.5,!=4.0.0,!=4.0.1,!=4.0.3,!=4.1.0,!=4.1.1,!=4.3.0,!=4.3.1', + # for Taurus3 requires >= 3.10 (special version from + # taurus-org/taurus@3.x-sdn2.5.1 branch) + # for Taurus4 requires >= 4.5.0 + 'taurus>=3.10,!=4.0,!=4.1,!=4.3,!=4.4', 'lxml>=2.1' ] diff --git a/src/sardana/requirements.py b/src/sardana/requirements.py index 6b4a4df97d..8ed81ce2c6 100644 --- a/src/sardana/requirements.py +++ b/src/sardana/requirements.py @@ -37,7 +37,7 @@ # module minimum "Python": (2, 6, 0), "PyTango": (7, 2, 3), - "taurus.core": (3, 7, 5), + "taurus.core": (3, 10), } From 89e50c7babfce0071658df49315684e42b62151c Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 29 Jan 2019 19:29:15 +0100 Subject: [PATCH 546/652] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93fb2f49f6..a0c8adbe78 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ This file follows the formats and conventions from [keepachangelog.com] the need to encapsulate them in square brackets (spock syntax) or list (macro API) (#781, #983) - Possibility to change data format (shape) of of pseudo counter values (#986) +- Check scan range agains motor limits wheneve possible (#46, #963) - Workaround for API_DeviceTimedOut errors on MeasurementGroup Start. Call Stop in case this error occured (#764). - Optional measurement group parameter to `ct` and `uct` macros (#940, #473) From 1fd4f4f28aa72de9ddd1003900f2788e252d0123 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 29 Jan 2019 23:12:16 +0100 Subject: [PATCH 547/652] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0205e1381d..853694a84a 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ This file follows the formats and conventions from [keepachangelog.com] - `PoolAcquisitionSoftwareStart` acquisition action - `SoftwareStart` and `HardwareStart` synchronization in `DummyCounterTimerController` +- Support to Qt5 for Sardana-Taurus widgets and Sardana-Taurus extensions (#1006, + #1009) - Possibility to define macros with optional parameters. These must be the last ones in the definition (#285, #876, #943, #941, #955) - Possibility to pass values of repeat paramters with just one member without @@ -76,7 +78,9 @@ This file follows the formats and conventions from [keepachangelog.com] in favor of `LoadOne(axis, value, repeats, latency)` (SEP18, #773) - Unused class `sardana.taurus.qt.qtgui.extra_macroexecutor.dooroutput.DoorAttrListener` +### Removed +- Support to Qt < 4.7.4 (#1006, #1009) ## [2.5.0] 2018-08-10 From 93dca494a54c69d95ae445015cb3398bd1042df2 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 30 Jan 2019 15:37:17 +0100 Subject: [PATCH 548/652] (doc) Refer to expconf equally in the whole chapter --- doc/source/users/taurus/experimentconfiguration.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/source/users/taurus/experimentconfiguration.rst b/doc/source/users/taurus/experimentconfiguration.rst index 6dd31828b5..4a70be0f6c 100644 --- a/doc/source/users/taurus/experimentconfiguration.rst +++ b/doc/source/users/taurus/experimentconfiguration.rst @@ -9,7 +9,7 @@ Experiment Configuration user interface .. contents:: -Experiment Configuration widget a.k.a. expconf is a complete interface to +Experiment Configuration widget a.k.a. ``expconf`` is a complete interface to define the experiment configuration. It consists of three main groups of parameters organized in tabs: @@ -22,7 +22,9 @@ will be maintained as pending to apply until either applied or reset by the user. This widget is usually present in sardana-aware Taurus GUIs and is also invoked -by the `expconf` command in :ref:`Spock` +by the ``expconf`` command in :ref:`Spock`. + + .. _expconf_ui_measurementgroup: From 0d935905341607b139fa1eb712ddca7ea204c4a4 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 30 Jan 2019 16:50:29 +0100 Subject: [PATCH 549/652] Move Show/Hide plots action to the measgrp tab Show/Hide plots is assigned to the experiment configuration widget. But it has more sense to be assigned to the measurement group since it is about plotting of the experimental channels (part of the measurement group configuration). Move it to the measurement group configuration tab. --- .../taurus/qt/qtgui/extra_sardana/expdescription.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 330a4f00d0..bb0fd51b02 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -243,11 +243,14 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.__plotManager = None icon = resource.getIcon(":/actions/view.svg") - self.togglePlotsAction = Qt.QAction(icon, "Show/Hide plots", self) + measGrpTab = self.ui.tabWidget.widget(0) + self.togglePlotsAction = Qt.QAction(icon, "Show/Hide plots", + measGrpTab) self.togglePlotsAction.setCheckable(True) self.togglePlotsAction.setChecked(False) self.togglePlotsAction.setEnabled(plotsButton) - self.addAction(self.togglePlotsAction) + measGrpTab.addAction(self.togglePlotsAction) + measGrpTab.setContextMenuPolicy(Qt.Qt.ActionsContextMenu) self.connect(self.togglePlotsAction, Qt.SIGNAL("toggled(bool)"), self.onPlotsButtonToggled) self.ui.plotsButton.setDefaultAction(self.togglePlotsAction) From 3e34fb504b617471143075b6b9e931c5aadcac31 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 30 Jan 2019 16:54:04 +0100 Subject: [PATCH 550/652] Add Auto update action in context menu of expconf Auto update action allows to enable/disable expconf slave mode - automatically update changes from the server and discard local changes. --- .../qt/qtgui/extra_sardana/expdescription.py | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index bb0fd51b02..29a273939f 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -203,11 +203,17 @@ def __init__(self, parent=None, door=None, plotsButton=True, self._dirty = False self._dirtyMntGrps = set() - # Add warning message to the Widget - self._autoUpdate = autoUpdate - if self._autoUpdate: - w = self._getWarningWidget() - self.ui.verticalLayout_3.insertWidget(0, w) + self._warningWidget = None + self._autoUpdate = False + self.setAutoUpdate(autoUpdate) + self.setContextMenuPolicy(Qt.Qt.ActionsContextMenu) + self._autoUpdateAction = Qt.QAction("Auto update", self) + self._autoUpdateAction.setCheckable(True) + self.connect(self._autoUpdateAction, Qt.SIGNAL( + "toggled(bool)"), self.setAutoUpdate) + self.addAction(self._autoUpdateAction) + self.registerConfigProperty( + self.isAutoUpdate, self.setAutoUpdate, "autoUpdate") # Pending event variables self._expConfChangedDialog = None @@ -263,6 +269,19 @@ def __init__(self, parent=None, door=None, plotsButton=True, # Taurus Configuration properties and delegates self.registerConfigDelegate(self.ui.channelEditor) + def setAutoUpdate(self, auto_update): + if auto_update and not self._autoUpdate: + self._warningWidget = self._getWarningWidget() + self.ui.verticalLayout_3.insertWidget(0, self._warningWidget) + if not auto_update and self._autoUpdate: + self.ui.verticalLayout_3.removeWidget(self._warningWidget) + self._warningWidget.deleteLater() + self._warningWidget = None + self._autoUpdate = auto_update + + def isAutoUpdate(self): + return self._autoUpdate + def _getWarningWidget(self): w = Qt.QWidget() layout = QtGui.QHBoxLayout() From 6471860652618cd0a386cf4ded2737e75893afb1 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 30 Jan 2019 16:54:31 +0100 Subject: [PATCH 551/652] Document expconf reaction on server changes and auto-update feature --- doc/source/users/taurus/experimentconfiguration.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/source/users/taurus/experimentconfiguration.rst b/doc/source/users/taurus/experimentconfiguration.rst index 4a70be0f6c..5d75849511 100644 --- a/doc/source/users/taurus/experimentconfiguration.rst +++ b/doc/source/users/taurus/experimentconfiguration.rst @@ -21,6 +21,19 @@ The parameters may be modified in an arbitrary order, at any of the tabs, and will be maintained as pending to apply until either applied or reset by the user. +.. important:: + While editing configuration in the ``expconf`` widget, the experiment + configuration on the server may have changed, for example, another + ``expconf`` instance applied changes or a running macro changed it + programmatically. This is notified to the user with a pop-up dialog + offering the user to either keep the local version of the experiment + configuration or to load the new configuration from the server. Be aware that + the second option will **override all your local changes**. It is also + possible to use the ``expconf`` widget in *slave* mode and automatically + update on the server changes. You can enable/disable the "Auto update" mode + from the context menu. + + This widget is usually present in sardana-aware Taurus GUIs and is also invoked by the ``expconf`` command in :ref:`Spock`. From 78f4ee7de88fdcf28be79d9164533af461568fe8 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 30 Jan 2019 17:02:30 +0100 Subject: [PATCH 552/652] Adapt Auto update action to new-style signals --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 91e149f09b..2b9344173d 100755 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -206,8 +206,7 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.setContextMenuPolicy(Qt.Qt.ActionsContextMenu) self._autoUpdateAction = Qt.QAction("Auto update", self) self._autoUpdateAction.setCheckable(True) - self.connect(self._autoUpdateAction, Qt.SIGNAL( - "toggled(bool)"), self.setAutoUpdate) + self._autoUpdateAction.toggled.connect(self.setAutoUpdate) self.addAction(self._autoUpdateAction) self.registerConfigProperty( self.isAutoUpdate, self.setAutoUpdate, "autoUpdate") From d979bb6b60d64b188a5f63cd4881a329223af396 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 30 Jan 2019 17:06:22 +0100 Subject: [PATCH 553/652] Correct show/hide plots tooltip usage --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 2b9344173d..25c5c8ad54 100755 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -238,7 +238,7 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.onChooseScanDirButtonClicked) self.__plotManager = None - tooltip = "Show/Hide plots" + tooltip = None # TODO: Disable show scan button since scan plot have to be # adapted to support QT5 @@ -252,7 +252,9 @@ def __init__(self, parent=None, door=None, plotsButton=True, icon = resource.getIcon(":/actions/view.svg") measGrpTab = self.ui.tabWidget.widget(0) - self.togglePlotsAction = Qt.QAction(icon, tooltip, self) + self.togglePlotsAction = Qt.QAction(icon, "Show/Hide plots", self) + if tooltip is not None: + self.togglePlotsAction.setToolTip(tooltip) self.togglePlotsAction.setCheckable(True) self.togglePlotsAction.setChecked(False) self.togglePlotsAction.setEnabled(plotsButton) From 991372bf880a80be41c316875ab07d8a4de9c40e Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 30 Jan 2019 18:12:15 +0100 Subject: [PATCH 554/652] Check autoupdate action based on expconf start argument --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 25c5c8ad54..eec67c9600 100755 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -202,12 +202,12 @@ def __init__(self, parent=None, door=None, plotsButton=True, self._warningWidget = None self._autoUpdate = False - self.setAutoUpdate(autoUpdate) self.setContextMenuPolicy(Qt.Qt.ActionsContextMenu) self._autoUpdateAction = Qt.QAction("Auto update", self) self._autoUpdateAction.setCheckable(True) self._autoUpdateAction.toggled.connect(self.setAutoUpdate) self.addAction(self._autoUpdateAction) + self._autoUpdateAction.setChecked(autoUpdate) self.registerConfigProperty( self.isAutoUpdate, self.setAutoUpdate, "autoUpdate") From d6a6a0b509fe3d230bf5a97c1c8a261425b08635 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 31 Jan 2019 11:28:27 +0100 Subject: [PATCH 555/652] Bump version 2.5.1-alpha to 2.6.0-alpha --- .bumpversion.cfg | 2 +- src/sardana/release.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 99e68d31ca..6456236e6f 100755 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ commit = True message = Bump version {current_version} to {new_version} tag = False tag_name = {new_version} -current_version = 2.5.1-alpha +current_version = 2.6.0-alpha parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} diff --git a/src/sardana/release.py b/src/sardana/release.py index 118a97d4de..e9c9403763 100644 --- a/src/sardana/release.py +++ b/src/sardana/release.py @@ -47,7 +47,7 @@ # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '2.5.1-alpha' +version = '2.6.0-alpha' # generate version_info and revision (**deprecated** since v 2.1.2--alpha). if '-' in version: From a6b4936054efc62a4cbe3b9cad8da922831dc787 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 31 Jan 2019 11:28:28 +0100 Subject: [PATCH 556/652] Bump version 2.6.0-alpha to 2.6.0 --- .bumpversion.cfg | 2 +- src/sardana/release.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 6456236e6f..7c79737971 100755 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ commit = True message = Bump version {current_version} to {new_version} tag = False tag_name = {new_version} -current_version = 2.6.0-alpha +current_version = 2.6.0 parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} diff --git a/src/sardana/release.py b/src/sardana/release.py index e9c9403763..566593c88d 100644 --- a/src/sardana/release.py +++ b/src/sardana/release.py @@ -47,7 +47,7 @@ # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '2.6.0-alpha' +version = '2.6.0' # generate version_info and revision (**deprecated** since v 2.1.2--alpha). if '-' in version: From 7ef8dd22242e7ed008bf2ba7a0d2982719e22e98 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 31 Jan 2019 11:35:37 +0100 Subject: [PATCH 557/652] Bump taurus requires to 3.10 Install requires was already set in the qt5 development but requires was forgotten. Bum taurus requires to 3.10. --- setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index fcaf26cac1..1078245737 100644 --- a/setup.py +++ b/setup.py @@ -55,8 +55,10 @@ def get_release_info(): # when using PyTango < 9 the dependency is >= 0.0.1 and < 0.1.0 # when using PyTango >= 9 the dependency is >= 0.1.6 'itango (>=0.0.1)', - # for Taurus3 requires >= 3.7.5; for Taurus4 requires >= 4.4.0 - 'taurus (>= 3.7.5)', + # for Taurus3 requires >= 3.10 (special version from + # taurus-org/taurus@3.x-sdn2.5.1 branch) + # for Taurus4 requires >= 4.5.0 + 'taurus (>= 3.10)', 'lxml (>=2.1)', # ordereddict is necessary for Python < 2.6 'ordereddict' From efdfb767a221fe2bac0d716b14c1bc61f7451f83 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 31 Jan 2019 11:43:55 +0100 Subject: [PATCH 558/652] Bump versions in man pages --- doc/man/MacroServer.1 | 6 +++--- doc/man/Pool.1 | 6 +++--- doc/man/Sardana.1 | 6 +++--- doc/man/diffractometeralignment.1 | 6 +++--- doc/man/hklscan.1 | 6 +++--- doc/man/macroexecutor.1 | 6 +++--- doc/man/sardanatestsuite.1 | 6 +++--- doc/man/sequencer.1 | 6 +++--- doc/man/spock.1 | 4 ++-- doc/man/ubmatrix.1 | 6 +++--- 10 files changed, 29 insertions(+), 29 deletions(-) mode change 100644 => 100755 doc/man/MacroServer.1 mode change 100644 => 100755 doc/man/Pool.1 mode change 100644 => 100755 doc/man/Sardana.1 mode change 100644 => 100755 doc/man/diffractometeralignment.1 mode change 100644 => 100755 doc/man/hklscan.1 mode change 100644 => 100755 doc/man/macroexecutor.1 mode change 100644 => 100755 doc/man/sardanatestsuite.1 mode change 100644 => 100755 doc/man/sequencer.1 mode change 100644 => 100755 doc/man/ubmatrix.1 diff --git a/doc/man/MacroServer.1 b/doc/man/MacroServer.1 old mode 100644 new mode 100755 index 0bfce5ccc0..1c5a666807 --- a/doc/man/MacroServer.1 +++ b/doc/man/MacroServer.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH MACROSERVER "1" "August 2018" "MacroServer 2.5.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH MACROSERVER "1" "January 2019" "MacroServer 2.6.0" "User Commands" .SH NAME -MacroServer \- manual page for MacroServer 2.5.0 +MacroServer \- manual page for MacroServer 2.6.0 .SH SYNOPSIS .B usage: \fI\,MacroServer instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/Pool.1 b/doc/man/Pool.1 old mode 100644 new mode 100755 index fae5daa19f..6907c255a0 --- a/doc/man/Pool.1 +++ b/doc/man/Pool.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH POOL "1" "August 2018" "Pool 2.5.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH POOL "1" "January 2019" "Pool 2.6.0" "User Commands" .SH NAME -Pool \- manual page for Pool 2.5.0 +Pool \- manual page for Pool 2.6.0 .SH SYNOPSIS .B usage: \fI\,Pool instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/Sardana.1 b/doc/man/Sardana.1 old mode 100644 new mode 100755 index 9fa4ea1d9d..a596bb21b0 --- a/doc/man/Sardana.1 +++ b/doc/man/Sardana.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH SARDANA "1" "August 2018" "Sardana 2.5.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH SARDANA "1" "January 2019" "Sardana 2.6.0" "User Commands" .SH NAME -Sardana \- manual page for Sardana 2.5.0 +Sardana \- manual page for Sardana 2.6.0 .SH SYNOPSIS .B usage: \fI\,Sardana instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/diffractometeralignment.1 b/doc/man/diffractometeralignment.1 old mode 100644 new mode 100755 index 764cef0d7f..21fcdda97a --- a/doc/man/diffractometeralignment.1 +++ b/doc/man/diffractometeralignment.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH DIFFRACTOMETERALIGNMENT "1" "August 2018" "diffractometeralignment 2.5.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH DIFFRACTOMETERALIGNMENT "1" "January 2019" "diffractometeralignment 2.6.0" "User Commands" .SH NAME -diffractometeralignment \- manual page for diffractometeralignment 2.5.0 +diffractometeralignment \- manual page for diffractometeralignment 2.6.0 .SH SYNOPSIS .B diffractometeralignment \fI\, \/\fR[\fI\,door_name\/\fR] diff --git a/doc/man/hklscan.1 b/doc/man/hklscan.1 old mode 100644 new mode 100755 index d1399936db..5f51d57c05 --- a/doc/man/hklscan.1 +++ b/doc/man/hklscan.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH HKLSCAN "1" "August 2018" "hklscan 2.5.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH HKLSCAN "1" "January 2019" "hklscan 2.6.0" "User Commands" .SH NAME -hklscan \- manual page for hklscan 2.5.0 +hklscan \- manual page for hklscan 2.6.0 .SH SYNOPSIS .B hklscan \fI\, \/\fR[\fI\,door_name\/\fR] diff --git a/doc/man/macroexecutor.1 b/doc/man/macroexecutor.1 old mode 100644 new mode 100755 index 4e0a7522eb..893df12dd2 --- a/doc/man/macroexecutor.1 +++ b/doc/man/macroexecutor.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH MACROEXECUTOR "1" "August 2018" "macroexecutor 2.5.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH MACROEXECUTOR "1" "January 2019" "macroexecutor 2.6.0" "User Commands" .SH NAME -macroexecutor \- manual page for macroexecutor 2.5.0 +macroexecutor \- manual page for macroexecutor 2.6.0 .SH SYNOPSIS .B macroexecutor [\fI\,options\/\fR] diff --git a/doc/man/sardanatestsuite.1 b/doc/man/sardanatestsuite.1 old mode 100644 new mode 100755 index 773d0832e8..da6a46657f --- a/doc/man/sardanatestsuite.1 +++ b/doc/man/sardanatestsuite.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH SARDANATESTSUITE "1" "August 2018" "sardanatestsuite 2.5.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH SARDANATESTSUITE "1" "January 2019" "sardanatestsuite 2.6.0" "User Commands" .SH NAME -sardanatestsuite \- manual page for sardanatestsuite 2.5.0 +sardanatestsuite \- manual page for sardanatestsuite 2.6.0 .SH DESCRIPTION usage: sardanatestsuite [\-h] [\-e EXCLUDE_PATTERN] [\-\-version] .PP diff --git a/doc/man/sequencer.1 b/doc/man/sequencer.1 old mode 100644 new mode 100755 index c8c454c47e..ca582e0a75 --- a/doc/man/sequencer.1 +++ b/doc/man/sequencer.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH SEQUENCER "1" "August 2018" "sequencer 2.5.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH SEQUENCER "1" "January 2019" "sequencer 2.6.0" "User Commands" .SH NAME -sequencer \- manual page for sequencer 2.5.0 +sequencer \- manual page for sequencer 2.6.0 .SH SYNOPSIS .B sequencer [\fI\,options\/\fR] diff --git a/doc/man/spock.1 b/doc/man/spock.1 index 5fec32848d..dbb42e9555 100644 --- a/doc/man/spock.1 +++ b/doc/man/spock.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH SPOCK "1" "August 2018" "spock 2.5.0" "User Commands" +.TH SPOCK "1" "August 2018" "spock 2.6.0" "User Commands" .SH NAME -spock \- manual page for spock 2.5.0 +spock \- manual page for spock 2.6.0 .SH DESCRIPTION ========= .IP diff --git a/doc/man/ubmatrix.1 b/doc/man/ubmatrix.1 old mode 100644 new mode 100755 index 0e0aafaa6f..761f6c98f4 --- a/doc/man/ubmatrix.1 +++ b/doc/man/ubmatrix.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH UBMATRIX "1" "August 2018" "ubmatrix 2.5.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH UBMATRIX "1" "January 2019" "ubmatrix 2.6.0" "User Commands" .SH NAME -ubmatrix \- manual page for ubmatrix 2.5.0 +ubmatrix \- manual page for ubmatrix 2.6.0 .SH SYNOPSIS .B ubmatrix \fI\,\/\fR From 28a55a09c46d5986f35c6268015477160231d130 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 31 Jan 2019 11:49:57 +0100 Subject: [PATCH 559/652] Update changelog to 2.6.0 --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 853694a84a..6f8e25249e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This file follows the formats and conventions from [keepachangelog.com] ## [Unreleased] +### Added + +## [2.6.0] 2019-01-31 + ### Added - New acquisition and synchronization concepts (SEP18, #773): - Preparation of measurement group for a group of acquisitions is mandatory @@ -79,7 +83,6 @@ This file follows the formats and conventions from [keepachangelog.com] - Unused class `sardana.taurus.qt.qtgui.extra_macroexecutor.dooroutput.DoorAttrListener` ### Removed - - Support to Qt < 4.7.4 (#1006, #1009) ## [2.5.0] 2018-08-10 @@ -553,7 +556,8 @@ Main improvements since sardana 1.5.0 (aka Jan15): [keepachangelog.com]: http://keepachangelog.com -[Unreleased]: https://github.com/sardana-org/sardana/compare/2.5.0...HEAD +[Unreleased]: https://github.com/sardana-org/sardana/compare/2.6.0...HEAD +[2.6.0]: https://github.com/sardana-org/sardana/compare/2.5.0...2.6.0 [2.5.0]: https://github.com/sardana-org/sardana/compare/2.4.0...2.5.0 [2.4.0]: https://github.com/sardana-org/sardana/compare/2.3.2...2.4.0 [2.3.2]: https://github.com/sardana-org/sardana/compare/2.3.1...2.3.2 From aab5ec8cb49ddb169aa100bbc976dcdabcf86ba0 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Thu, 31 Jan 2019 12:39:08 +0100 Subject: [PATCH 560/652] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 853694a84a..88e47cb21e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,7 @@ This file follows the formats and conventions from [keepachangelog.com] configurations. An event offers an option to reload the whole experiment configuration or keep the local changes. `expconf` started with `--auto-update` option will automatically reload the whole experiment - configuration (#806, #882, #988) + configuration (#806, #882, #988, #1028) - Reload macro library overriding another library (#927, #946) - Avoid final padding in timescan when it was stopped by user (#869, #935) - Moveables limits check in continuous scans when moveables position attribute From 3889dd2fc285dc7dff3c6d12a53b20f4c0752baf Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Thu, 31 Jan 2019 14:41:56 +0100 Subject: [PATCH 561/652] (m) Fix tooltip An incorrect variable is used to set the "show scan" button tooltip when using Qt5. Fix it. --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index eec67c9600..915a6b37b3 100755 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -243,11 +243,11 @@ def __init__(self, parent=None, door=None, plotsButton=True, # TODO: Disable show scan button since scan plot have to be # adapted to support QT5 # -------------------------------------------------------------------- - from taurus.external.qt import PYQT4, QT_API + from taurus.external.qt import PYQT4, API if not PYQT4: self.debug('Show plots is only supported with PyQt4 for now') plotsButton = False - tooltip = "Show/Hide plots is not ready for %s" % QT_API + tooltip = "Show/Hide plots is not ready for %s" % API # -------------------------------------------------------------------- icon = resource.getIcon(":/actions/view.svg") From 4765c7c3c7139b29a33ae9f38c9fffcd4a38ba50 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 31 Jan 2019 17:21:26 +0100 Subject: [PATCH 562/652] Remove unnecessary signal connect Similarly to work done in commit c653457 remove unnecessary connections in LineEditParam and CheckBoxParam parameditors. This work is done by ParamEditorDelegate. --- .../macroparameterseditor/parameditors.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py index 310eb5c026..db1ed40724 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py @@ -160,10 +160,6 @@ class LineEditParam(ParamBase, Qt.QLineEdit): def __init__(self, parent=None, paramModel=None): Qt.QLineEdit.__init__(self, parent) ParamBase.__init__(self, paramModel) - self.textChanged.connect(self.onTextChanged) - - def onTextChanged(self): - self.onModelChanged() # def setDefaultValue(self): # defVal = self.paramModel().defValue() @@ -186,7 +182,6 @@ class CheckBoxParam(ParamBase, Qt.QCheckBox): def __init__(self, parent=None, paramModel=None): Qt.QCheckBox.__init__(self, parent) ParamBase.__init__(self, paramModel) - self.stateChanged.connect(self.onStateChanged) def getValue(self): return str(self.isChecked()) @@ -194,9 +189,6 @@ def getValue(self): def setValue(self, value): self.setChecked(str2bool(value)) - def onStateChanged(self): - self.onModelChanged() - class SpinBoxParam(ParamBase, Qt.QSpinBox): From 24ab790665840e1121dcf818302474a173cbd798 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 10:13:12 +0100 Subject: [PATCH 563/652] Improve macroexecutor error msg when loading settings --- src/sardana/taurus/core/tango/sardana/macroserver.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macroserver.py b/src/sardana/taurus/core/tango/sardana/macroserver.py index a21eeb02dd..795cbc73a7 100755 --- a/src/sardana/taurus/core/tango/sardana/macroserver.py +++ b/src/sardana/taurus/core/tango/sardana/macroserver.py @@ -1114,8 +1114,11 @@ def fillMacroNodeAdditionalInfos(self, macroNode): macroName = macroNode.name() macroInfoObj = self.getMacroInfoObj(macroName) if macroInfoObj is None: - raise Exception( - "It was not possible to get information about %s macro.\nCheck if MacroServer is alive and if this macro exist." % macroName) + msg = "It was not possible to get information about {0} " \ + "macro. Check if MacroServer is alive and if this macro " \ + "exist.".format(macroName) + self.info(msg) + raise Exception("no info about macro {0}".format(macroName)) allowedHookPlaces = [] hints = macroInfoObj.hints or {} for hook in hints.get("allowsHooks", []): From fa871a798c5f98f7504e0c164a3407356056c310 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 11:22:07 +0100 Subject: [PATCH 564/652] Make auto update action correctly restore its settings Register config property with action's setter/getter so it is correctly restored from the setting. --- .../taurus/qt/qtgui/extra_sardana/expdescription.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index eec67c9600..536c5ed1ce 100755 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -200,8 +200,8 @@ def __init__(self, parent=None, door=None, plotsButton=True, self._dirty = False self._dirtyMntGrps = set() - self._warningWidget = None self._autoUpdate = False + self._warningWidget = None self.setContextMenuPolicy(Qt.Qt.ActionsContextMenu) self._autoUpdateAction = Qt.QAction("Auto update", self) self._autoUpdateAction.setCheckable(True) @@ -209,7 +209,9 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.addAction(self._autoUpdateAction) self._autoUpdateAction.setChecked(autoUpdate) self.registerConfigProperty( - self.isAutoUpdate, self.setAutoUpdate, "autoUpdate") + self._autoUpdateAction.isChecked, + self._autoUpdateAction.setChecked, + "autoUpdate") # Pending event variables self._expConfChangedDialog = None @@ -281,9 +283,6 @@ def setAutoUpdate(self, auto_update): self._warningWidget = None self._autoUpdate = auto_update - def isAutoUpdate(self): - return self._autoUpdate - def _getWarningWidget(self): w = Qt.QWidget() layout = QtGui.QHBoxLayout() From eda3a84661b9b9b94e3287c7e70abdf6f0e6ec6f Mon Sep 17 00:00:00 2001 From: reszelaz Date: Fri, 1 Feb 2019 12:53:31 +0100 Subject: [PATCH 565/652] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88e47cb21e..a68971f768 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,7 @@ This file follows the formats and conventions from [keepachangelog.com] configurations. An event offers an option to reload the whole experiment configuration or keep the local changes. `expconf` started with `--auto-update` option will automatically reload the whole experiment - configuration (#806, #882, #988, #1028) + configuration (#806, #882, #988, #1028, #1033) - Reload macro library overriding another library (#927, #946) - Avoid final padding in timescan when it was stopped by user (#869, #935) - Moveables limits check in continuous scans when moveables position attribute From c4d02b7cee66734afa3ab177658fad4e84b73ef5 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 15:51:07 +0100 Subject: [PATCH 566/652] Use python property instead of taurus property Refactor code to use standard python property instead of taurus property implementation. --- src/sardana/macroserver/macro.py | 109 +++++++++++++++++-------------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/src/sardana/macroserver/macro.py b/src/sardana/macroserver/macro.py index 6e063bab2e..4b40819f11 100644 --- a/src/sardana/macroserver/macro.py +++ b/src/sardana/macroserver/macro.py @@ -230,57 +230,66 @@ def appendHook(self, hook_info): except KeyError: self._hookHintsDict[hint] = [hook] - @propertx - def hooks(): - def get(self): - return self._getHooks() + @property + def hooks(self): + """Hooks (callables) attached to the macro object together with the + hook places (places where they will be called). + + :getter: Return all hooks attached to the macro object (including + general hooks). + :setter: Set hooks to the object. **This may override eventual + general hooks.** + Use :meth:`~sardana.macroserver.macro.Hookable.appendHook` + if the general hooks want to be kept. For backwards compatibility + accepts hook in the :obj:`list`\ format. + :type: :obj:`list`\<:obj:`tuple`\> where each tuple has two + elements: callable and :obj:`list`\<:obj:`str`\> + """ + return self._getHooks() - def set(self, hooks): - '''hooks must be list>. Exceptionally, for - backwards compatibility, list is also admitted, but may - not be supported in the future. - "two variables are created: - - self._hooks (list>) (will be a tuple - regardless of what was passed) - - self._hookHintsDict (dict) a dict of key=hint and - value=list of hooks with that hint. - self._hookHintsDict also stores two - special keys: "_ALL_": which contains all - the hooks "_NOHINTS_": which contains the - hooks that don't provide hints - ''' - if not isinstance(hooks, list): - self.error( - 'the hooks must be passed as a list>') - return - - # store self._hooks, making sure it is of type: - # list> - self._hooks = [] - for h in hooks: - if isinstance(h, (tuple, list)) and len(h) == 2: - self._hooks.append(h) - else: # we assume that hooks is a list - self._hooks.append((h, [])) - self.info( - 'Deprecation warning: hooks should be set with a list of hints. See Hookable API docs') - - # delete _hookHintsDict to force its recreation on the next access - if hasattr(self, '_hookHintsDict'): - del self._hookHintsDict - # create _hookHintsDict - self._getHookHintsDict()['_ALL_'] = zip(*self._hooks)[0] - nohints = self._hookHintsDict['_NOHINTS_'] - for hook, hints in self._hooks: - if len(hints) == 0: - nohints.append(hook) - else: - for hint in hints: - try: - self._hookHintsDict[hint].append(hook) - except KeyError: - self._hookHintsDict[hint] = [hook] - return get, set + @hooks.setter + def hooks(self, hooks): + """Sets hooks. Internally two variables instance members are created: + + - _hooks (list>) (will be a tuple regardless of + what was passed) + - _hookHintsDict (dict) a dict of key=hint and value=list + of hooks with that hint. _hookHintsDict also stores two special + keys: "_ALL_": which contains all the hooks "_NOHINTS_": which + contains the hooks that don't provide hints + + """ + if not isinstance(hooks, list): + self.error( + 'the hooks must be passed as a list>') + return + + # store self._hooks, making sure it is of type: + # list> + self._hooks = [] + for h in hooks: + if isinstance(h, (tuple, list)) and len(h) == 2: + self._hooks.append(h) + else: # we assume that hooks is a list + self._hooks.append((h, [])) + self.info( + 'Deprecation warning: hooks should be set with a list of hints. See Hookable API docs') + + # delete _hookHintsDict to force its recreation on the next access + if hasattr(self, '_hookHintsDict'): + del self._hookHintsDict + # create _hookHintsDict + self._getHookHintsDict()['_ALL_'] = zip(*self._hooks)[0] + nohints = self._hookHintsDict['_NOHINTS_'] + for hook, hints in self._hooks: + if len(hints) == 0: + nohints.append(hook) + else: + for hint in hints: + try: + self._hookHintsDict[hint].append(hook) + except KeyError: + self._hookHintsDict[hint] = [hook] class ExecMacroHook(object): From 8d9ebedb7a79055c7b7d40cb0e20125d4db80564 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 15:51:39 +0100 Subject: [PATCH 567/652] Remove note cause it is already included in the hooks property docstring. --- doc/source/users/macro_hooks.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/doc/source/users/macro_hooks.rst b/doc/source/users/macro_hooks.rst index 98377d3064..cb396e2dd6 100644 --- a/doc/source/users/macro_hooks.rst +++ b/doc/source/users/macro_hooks.rst @@ -23,14 +23,6 @@ using three different ways: All available macros can be used as a hook. .. _sardana-macros-hooks-general: - -**Note:**If hooks are attached programmatically to a macro using the -:attr:`~sardana.macroserver.macro.Hookable.hooks` property -the general hooks are deactivated when running this macro. -The method :meth:`~sardana.macroserver.macro.Hookable.appendHook` -has to be used if the general hooks want to be kept. The Sequencer Hooks -do not have any effect on the general hooks, they will be run if they -are defined. General Hooks ------------- From bce2aea5e53412d0a5cc3d001c99ca578ae52283 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 15:53:22 +0100 Subject: [PATCH 568/652] Reformat note --- .../devel/howto_macros/macros_general.rst | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 8e23fc1309..e747771556 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -915,18 +915,13 @@ using the :meth:`~sardana.macroserver.macro.Hookable.appendHook` method:: hookable_macro.appendHook((hook_function, ["another-hook-place"])) self.runMacro(hookable_macro) -Note the following differences between using the property or the method: - -- the property :attr:`~sardana.macroserver.macro.Hookable.hooks` sets all hooks - at once, the method :meth:`~sardana.macroserver.macro.Hookable.appendHook` - appends hooks one by one. - -- the property :attr:`~sardana.macroserver.macro.Hookable.hooks` deactivate the - general hooks for the macro it is used with, the method - :meth:`~sardana.macroserver.macro.Hookable.appendHook` keeps the general - hooks for this macro. - - +.. note:: Be aware of the following difference between setting the + :attr:`~sardana.macroserver.macro.Hookable.hooks` property and using the + :meth:`~sardana.macroserver.macro.Hookable.appendHook` method. + Setting the property applies all hooks at once but may override + :ref:`general hooks` eventually attached to + the macro. Using the method appends just one hook but does not affect + the general hooks eventually attached to the macro. .. _sardana-macro-using-external-libraries: From 71fc27b61ecb32d6e08716b2d0514eca99ea6d0d Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 15:59:37 +0100 Subject: [PATCH 569/652] Fix flake8 --- src/sardana/macroserver/macro.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sardana/macroserver/macro.py b/src/sardana/macroserver/macro.py index 4b40819f11..2e6a41cc7f 100644 --- a/src/sardana/macroserver/macro.py +++ b/src/sardana/macroserver/macro.py @@ -244,7 +244,7 @@ def hooks(self): accepts hook in the :obj:`list`\ format. :type: :obj:`list`\<:obj:`tuple`\> where each tuple has two elements: callable and :obj:`list`\<:obj:`str`\> - """ + """ # noqa return self._getHooks() @hooks.setter @@ -272,8 +272,9 @@ def hooks(self, hooks): self._hooks.append(h) else: # we assume that hooks is a list self._hooks.append((h, [])) - self.info( - 'Deprecation warning: hooks should be set with a list of hints. See Hookable API docs') + msg = ("Deprecation warning: hooks should be set with a" + " list of hints. See Hookable API docs") + self.info(msg) # delete _hookHintsDict to force its recreation on the next access if hasattr(self, '_hookHintsDict'): From 9c73280bd38d80c2523e559ccf6b222f5809a725 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Fri, 1 Feb 2019 16:49:51 +0100 Subject: [PATCH 570/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a68971f768..5bddbfeace 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ This file follows the formats and conventions from [keepachangelog.com] - Document remote connection to MacroServer Python process (RConsolePort Tango property) (#984) - sardana.taurus.qt.qtgui.macrolistener (moved from taurus.qt.qtgui.taurusgui) +- Documentation on differences between `Hookable.hooks` and `Hookable.appendHook` + (#962, #1013) ### Fixed - Do not read 1D and 2D experimental channels during software acquisition loop From a70474e9ae825818ef516fc702ee470bbfae1cd7 Mon Sep 17 00:00:00 2001 From: teresa Date: Tue, 15 Jan 2019 11:59:24 +0100 Subject: [PATCH 571/652] Documenting how to add programmatic hooks keeping the general ones --- doc/source/devel/howto_macros/macros_general.rst | 12 ++++++++++++ doc/source/users/macro_hooks.rst | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 23041beec6..dfd19302ce 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -915,6 +915,18 @@ using the :meth:`~sardana.macroserver.macro.Hookable.appendHook` method:: hookable_macro.appendHook((hook_function, ["another-hook-place"])) self.runMacro(hookable_macro) +Note the following differences between using the property or the method: + +- the property :attr:`~sardana.macroserver.macro.Hookable.hooks` sets all hooks + at once, the method :meth:`~sardana.macroserver.macro.Hookable.appendHook` + appends hooks one by one. + +- the property :attr:`~sardana.macroserver.macro.Hookable.hooks` deactivate the + general hooks for the macro it is used with, the the method + :meth:`~sardana.macroserver.macro.Hookable.appendHook` keeps the general + hooks for this macro. + + .. _sardana-macro-using-external-libraries: diff --git a/doc/source/users/macro_hooks.rst b/doc/source/users/macro_hooks.rst index b3f1969204..98377d3064 100644 --- a/doc/source/users/macro_hooks.rst +++ b/doc/source/users/macro_hooks.rst @@ -24,6 +24,14 @@ All available macros can be used as a hook. .. _sardana-macros-hooks-general: +**Note:**If hooks are attached programmatically to a macro using the +:attr:`~sardana.macroserver.macro.Hookable.hooks` property +the general hooks are deactivated when running this macro. +The method :meth:`~sardana.macroserver.macro.Hookable.appendHook` +has to be used if the general hooks want to be kept. The Sequencer Hooks +do not have any effect on the general hooks, they will be run if they +are defined. + General Hooks ------------- @@ -40,6 +48,7 @@ For each hook place, several hooks can be attached, they will be run in the order they were added. The same hook can be run several times in the same place if it was added several times. + Examples: - Check motor limits in step scans (pre-scan) From e81afaf71f85a7f911aac641d3addbc19c429c12 Mon Sep 17 00:00:00 2001 From: teresa Date: Wed, 16 Jan 2019 08:44:12 +0100 Subject: [PATCH 572/652] Correcting typo --- doc/source/devel/howto_macros/macros_general.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index dfd19302ce..8e23fc1309 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -922,7 +922,7 @@ Note the following differences between using the property or the method: appends hooks one by one. - the property :attr:`~sardana.macroserver.macro.Hookable.hooks` deactivate the - general hooks for the macro it is used with, the the method + general hooks for the macro it is used with, the method :meth:`~sardana.macroserver.macro.Hookable.appendHook` keeps the general hooks for this macro. From 5ae3a8a1798f90e2eaec209b9851af5f56bb8666 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 31 Jan 2019 17:21:26 +0100 Subject: [PATCH 573/652] Remove unnecessary signal connect Similarly to work done in commit c653457 remove unnecessary connections in LineEditParam and CheckBoxParam parameditors. This work is done by ParamEditorDelegate. --- .../macroparameterseditor/parameditors.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py index 310eb5c026..db1ed40724 100644 --- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py +++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroparameterseditor/parameditors.py @@ -160,10 +160,6 @@ class LineEditParam(ParamBase, Qt.QLineEdit): def __init__(self, parent=None, paramModel=None): Qt.QLineEdit.__init__(self, parent) ParamBase.__init__(self, paramModel) - self.textChanged.connect(self.onTextChanged) - - def onTextChanged(self): - self.onModelChanged() # def setDefaultValue(self): # defVal = self.paramModel().defValue() @@ -186,7 +182,6 @@ class CheckBoxParam(ParamBase, Qt.QCheckBox): def __init__(self, parent=None, paramModel=None): Qt.QCheckBox.__init__(self, parent) ParamBase.__init__(self, paramModel) - self.stateChanged.connect(self.onStateChanged) def getValue(self): return str(self.isChecked()) @@ -194,9 +189,6 @@ def getValue(self): def setValue(self, value): self.setChecked(str2bool(value)) - def onStateChanged(self): - self.onModelChanged() - class SpinBoxParam(ParamBase, Qt.QSpinBox): From 2ccb172ab03aff383da174ad1b51626d663058d7 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 10:13:12 +0100 Subject: [PATCH 574/652] Improve macroexecutor error msg when loading settings --- src/sardana/taurus/core/tango/sardana/macroserver.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macroserver.py b/src/sardana/taurus/core/tango/sardana/macroserver.py index a21eeb02dd..795cbc73a7 100755 --- a/src/sardana/taurus/core/tango/sardana/macroserver.py +++ b/src/sardana/taurus/core/tango/sardana/macroserver.py @@ -1114,8 +1114,11 @@ def fillMacroNodeAdditionalInfos(self, macroNode): macroName = macroNode.name() macroInfoObj = self.getMacroInfoObj(macroName) if macroInfoObj is None: - raise Exception( - "It was not possible to get information about %s macro.\nCheck if MacroServer is alive and if this macro exist." % macroName) + msg = "It was not possible to get information about {0} " \ + "macro. Check if MacroServer is alive and if this macro " \ + "exist.".format(macroName) + self.info(msg) + raise Exception("no info about macro {0}".format(macroName)) allowedHookPlaces = [] hints = macroInfoObj.hints or {} for hook in hints.get("allowsHooks", []): From a2d1ca57d36ef0016e4fad259cffa77615f1fff6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 11:22:07 +0100 Subject: [PATCH 575/652] Make auto update action correctly restore its settings Register config property with action's setter/getter so it is correctly restored from the setting. --- .../taurus/qt/qtgui/extra_sardana/expdescription.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 915a6b37b3..9e1ecb2930 100755 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -200,8 +200,8 @@ def __init__(self, parent=None, door=None, plotsButton=True, self._dirty = False self._dirtyMntGrps = set() - self._warningWidget = None self._autoUpdate = False + self._warningWidget = None self.setContextMenuPolicy(Qt.Qt.ActionsContextMenu) self._autoUpdateAction = Qt.QAction("Auto update", self) self._autoUpdateAction.setCheckable(True) @@ -209,7 +209,9 @@ def __init__(self, parent=None, door=None, plotsButton=True, self.addAction(self._autoUpdateAction) self._autoUpdateAction.setChecked(autoUpdate) self.registerConfigProperty( - self.isAutoUpdate, self.setAutoUpdate, "autoUpdate") + self._autoUpdateAction.isChecked, + self._autoUpdateAction.setChecked, + "autoUpdate") # Pending event variables self._expConfChangedDialog = None @@ -281,9 +283,6 @@ def setAutoUpdate(self, auto_update): self._warningWidget = None self._autoUpdate = auto_update - def isAutoUpdate(self): - return self._autoUpdate - def _getWarningWidget(self): w = Qt.QWidget() layout = QtGui.QHBoxLayout() From 272fd9e3d0b4cff172a94b837fc44234784693db Mon Sep 17 00:00:00 2001 From: reszelaz Date: Fri, 1 Feb 2019 12:53:31 +0100 Subject: [PATCH 576/652] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 488c197910..a6294b1f34 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,7 @@ This file follows the formats and conventions from [keepachangelog.com] configurations. An event offers an option to reload the whole experiment configuration or keep the local changes. `expconf` started with `--auto-update` option will automatically reload the whole experiment - configuration (#806, #882, #988, #1028) + configuration (#806, #882, #988, #1028, #1033) - Reload macro library overriding another library (#927, #946) - Avoid final padding in timescan when it was stopped by user (#869, #935) - Moveables limits check in continuous scans when moveables position attribute From dceb139313c15e14d48d4f69058ae7150b4645fc Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 15:51:07 +0100 Subject: [PATCH 577/652] Use python property instead of taurus property Refactor code to use standard python property instead of taurus property implementation. --- src/sardana/macroserver/macro.py | 109 +++++++++++++++++-------------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/src/sardana/macroserver/macro.py b/src/sardana/macroserver/macro.py index 6e063bab2e..4b40819f11 100644 --- a/src/sardana/macroserver/macro.py +++ b/src/sardana/macroserver/macro.py @@ -230,57 +230,66 @@ def appendHook(self, hook_info): except KeyError: self._hookHintsDict[hint] = [hook] - @propertx - def hooks(): - def get(self): - return self._getHooks() + @property + def hooks(self): + """Hooks (callables) attached to the macro object together with the + hook places (places where they will be called). + + :getter: Return all hooks attached to the macro object (including + general hooks). + :setter: Set hooks to the object. **This may override eventual + general hooks.** + Use :meth:`~sardana.macroserver.macro.Hookable.appendHook` + if the general hooks want to be kept. For backwards compatibility + accepts hook in the :obj:`list`\ format. + :type: :obj:`list`\<:obj:`tuple`\> where each tuple has two + elements: callable and :obj:`list`\<:obj:`str`\> + """ + return self._getHooks() - def set(self, hooks): - '''hooks must be list>. Exceptionally, for - backwards compatibility, list is also admitted, but may - not be supported in the future. - "two variables are created: - - self._hooks (list>) (will be a tuple - regardless of what was passed) - - self._hookHintsDict (dict) a dict of key=hint and - value=list of hooks with that hint. - self._hookHintsDict also stores two - special keys: "_ALL_": which contains all - the hooks "_NOHINTS_": which contains the - hooks that don't provide hints - ''' - if not isinstance(hooks, list): - self.error( - 'the hooks must be passed as a list>') - return - - # store self._hooks, making sure it is of type: - # list> - self._hooks = [] - for h in hooks: - if isinstance(h, (tuple, list)) and len(h) == 2: - self._hooks.append(h) - else: # we assume that hooks is a list - self._hooks.append((h, [])) - self.info( - 'Deprecation warning: hooks should be set with a list of hints. See Hookable API docs') - - # delete _hookHintsDict to force its recreation on the next access - if hasattr(self, '_hookHintsDict'): - del self._hookHintsDict - # create _hookHintsDict - self._getHookHintsDict()['_ALL_'] = zip(*self._hooks)[0] - nohints = self._hookHintsDict['_NOHINTS_'] - for hook, hints in self._hooks: - if len(hints) == 0: - nohints.append(hook) - else: - for hint in hints: - try: - self._hookHintsDict[hint].append(hook) - except KeyError: - self._hookHintsDict[hint] = [hook] - return get, set + @hooks.setter + def hooks(self, hooks): + """Sets hooks. Internally two variables instance members are created: + + - _hooks (list>) (will be a tuple regardless of + what was passed) + - _hookHintsDict (dict) a dict of key=hint and value=list + of hooks with that hint. _hookHintsDict also stores two special + keys: "_ALL_": which contains all the hooks "_NOHINTS_": which + contains the hooks that don't provide hints + + """ + if not isinstance(hooks, list): + self.error( + 'the hooks must be passed as a list>') + return + + # store self._hooks, making sure it is of type: + # list> + self._hooks = [] + for h in hooks: + if isinstance(h, (tuple, list)) and len(h) == 2: + self._hooks.append(h) + else: # we assume that hooks is a list + self._hooks.append((h, [])) + self.info( + 'Deprecation warning: hooks should be set with a list of hints. See Hookable API docs') + + # delete _hookHintsDict to force its recreation on the next access + if hasattr(self, '_hookHintsDict'): + del self._hookHintsDict + # create _hookHintsDict + self._getHookHintsDict()['_ALL_'] = zip(*self._hooks)[0] + nohints = self._hookHintsDict['_NOHINTS_'] + for hook, hints in self._hooks: + if len(hints) == 0: + nohints.append(hook) + else: + for hint in hints: + try: + self._hookHintsDict[hint].append(hook) + except KeyError: + self._hookHintsDict[hint] = [hook] class ExecMacroHook(object): From 92aa7b6a0b201b4c874b154c67abd6faea2f325e Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 15:51:39 +0100 Subject: [PATCH 578/652] Remove note cause it is already included in the hooks property docstring. --- doc/source/users/macro_hooks.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/doc/source/users/macro_hooks.rst b/doc/source/users/macro_hooks.rst index 98377d3064..cb396e2dd6 100644 --- a/doc/source/users/macro_hooks.rst +++ b/doc/source/users/macro_hooks.rst @@ -23,14 +23,6 @@ using three different ways: All available macros can be used as a hook. .. _sardana-macros-hooks-general: - -**Note:**If hooks are attached programmatically to a macro using the -:attr:`~sardana.macroserver.macro.Hookable.hooks` property -the general hooks are deactivated when running this macro. -The method :meth:`~sardana.macroserver.macro.Hookable.appendHook` -has to be used if the general hooks want to be kept. The Sequencer Hooks -do not have any effect on the general hooks, they will be run if they -are defined. General Hooks ------------- From 7a81c7fffbb3e934b703186b0d3990464606015e Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 15:53:22 +0100 Subject: [PATCH 579/652] Reformat note --- .../devel/howto_macros/macros_general.rst | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst index 8e23fc1309..e747771556 100644 --- a/doc/source/devel/howto_macros/macros_general.rst +++ b/doc/source/devel/howto_macros/macros_general.rst @@ -915,18 +915,13 @@ using the :meth:`~sardana.macroserver.macro.Hookable.appendHook` method:: hookable_macro.appendHook((hook_function, ["another-hook-place"])) self.runMacro(hookable_macro) -Note the following differences between using the property or the method: - -- the property :attr:`~sardana.macroserver.macro.Hookable.hooks` sets all hooks - at once, the method :meth:`~sardana.macroserver.macro.Hookable.appendHook` - appends hooks one by one. - -- the property :attr:`~sardana.macroserver.macro.Hookable.hooks` deactivate the - general hooks for the macro it is used with, the method - :meth:`~sardana.macroserver.macro.Hookable.appendHook` keeps the general - hooks for this macro. - - +.. note:: Be aware of the following difference between setting the + :attr:`~sardana.macroserver.macro.Hookable.hooks` property and using the + :meth:`~sardana.macroserver.macro.Hookable.appendHook` method. + Setting the property applies all hooks at once but may override + :ref:`general hooks` eventually attached to + the macro. Using the method appends just one hook but does not affect + the general hooks eventually attached to the macro. .. _sardana-macro-using-external-libraries: From e2c894aa659363fc0e10752d333339cc8a7d6e2a Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Feb 2019 15:59:37 +0100 Subject: [PATCH 580/652] Fix flake8 --- src/sardana/macroserver/macro.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sardana/macroserver/macro.py b/src/sardana/macroserver/macro.py index 4b40819f11..2e6a41cc7f 100644 --- a/src/sardana/macroserver/macro.py +++ b/src/sardana/macroserver/macro.py @@ -244,7 +244,7 @@ def hooks(self): accepts hook in the :obj:`list`\ format. :type: :obj:`list`\<:obj:`tuple`\> where each tuple has two elements: callable and :obj:`list`\<:obj:`str`\> - """ + """ # noqa return self._getHooks() @hooks.setter @@ -272,8 +272,9 @@ def hooks(self, hooks): self._hooks.append(h) else: # we assume that hooks is a list self._hooks.append((h, [])) - self.info( - 'Deprecation warning: hooks should be set with a list of hints. See Hookable API docs') + msg = ("Deprecation warning: hooks should be set with a" + " list of hints. See Hookable API docs") + self.info(msg) # delete _hookHintsDict to force its recreation on the next access if hasattr(self, '_hookHintsDict'): From dc334f79d00c10ada5caebdb3ad0f3295c2d7848 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Fri, 1 Feb 2019 16:49:51 +0100 Subject: [PATCH 581/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6294b1f34..6813b37121 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ This file follows the formats and conventions from [keepachangelog.com] - Document remote connection to MacroServer Python process (RConsolePort Tango property) (#984) - sardana.taurus.qt.qtgui.macrolistener (moved from taurus.qt.qtgui.taurusgui) +- Documentation on differences between `Hookable.hooks` and `Hookable.appendHook` + (#962, #1013) ### Fixed - Do not read 1D and 2D experimental channels during software acquisition loop From a7f9f24875aa90c7ad5db8c7956deab27a87c1b4 Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Mon, 4 Feb 2019 13:01:47 +0100 Subject: [PATCH 582/652] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6813b37121..98e36e488b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ This file follows the formats and conventions from [keepachangelog.com] - `SoftwareStart` and `HardwareStart` synchronization in `DummyCounterTimerController` - Support to Qt5 for Sardana-Taurus widgets and Sardana-Taurus extensions (#1006, - #1009) + #1009, #1031) - Possibility to define macros with optional parameters. These must be the last ones in the definition (#285, #876, #943, #941, #955) - Possibility to pass values of repeat paramters with just one member without From e5c4e16add3385dd8765893470575bed728679b1 Mon Sep 17 00:00:00 2001 From: teresa Date: Mon, 4 Feb 2019 13:22:38 +0100 Subject: [PATCH 583/652] Adding license and correcting typo --- src/sardana/macroserver/macros/hkl.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py index aec6f43a2b..50f6cc8a8a 100644 --- a/src/sardana/macroserver/macros/hkl.py +++ b/src/sardana/macroserver/macros/hkl.py @@ -1,3 +1,25 @@ +############################################################################## +## +# This file is part of Sardana +## +# http://www.sardana-controls.org/ +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Sardana 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. +## +# Sardana 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 Sardana. If not, see . +## +############################################################################## """ Macro library containning diffractometer related macros for the macros @@ -13,7 +35,7 @@ # using getDevice. However this getter seems to accept only the elements names # and not the full names. -__all__ = ["addreflexion", "affine", "br", "ca", "caa", "ci", "computeub", +__all__ = ["addreflection", "affine", "br", "ca", "caa", "ci", "computeub", "freeze", "getmode", "hklscan", "hscan", "kscan", "latticecal", "loadcrystal", "lscan", "newcrystal", "or0", "or1", "orswap", "pa", "savecrystal", "setaz", "setlat", "setmode", "setor0", From 950a1dfd6312384f66fe4fdc4fba29e7a2d6441c Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 4 Feb 2019 15:20:58 +0100 Subject: [PATCH 584/652] Bump version 2.6.0 to 2.6.1-alpha --- .bumpversion.cfg | 2 +- src/sardana/release.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 7c79737971..18e4f93312 100755 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ commit = True message = Bump version {current_version} to {new_version} tag = False tag_name = {new_version} -current_version = 2.6.0 +current_version = 2.6.1-alpha parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} diff --git a/src/sardana/release.py b/src/sardana/release.py index 566593c88d..20e34fa8af 100644 --- a/src/sardana/release.py +++ b/src/sardana/release.py @@ -47,7 +47,7 @@ # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '2.6.0' +version = '2.6.1-alpha' # generate version_info and revision (**deprecated** since v 2.1.2--alpha). if '-' in version: From a2823a4ff8c9929e46ac887dd560f46b71012e9a Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 4 Feb 2019 15:20:59 +0100 Subject: [PATCH 585/652] Bump version 2.6.1-alpha to 2.6.1 --- .bumpversion.cfg | 2 +- src/sardana/release.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 18e4f93312..c362a0c235 100755 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ commit = True message = Bump version {current_version} to {new_version} tag = False tag_name = {new_version} -current_version = 2.6.1-alpha +current_version = 2.6.1 parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} diff --git a/src/sardana/release.py b/src/sardana/release.py index 20e34fa8af..f2804659d5 100644 --- a/src/sardana/release.py +++ b/src/sardana/release.py @@ -47,7 +47,7 @@ # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '2.6.1-alpha' +version = '2.6.1' # generate version_info and revision (**deprecated** since v 2.1.2--alpha). if '-' in version: From 6756b7deb32dace8f1564cbfdbebf73640c19e44 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 4 Feb 2019 15:26:08 +0100 Subject: [PATCH 586/652] Bump version numbers in manpages --- doc/man/MacroServer.1 | 4 ++-- doc/man/Pool.1 | 4 ++-- doc/man/Sardana.1 | 4 ++-- doc/man/diffractometeralignment.1 | 4 ++-- doc/man/hklscan.1 | 4 ++-- doc/man/macroexecutor.1 | 4 ++-- doc/man/sardanatestsuite.1 | 4 ++-- doc/man/sequencer.1 | 4 ++-- doc/man/spock.1 | 10 +++++----- doc/man/ubmatrix.1 | 4 ++-- 10 files changed, 23 insertions(+), 23 deletions(-) mode change 100644 => 100755 doc/man/spock.1 diff --git a/doc/man/MacroServer.1 b/doc/man/MacroServer.1 index 1c5a666807..c2d22cfb81 100755 --- a/doc/man/MacroServer.1 +++ b/doc/man/MacroServer.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH MACROSERVER "1" "January 2019" "MacroServer 2.6.0" "User Commands" +.TH MACROSERVER "1" "February 2019" "MacroServer 2.6.1" "User Commands" .SH NAME -MacroServer \- manual page for MacroServer 2.6.0 +MacroServer \- manual page for MacroServer 2.6.1 .SH SYNOPSIS .B usage: \fI\,MacroServer instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/Pool.1 b/doc/man/Pool.1 index 6907c255a0..1ba8241fdf 100755 --- a/doc/man/Pool.1 +++ b/doc/man/Pool.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH POOL "1" "January 2019" "Pool 2.6.0" "User Commands" +.TH POOL "1" "February 2019" "Pool 2.6.1" "User Commands" .SH NAME -Pool \- manual page for Pool 2.6.0 +Pool \- manual page for Pool 2.6.1 .SH SYNOPSIS .B usage: \fI\,Pool instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/Sardana.1 b/doc/man/Sardana.1 index a596bb21b0..f540e0ca3a 100755 --- a/doc/man/Sardana.1 +++ b/doc/man/Sardana.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SARDANA "1" "January 2019" "Sardana 2.6.0" "User Commands" +.TH SARDANA "1" "February 2019" "Sardana 2.6.1" "User Commands" .SH NAME -Sardana \- manual page for Sardana 2.6.0 +Sardana \- manual page for Sardana 2.6.1 .SH SYNOPSIS .B usage: \fI\,Sardana instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/diffractometeralignment.1 b/doc/man/diffractometeralignment.1 index 21fcdda97a..439a52fd7a 100755 --- a/doc/man/diffractometeralignment.1 +++ b/doc/man/diffractometeralignment.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH DIFFRACTOMETERALIGNMENT "1" "January 2019" "diffractometeralignment 2.6.0" "User Commands" +.TH DIFFRACTOMETERALIGNMENT "1" "February 2019" "diffractometeralignment 2.6.1" "User Commands" .SH NAME -diffractometeralignment \- manual page for diffractometeralignment 2.6.0 +diffractometeralignment \- manual page for diffractometeralignment 2.6.1 .SH SYNOPSIS .B diffractometeralignment \fI\, \/\fR[\fI\,door_name\/\fR] diff --git a/doc/man/hklscan.1 b/doc/man/hklscan.1 index 5f51d57c05..dd019a39eb 100755 --- a/doc/man/hklscan.1 +++ b/doc/man/hklscan.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH HKLSCAN "1" "January 2019" "hklscan 2.6.0" "User Commands" +.TH HKLSCAN "1" "February 2019" "hklscan 2.6.1" "User Commands" .SH NAME -hklscan \- manual page for hklscan 2.6.0 +hklscan \- manual page for hklscan 2.6.1 .SH SYNOPSIS .B hklscan \fI\, \/\fR[\fI\,door_name\/\fR] diff --git a/doc/man/macroexecutor.1 b/doc/man/macroexecutor.1 index 893df12dd2..b81b8d70c6 100755 --- a/doc/man/macroexecutor.1 +++ b/doc/man/macroexecutor.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH MACROEXECUTOR "1" "January 2019" "macroexecutor 2.6.0" "User Commands" +.TH MACROEXECUTOR "1" "February 2019" "macroexecutor 2.6.1" "User Commands" .SH NAME -macroexecutor \- manual page for macroexecutor 2.6.0 +macroexecutor \- manual page for macroexecutor 2.6.1 .SH SYNOPSIS .B macroexecutor [\fI\,options\/\fR] diff --git a/doc/man/sardanatestsuite.1 b/doc/man/sardanatestsuite.1 index da6a46657f..5e202cf342 100755 --- a/doc/man/sardanatestsuite.1 +++ b/doc/man/sardanatestsuite.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SARDANATESTSUITE "1" "January 2019" "sardanatestsuite 2.6.0" "User Commands" +.TH SARDANATESTSUITE "1" "February 2019" "sardanatestsuite 2.6.1" "User Commands" .SH NAME -sardanatestsuite \- manual page for sardanatestsuite 2.6.0 +sardanatestsuite \- manual page for sardanatestsuite 2.6.1 .SH DESCRIPTION usage: sardanatestsuite [\-h] [\-e EXCLUDE_PATTERN] [\-\-version] .PP diff --git a/doc/man/sequencer.1 b/doc/man/sequencer.1 index ca582e0a75..026957801f 100755 --- a/doc/man/sequencer.1 +++ b/doc/man/sequencer.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SEQUENCER "1" "January 2019" "sequencer 2.6.0" "User Commands" +.TH SEQUENCER "1" "February 2019" "sequencer 2.6.1" "User Commands" .SH NAME -sequencer \- manual page for sequencer 2.6.0 +sequencer \- manual page for sequencer 2.6.1 .SH SYNOPSIS .B sequencer [\fI\,options\/\fR] diff --git a/doc/man/spock.1 b/doc/man/spock.1 old mode 100644 new mode 100755 index dbb42e9555..f0966bceba --- a/doc/man/spock.1 +++ b/doc/man/spock.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH SPOCK "1" "August 2018" "spock 2.6.0" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. +.TH SPOCK "1" "February 2019" "spock 2.6.1" "User Commands" .SH NAME -spock \- manual page for spock 2.6.0 +spock \- manual page for spock 2.6.1 .SH DESCRIPTION ========= .IP @@ -248,14 +248,14 @@ The IPython profile to use. \fB\-\-pylab=\fR (InteractiveShellApp.pylab) .IP Default: None -Choices: [u'auto', u'agg', u'gtk', u'gtk3', u'inline', u'ipympl', u'nbagg', u'notebook', u'osx', u'pdf', u'ps', u'qt', u'qt4', u'qt5', u'svg', u'tk', u'widget', u'wx'] +Choices: [u'auto', u'gtk', u'gtk3', u'inline', u'nbagg', u'notebook', u'osx', u'qt', u'qt4', u'qt5', u'tk', u'wx'] Pre\-load matplotlib and numpy for interactive use, selecting a particular matplotlib backend and loop integration. .PP \fB\-\-matplotlib=\fR (InteractiveShellApp.matplotlib) .IP Default: None -Choices: [u'auto', u'agg', u'gtk', u'gtk3', u'inline', u'ipympl', u'nbagg', u'notebook', u'osx', u'pdf', u'ps', u'qt', u'qt4', u'qt5', u'svg', u'tk', u'widget', u'wx'] +Choices: [u'auto', u'gtk', u'gtk3', u'inline', u'nbagg', u'notebook', u'osx', u'qt', u'qt4', u'qt5', u'tk', u'wx'] Configure matplotlib for interactive use with the default matplotlib backend. .PP diff --git a/doc/man/ubmatrix.1 b/doc/man/ubmatrix.1 index 761f6c98f4..b4af81bcd3 100755 --- a/doc/man/ubmatrix.1 +++ b/doc/man/ubmatrix.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH UBMATRIX "1" "January 2019" "ubmatrix 2.6.0" "User Commands" +.TH UBMATRIX "1" "February 2019" "ubmatrix 2.6.1" "User Commands" .SH NAME -ubmatrix \- manual page for ubmatrix 2.6.0 +ubmatrix \- manual page for ubmatrix 2.6.1 .SH SYNOPSIS .B ubmatrix \fI\,\/\fR From 6206a9042b59a156bec214bd65c6eb6d62aa373d Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 4 Feb 2019 15:34:20 +0100 Subject: [PATCH 587/652] Add 2.6.1 release to CHANGELOG --- CHANGELOG.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98e36e488b..7c0cb0fe09 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ This file follows the formats and conventions from [keepachangelog.com] ### Added +## [2.6.1] 2019-02-04 + +### Fixed +- String parameter editor in macroexecutor and sequencer (#1030, #1031) +- Documentation on differences between `Hookable.hooks` and `Hookable.appendHook` + (#962, #1013) + ## [2.6.0] 2019-01-31 ### Added @@ -24,7 +31,7 @@ This file follows the formats and conventions from [keepachangelog.com] - `SoftwareStart` and `HardwareStart` synchronization in `DummyCounterTimerController` - Support to Qt5 for Sardana-Taurus widgets and Sardana-Taurus extensions (#1006, - #1009, #1031) + #1009) - Possibility to define macros with optional parameters. These must be the last ones in the definition (#285, #876, #943, #941, #955) - Possibility to pass values of repeat paramters with just one member without @@ -41,8 +48,6 @@ This file follows the formats and conventions from [keepachangelog.com] - Document remote connection to MacroServer Python process (RConsolePort Tango property) (#984) - sardana.taurus.qt.qtgui.macrolistener (moved from taurus.qt.qtgui.taurusgui) -- Documentation on differences between `Hookable.hooks` and `Hookable.appendHook` - (#962, #1013) ### Fixed - Do not read 1D and 2D experimental channels during software acquisition loop @@ -558,7 +563,8 @@ Main improvements since sardana 1.5.0 (aka Jan15): [keepachangelog.com]: http://keepachangelog.com -[Unreleased]: https://github.com/sardana-org/sardana/compare/2.6.0...HEAD +[Unreleased]: https://github.com/sardana-org/sardana/compare/2.6.1...HEAD +[2.6.1]: https://github.com/sardana-org/sardana/compare/2.6.0...2.6.1 [2.6.0]: https://github.com/sardana-org/sardana/compare/2.5.0...2.6.0 [2.5.0]: https://github.com/sardana-org/sardana/compare/2.4.0...2.5.0 [2.4.0]: https://github.com/sardana-org/sardana/compare/2.3.2...2.4.0 From 1928a5d8fb6c3102f0141c0570d73a1e9fac5892 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 4 Feb 2019 16:13:38 +0100 Subject: [PATCH 588/652] Fix flake8 --- src/sardana/macroserver/macros/hkl.py | 34 +++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) mode change 100644 => 100755 src/sardana/macroserver/macros/hkl.py diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py old mode 100644 new mode 100755 index 50f6cc8a8a..4dbfc4527f --- a/src/sardana/macroserver/macros/hkl.py +++ b/src/sardana/macroserver/macros/hkl.py @@ -47,7 +47,7 @@ import re import numpy as np -from sardana.macroserver.macro import * +from sardana.macroserver.macro import Macro, iMacro, Type from sardana.macroserver.macros.scan import aNscan from sardana.macroserver.msexception import UnknownEnv @@ -111,7 +111,8 @@ def prepare(self): 'Chi': "chi", 'Phi': "phi", 'Tth': "tth"} elif self.nb_motors == 6: self.labelmotor = {'Mu': "mu", 'Theta': "omega", 'Chi': "chi", - 'Phi': "phi", 'Gamma': "gamma", 'Delta': "delta"} + 'Phi': "phi", 'Gamma': "gamma", + 'Delta': "delta"} prop = self.diffrac.get_property(['DiffractometerType']) for v in prop['DiffractometerType']: @@ -441,7 +442,9 @@ def run(self, mu, theta, chi, phi, gamma, delta, omega_t): if delta == -999 and self.nb_motors == 6: self.error("Six angle values are need as argument") elif omega_t == -999 and self.nb_motors == 7: - self.error("Seven angle values are need as argument (omega_t is missed - last argument)") + msg = ("Seven angle values are need as argument (omega_t is " + "missed - last argument)") + self.error(msg) else: if self.nb_motors != 7: angles = [mu, theta, chi, phi, gamma, delta] @@ -989,19 +992,22 @@ class setorn(iMacro, _diffrac): ['ang7', Type.Float, -999, "Real position"], ] - def prepare(self, ref_id, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7): + def prepare(self, ref_id, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, + ang7): _diffrac.prepare(self) def run(self, ref_id, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7): if H == -999.0: - self.output("Order of the real motor positions to be given as argument:") + msg = "Order of the real motor positions to be given as argument:" + self.output(msg) for el in self.angle_names: self.output(el) return - - if (ang6 == -999 and self.nb_motors == 6) or ( - ang4 == -999 and self.nb_motors == 4) or (ang7 == -999 and self.nb_motors == 7): + + if ((ang6 == -999 and self.nb_motors == 6) + or (ang4 == -999 and self.nb_motors == 4) + or (ang7 == -999 and self.nb_motors == 7)): reflections = [] try: reflections = self.diffrac.reflectionlist @@ -1038,8 +1044,12 @@ def run(self, ref_id, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7): self.output("Enter %s angles" % ref_txt) angles_to_set = [] for el in self.angle_names: - angles_to_set.append(float(self.input(el+"?", default_value=tmp_ref[ - el], data_type=Type.String))) + angles_to_set.append( + float(self.input(el+"?", + default_value=tmp_ref[el], + data_type=Type.String) + ) + ) self.output("") @@ -1051,12 +1061,12 @@ def run(self, ref_id, H, K, L, ang1, ang2, ang3, ang4, ang5, ang6, ang7): L = float(self.input(" L?", default_value=tmp_ref[ "l"], data_type=Type.String)) self.output("") - else: + else: angles = [ang1, ang2, ang3, ang4, ang5, ang6, ang7] angles_to_set = [] for i in range(0, self.nb_motors): angles_to_set.append(angles[i]) - + # Check collinearity if ref_id == 0: From 1a9cde696e84d2827fe632ad601d21316397edaa Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 4 Feb 2019 17:02:03 +0100 Subject: [PATCH 589/652] Fix flake8 --- src/sardana/pool/controller.py | 4 +- src/sardana/pool/poolbasechannel.py | 65 ++++++++++--------- .../DummyCounterTimerController.py | 2 +- src/sardana/pool/poolcountertimer.py | 1 - src/sardana/tango/pool/CTExpChannel.py | 6 +- src/sardana/tango/pool/PoolDevice.py | 15 +++-- src/sardana/tango/pool/TwoDExpChannel.py | 1 + 7 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index 314c5de4af..35c4d9d511 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -298,7 +298,7 @@ class Controller(object): #: A :obj:`str` containning the path to the image logo file logo = None - + def __init__(self, inst, props, *args, **kwargs): self._inst_name = inst self._log = Logger("Controller.%s" % inst) @@ -662,7 +662,7 @@ class Loadable(object): .. note: Do not inherit directly from Loadable.""" default_timer = None - + def PrepareOne(self, axis, value, repetitions, latency, nb_starts): """**Controller API**. Override if necessary. Called to prepare the master channel axis with the measurement diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 93882e7c0f..7a7ba66f47 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -33,8 +33,10 @@ from sardana.sardanaattribute import SardanaAttribute from sardana.sardanabuffer import SardanaBuffer from sardana.pool.poolelement import PoolElement -from sardana.pool.poolacquisition import PoolAcquisitionSoftware, get_timerable_ctrls, AcqController -from sardana.pool.poolmeasurementgroup import TimerableControllerConfiguration, ChannelConfiguration, ControllerConfiguration +from sardana.pool.poolacquisition import PoolAcquisitionSoftware,\ + get_timerable_ctrls +from sardana.pool.poolmeasurementgroup import ChannelConfiguration,\ + ControllerConfiguration from sardana.sardanaevent import EventType from sardana.pool import AcqSynch, AcqMode @@ -260,8 +262,8 @@ def set_integration_time(self, integration_time, propagate=1): integration_time) integration_time = property(get_integration_time, set_integration_time, - doc="channel integration time") - + doc="channel integration time") + def extend_value_buffer(self, values, idx=None, propagate=1): """Extend value buffer with new values assigning them consecutive indexes starting with idx. If idx is omitted, then the new values will @@ -319,17 +321,19 @@ def start_acquisition(self): if self._timer is not None: if self.ctrls is None: self.create_config() - acq = self.acquisition.run(self.ctrls, self.integration_time, self.master, None) + self.acquisition.run(self.ctrls, + self.integration_time, + self.master, + None) def create_config(self): - if self._timer is None: return - + ctrl = self.get_controller() ctrl.set_ctrl_par("synchronization", AcqSynch.SoftwareTrigger) - + self.conf_ctrl = ControllerConfiguration(ctrl) # self has to be used. If not it is removed self.conf_channel = ChannelConfiguration(self) @@ -339,24 +343,27 @@ def create_config(self): self.conf_ctrl.timer = channel else: if self.timer == "__default": - self.conf_timer = ChannelConfiguration(ctrl.get_element(axis=ctrl.ctrl.default_timer)) - else: - self.conf_timer = ChannelConfiguration(self.pool.get_element_by_name(self.timer)) + self.conf_timer = ChannelConfiguration( + ctrl.get_element(axis=ctrl.ctrl.default_timer)) + else: + self.conf_timer = ChannelConfiguration( + self.pool.get_element_by_name(self.timer)) self.conf_ctrl.add_channel(self.conf_timer) ctimer = self.conf_ctrl.get_channels(enabled=True)[1] self.conf_ctrl.timer = ctimer - + self.conf_ctrl.monitor = channel self.ctrls = get_timerable_ctrls([self.conf_ctrl], AcqMode.Timer) self.master = self.ctrls[0].master - comp_self = "__self" if self.timer != "__self": if self.timer == "__default": - self.acquisition.add_element(ctrl.get_element(axis=ctrl.ctrl.default_timer)) + self.acquisition.add_element( + ctrl.get_element(axis=ctrl.ctrl.default_timer)) else: - self.acquisition.add_element(self.pool.get_element_by_name(self.timer)) + self.acquisition.add_element( + self.pool.get_element_by_name(self.timer)) + - class PoolTimerableChannel(PoolBaseChannel): def __init__(self, **kwargs): @@ -378,7 +385,7 @@ def get_timer(self, cache=True, propagate=1): return self._timer def set_timer(self, timer, propagate=1): - + if timer == self._timer: # timer is not changed. Do nothing return @@ -387,34 +394,32 @@ def set_timer(self, timer, propagate=1): try: ctrl = self.get_controller() self.default_timer_axis = ctrl.ctrl.default_timer - except: + except Exception: raise ValueError("Error reading default_timer") return - if self.default_timer_axis == None: + if self.default_timer_axis is None: raise ValueError("default_timer not defined in controller") - + if timer is not None and timer != "__self": try: if timer != "__default": - self.acquisition.remove_element(self.pool.get_element_by_name(timer)) + self.acquisition.remove_element( + self.pool.get_element_by_name(timer)) else: - self.acquisition.remove_element(ctrl.get_element(axis = self.default_timer_axis)) - except: # The new timer does not belong to action + self.acquisition.remove_element( + ctrl.get_element(axis=self.default_timer_axis)) + except Exception: # The new timer does not belong to action pass - self._timer = timer - self.create_config() - + if not propagate: return if timer is None: timer = 'None' - - self.fire_event(EventType("timer", priority=propagate), - timer) + self.fire_event(EventType("timer", priority=propagate), timer) timer = property(get_timer, set_timer, - doc="timer for the timerable channel") + doc="timer for the timerable channel") diff --git a/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py b/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py index 4fbb1e33ab..036aa7558c 100644 --- a/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py +++ b/src/sardana/pool/poolcontrollers/DummyCounterTimerController.py @@ -66,7 +66,7 @@ class DummyCounterTimerController(CounterTimerController): CounterMode = 3 default_timer = 1 - + def __init__(self, inst, props, *args, **kwargs): CounterTimerController.__init__(self, inst, props, *args, **kwargs) self._synchronization = AcqSynch.SoftwareTrigger diff --git a/src/sardana/pool/poolcountertimer.py b/src/sardana/pool/poolcountertimer.py index c73b53f7bb..02ae46972f 100644 --- a/src/sardana/pool/poolcountertimer.py +++ b/src/sardana/pool/poolcountertimer.py @@ -59,4 +59,3 @@ def set_write_value(self, w_value, timestamp=None, propagate=1): int""" self._value.set_write_value(w_value, timestamp=timestamp, propagate=propagate) - diff --git a/src/sardana/tango/pool/CTExpChannel.py b/src/sardana/tango/pool/CTExpChannel.py index 18d8bb5002..dca52172e8 100644 --- a/src/sardana/tango/pool/CTExpChannel.py +++ b/src/sardana/tango/pool/CTExpChannel.py @@ -214,7 +214,7 @@ def is_Value_allowed(self, req_type): if self.get_state() in [DevState.FAULT, DevState.UNKNOWN]: return False return True - + def Start(self): self.ct.start_acquisition() @@ -237,12 +237,12 @@ class CTExpChannelClass(PoolTimerableDeviceClass): # Attribute definitions attr_list = {} attr_list.update(PoolTimerableDeviceClass.attr_list) - + standard_attr_list = { 'Value': [[DevDouble, SCALAR, READ], {'abs_change': '1.0', }] } - + standard_attr_list.update(PoolTimerableDeviceClass.standard_attr_list) def _get_class_properties(self): diff --git a/src/sardana/tango/pool/PoolDevice.py b/src/sardana/tango/pool/PoolDevice.py index 04c9eb0538..86edae222f 100644 --- a/src/sardana/tango/pool/PoolDevice.py +++ b/src/sardana/tango/pool/PoolDevice.py @@ -35,8 +35,8 @@ import time import numpy as np -from PyTango import Util, DevVoid, DevLong64, DevBoolean, DevString, DevDouble, \ - DevVarStringArray, DispLevel, DevState, SCALAR, SPECTRUM, \ +from PyTango import Util, DevVoid, DevLong64, DevBoolean, DevString,\ + DevDouble, DevVarStringArray, DispLevel, DevState, SCALAR, SPECTRUM, \ IMAGE, READ_WRITE, READ, AttrData, CmdArgType, DevFailed, seqStr_2_obj, \ Except, ErrSeverity @@ -873,7 +873,7 @@ def read_Data(self, attr): desc, "PoolExpChannelDevice.read_Data", ErrSeverity.WARN) - + def read_IntegrationTime(self, attr): """Reads the integration time. @@ -900,19 +900,19 @@ class PoolExpChannelDeviceClass(PoolElementDeviceClass): 'IntegrationTime': [[DevDouble, SCALAR, READ_WRITE]] } attr_list.update(PoolElementDeviceClass.attr_list) - + standard_attr_list = { 'Data': [[DevString, SCALAR, READ]], # TODO: think about DevEncoded } standard_attr_list.update(PoolElementDeviceClass.standard_attr_list) + class PoolTimerableDevice(PoolExpChannelDevice): def __init__(self, dclass, name): """Constructor""" PoolExpChannelDevice.__init__(self, dclass, name) - def read_Timer(self, attr): """Reads the timer for this channel. @@ -933,6 +933,7 @@ def write_Timer(self, attr): timer = None self.element.timer = timer + class PoolTimerableDeviceClass(PoolExpChannelDeviceClass): #: @@ -940,13 +941,13 @@ class PoolTimerableDeviceClass(PoolExpChannelDeviceClass): #: #: .. seealso:: :ref:`server` #: - + # Attribute definitions attr_list = { 'Timer': [[DevString, SCALAR, READ_WRITE], {'Memorized': "true", }] } attr_list.update(PoolExpChannelDeviceClass.attr_list) - + standard_attr_list = {} standard_attr_list.update(PoolExpChannelDeviceClass.standard_attr_list) diff --git a/src/sardana/tango/pool/TwoDExpChannel.py b/src/sardana/tango/pool/TwoDExpChannel.py index abda6f4296..634e835a30 100644 --- a/src/sardana/tango/pool/TwoDExpChannel.py +++ b/src/sardana/tango/pool/TwoDExpChannel.py @@ -45,6 +45,7 @@ from sardana.tango.pool.PoolDevice import PoolTimerableDevice, \ PoolTimerableDeviceClass + class TwoDExpChannel(PoolTimerableDevice): def __init__(self, dclass, name): From 25fc5402f3c9a301625e5155c1aa5562ecda8169 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 4 Feb 2019 17:47:23 +0100 Subject: [PATCH 590/652] Remove unused args of integration_time and timer getters --- src/sardana/pool/poolbasechannel.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 7a7ba66f47..431542bee3 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -240,15 +240,11 @@ def _set_value(self, value): # integration time # -------------------------------------------------------------------------- - def get_integration_time(self, cache=True, propagate=1): + def get_integration_time(self): """Returns the integration time for this object. - :param cache: not used [default: True] - :type cache: bool - :param propagate: [default: 1] - :type propagate: int :return: the current integration time - :rtype: bool""" + :rtype: :ob:`float`""" return self._integration_time def set_integration_time(self, integration_time, propagate=1): @@ -373,15 +369,11 @@ def __init__(self, **kwargs): # timer # ------------------------------------------------------------------------- - def get_timer(self, cache=True, propagate=1): + def get_timer(self): """Returns the timer for this object. - :param cache: not used [default: True] - :type cache: bool - :param propagate: [default: 1] - :type propagate: int :return: the current timer - :rtype: bool""" + :rtype: :obj:`str`""" return self._timer def set_timer(self, timer, propagate=1): From 53052dcb7e6e714075507c953e0fac7d798f99a5 Mon Sep 17 00:00:00 2001 From: zreszela Date: Mon, 4 Feb 2019 18:08:13 +0100 Subject: [PATCH 591/652] Move integration_time implementation (cosmetic) In order to not split code related to value and value buffer move the newly added integration_time attribute around. --- src/sardana/pool/poolbasechannel.py | 48 ++++++++++++++--------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 431542bee3..0d32e5a857 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -236,30 +236,6 @@ def _set_value(self, value): value = property(get_value, set_value, doc="channel value") - # -------------------------------------------------------------------------- - # integration time - # -------------------------------------------------------------------------- - - def get_integration_time(self): - """Returns the integration time for this object. - - :return: the current integration time - :rtype: :ob:`float`""" - return self._integration_time - - def set_integration_time(self, integration_time, propagate=1): - if integration_time == self._integration_time: - # integration time is not changed. Do nothing - return - self._integration_time = integration_time - if not propagate: - return - self.fire_event(EventType("integration_time", priority=propagate), - integration_time) - - integration_time = property(get_integration_time, set_integration_time, - doc="channel integration time") - def extend_value_buffer(self, values, idx=None, propagate=1): """Extend value buffer with new values assigning them consecutive indexes starting with idx. If idx is omitted, then the new values will @@ -310,6 +286,30 @@ def clear_value_buffer(self): val_attr = self._value_buffer val_attr.clear() + # -------------------------------------------------------------------------- + # integration time + # -------------------------------------------------------------------------- + + def get_integration_time(self): + """Returns the integration time for this object. + + :return: the current integration time + :rtype: :ob:`float`""" + return self._integration_time + + def set_integration_time(self, integration_time, propagate=1): + if integration_time == self._integration_time: + # integration time is not changed. Do nothing + return + self._integration_time = integration_time + if not propagate: + return + self.fire_event(EventType("integration_time", priority=propagate), + integration_time) + + integration_time = property(get_integration_time, set_integration_time, + doc="channel integration time") + def start_acquisition(self): self._aborted = False self._stopped = False From b95c6bfecc036673fd26d53ca8312f2d6af5e801 Mon Sep 17 00:00:00 2001 From: teresa Date: Tue, 5 Feb 2019 09:44:20 +0100 Subject: [PATCH 592/652] Adding hkl macro changes in CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bddbfeace..cf8ae175f6 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,7 @@ This file follows the formats and conventions from [keepachangelog.com] #1009) - Possibility to define macros with optional parameters. These must be the last ones in the definition (#285, #876, #943, #941, #955) -- Possibility to pass values of repeat paramters with just one member without +- Possibility to pass values of repeat parameters with just one member without the need to encapsulate them in square brackets (spock syntax) or list (macro API) (#781, #983) - Possibility to change data format (shape) of of pseudo counter values (#986) @@ -62,6 +62,8 @@ This file follows the formats and conventions from [keepachangelog.com] - Spock considers passing supernumerary parameters as errors (#438, #781) - MacroServer starts without the Qt library installed (#781, #907, #908) - Make `Description` an optional part of controller's properties definition (#976) +- Correcting bug in hkl macros introduced when extending macros for new + diffractometer types: angle order was switched ### Changed - MacroButton stops macros instead of aborting them (#931, #943) From bfcd44ec9f762b30df9dea099676d44a64933f12 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 5 Feb 2019 10:42:22 +0100 Subject: [PATCH 593/652] Change permissions to 644 --- doc/man/MacroServer.1 | 0 doc/man/Pool.1 | 0 doc/man/Sardana.1 | 0 doc/man/diffractometeralignment.1 | 0 doc/man/hklscan.1 | 0 doc/man/macroexecutor.1 | 0 doc/man/sardanatestsuite.1 | 0 doc/man/sequencer.1 | 0 doc/man/spock.1 | 0 doc/man/ubmatrix.1 | 0 doc/source/_static/macrobutton.png | Bin doc/source/_static/macrobutton_abort.png | Bin .../sardana/macroserver/macros/communication.rst | 0 .../devel/api/sardana/macroserver/macros/demo.rst | 0 .../devel/api/sardana/macroserver/macros/env.rst | 0 .../devel/api/sardana/macroserver/macros/expert.rst | 0 .../devel/api/sardana/macroserver/macros/hkl.rst | 0 .../api/sardana/macroserver/macros/ioregister.rst | 0 .../devel/api/sardana/macroserver/macros/lists.rst | 0 .../devel/api/sardana/macroserver/macros/mca.rst | 0 .../devel/api/sardana/macroserver/macros/scan.rst | 0 .../api/sardana/macroserver/macros/sequence.rst | 0 .../api/sardana/macroserver/macros/standard.rst | 0 .../devel/api/sardana/pool/poolsynchronization.rst | 0 doc/source/sep/res/sep0_workflow.png | Bin doc/source/sep/res/sep6_motion.bmp | Bin doc/source/users/spock.rst | 0 doc/source/users/taurus/macrobutton.rst | 0 src/sardana/macroserver/macros/discrete.py | 0 src/sardana/macroserver/macros/examples/motion.py | 0 src/sardana/macroserver/macros/hkl.py | 0 src/sardana/macroserver/scan/gscan.py | 0 src/sardana/macroserver/scan/test/test_gscan.py | 0 src/sardana/macroserver/test/__init__.py | 0 src/sardana/macroserver/test/res/__init__.py | 0 src/sardana/macroserver/test/res/fakerecorders.py | 0 .../test/res/recorders/path1/fakerecorders.py | 0 .../test/res/recorders/path2/fakerecorders.py | 0 .../test/res/recorders/path3/fakerecorders.py | 0 .../macroserver/test/test_msrecordermanager.py | 0 src/sardana/pool/poolacquisition.py | 0 .../pool/poolcontrollers/TaurusController.py | 0 src/sardana/pool/test/fake.py | 0 src/sardana/sardanamodulemanager.py | 0 src/sardana/spock/spockms.py | 0 src/sardana/tango/macroserver/test/base.py | 0 src/sardana/taurus/core/tango/sardana/macro.py | 0 .../taurus/core/tango/sardana/macroserver.py | 0 .../taurus/core/tango/sardana/test/__init__.py | 0 .../taurus/core/tango/sardana/test/paramdef.py | 0 .../taurus/core/tango/sardana/test/test_macro.py | 0 .../qt/qtgui/extra_macroexecutor/macrobutton.py | 0 .../sequenceeditor/sequenceeditor.py | 0 .../taurus/qt/qtgui/extra_sardana/expdescription.py | 0 .../taurus/qt/qtgui/extra_sardana/sardanaeditor.py | 0 .../taurus/qt/qtgui/macrolistener/__init__.py | 0 56 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 doc/man/MacroServer.1 mode change 100755 => 100644 doc/man/Pool.1 mode change 100755 => 100644 doc/man/Sardana.1 mode change 100755 => 100644 doc/man/diffractometeralignment.1 mode change 100755 => 100644 doc/man/hklscan.1 mode change 100755 => 100644 doc/man/macroexecutor.1 mode change 100755 => 100644 doc/man/sardanatestsuite.1 mode change 100755 => 100644 doc/man/sequencer.1 mode change 100755 => 100644 doc/man/spock.1 mode change 100755 => 100644 doc/man/ubmatrix.1 mode change 100755 => 100644 doc/source/_static/macrobutton.png mode change 100755 => 100644 doc/source/_static/macrobutton_abort.png mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/communication.rst mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/demo.rst mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/env.rst mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/expert.rst mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/hkl.rst mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/ioregister.rst mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/lists.rst mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/mca.rst mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/scan.rst mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/sequence.rst mode change 100755 => 100644 doc/source/devel/api/sardana/macroserver/macros/standard.rst mode change 100755 => 100644 doc/source/devel/api/sardana/pool/poolsynchronization.rst mode change 100755 => 100644 doc/source/sep/res/sep0_workflow.png mode change 100755 => 100644 doc/source/sep/res/sep6_motion.bmp mode change 100755 => 100644 doc/source/users/spock.rst mode change 100755 => 100644 doc/source/users/taurus/macrobutton.rst mode change 100755 => 100644 src/sardana/macroserver/macros/discrete.py mode change 100755 => 100644 src/sardana/macroserver/macros/examples/motion.py mode change 100755 => 100644 src/sardana/macroserver/macros/hkl.py mode change 100755 => 100644 src/sardana/macroserver/scan/gscan.py mode change 100755 => 100644 src/sardana/macroserver/scan/test/test_gscan.py mode change 100755 => 100644 src/sardana/macroserver/test/__init__.py mode change 100755 => 100644 src/sardana/macroserver/test/res/__init__.py mode change 100755 => 100644 src/sardana/macroserver/test/res/fakerecorders.py mode change 100755 => 100644 src/sardana/macroserver/test/res/recorders/path1/fakerecorders.py mode change 100755 => 100644 src/sardana/macroserver/test/res/recorders/path2/fakerecorders.py mode change 100755 => 100644 src/sardana/macroserver/test/res/recorders/path3/fakerecorders.py mode change 100755 => 100644 src/sardana/macroserver/test/test_msrecordermanager.py mode change 100755 => 100644 src/sardana/pool/poolacquisition.py mode change 100755 => 100644 src/sardana/pool/poolcontrollers/TaurusController.py mode change 100755 => 100644 src/sardana/pool/test/fake.py mode change 100755 => 100644 src/sardana/sardanamodulemanager.py mode change 100755 => 100644 src/sardana/spock/spockms.py mode change 100755 => 100644 src/sardana/tango/macroserver/test/base.py mode change 100755 => 100644 src/sardana/taurus/core/tango/sardana/macro.py mode change 100755 => 100644 src/sardana/taurus/core/tango/sardana/macroserver.py mode change 100755 => 100644 src/sardana/taurus/core/tango/sardana/test/__init__.py mode change 100755 => 100644 src/sardana/taurus/core/tango/sardana/test/paramdef.py mode change 100755 => 100644 src/sardana/taurus/core/tango/sardana/test/test_macro.py mode change 100755 => 100644 src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py mode change 100755 => 100644 src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py mode change 100755 => 100644 src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py mode change 100755 => 100644 src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py mode change 100755 => 100644 src/sardana/taurus/qt/qtgui/macrolistener/__init__.py diff --git a/doc/man/MacroServer.1 b/doc/man/MacroServer.1 old mode 100755 new mode 100644 diff --git a/doc/man/Pool.1 b/doc/man/Pool.1 old mode 100755 new mode 100644 diff --git a/doc/man/Sardana.1 b/doc/man/Sardana.1 old mode 100755 new mode 100644 diff --git a/doc/man/diffractometeralignment.1 b/doc/man/diffractometeralignment.1 old mode 100755 new mode 100644 diff --git a/doc/man/hklscan.1 b/doc/man/hklscan.1 old mode 100755 new mode 100644 diff --git a/doc/man/macroexecutor.1 b/doc/man/macroexecutor.1 old mode 100755 new mode 100644 diff --git a/doc/man/sardanatestsuite.1 b/doc/man/sardanatestsuite.1 old mode 100755 new mode 100644 diff --git a/doc/man/sequencer.1 b/doc/man/sequencer.1 old mode 100755 new mode 100644 diff --git a/doc/man/spock.1 b/doc/man/spock.1 old mode 100755 new mode 100644 diff --git a/doc/man/ubmatrix.1 b/doc/man/ubmatrix.1 old mode 100755 new mode 100644 diff --git a/doc/source/_static/macrobutton.png b/doc/source/_static/macrobutton.png old mode 100755 new mode 100644 diff --git a/doc/source/_static/macrobutton_abort.png b/doc/source/_static/macrobutton_abort.png old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/communication.rst b/doc/source/devel/api/sardana/macroserver/macros/communication.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/demo.rst b/doc/source/devel/api/sardana/macroserver/macros/demo.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/env.rst b/doc/source/devel/api/sardana/macroserver/macros/env.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/expert.rst b/doc/source/devel/api/sardana/macroserver/macros/expert.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/hkl.rst b/doc/source/devel/api/sardana/macroserver/macros/hkl.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/ioregister.rst b/doc/source/devel/api/sardana/macroserver/macros/ioregister.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/lists.rst b/doc/source/devel/api/sardana/macroserver/macros/lists.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/mca.rst b/doc/source/devel/api/sardana/macroserver/macros/mca.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/scan.rst b/doc/source/devel/api/sardana/macroserver/macros/scan.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/sequence.rst b/doc/source/devel/api/sardana/macroserver/macros/sequence.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/macroserver/macros/standard.rst b/doc/source/devel/api/sardana/macroserver/macros/standard.rst old mode 100755 new mode 100644 diff --git a/doc/source/devel/api/sardana/pool/poolsynchronization.rst b/doc/source/devel/api/sardana/pool/poolsynchronization.rst old mode 100755 new mode 100644 diff --git a/doc/source/sep/res/sep0_workflow.png b/doc/source/sep/res/sep0_workflow.png old mode 100755 new mode 100644 diff --git a/doc/source/sep/res/sep6_motion.bmp b/doc/source/sep/res/sep6_motion.bmp old mode 100755 new mode 100644 diff --git a/doc/source/users/spock.rst b/doc/source/users/spock.rst old mode 100755 new mode 100644 diff --git a/doc/source/users/taurus/macrobutton.rst b/doc/source/users/taurus/macrobutton.rst old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/macros/discrete.py b/src/sardana/macroserver/macros/discrete.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/macros/examples/motion.py b/src/sardana/macroserver/macros/examples/motion.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/scan/test/test_gscan.py b/src/sardana/macroserver/scan/test/test_gscan.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/test/__init__.py b/src/sardana/macroserver/test/__init__.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/test/res/__init__.py b/src/sardana/macroserver/test/res/__init__.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/test/res/fakerecorders.py b/src/sardana/macroserver/test/res/fakerecorders.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/test/res/recorders/path1/fakerecorders.py b/src/sardana/macroserver/test/res/recorders/path1/fakerecorders.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/test/res/recorders/path2/fakerecorders.py b/src/sardana/macroserver/test/res/recorders/path2/fakerecorders.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/test/res/recorders/path3/fakerecorders.py b/src/sardana/macroserver/test/res/recorders/path3/fakerecorders.py old mode 100755 new mode 100644 diff --git a/src/sardana/macroserver/test/test_msrecordermanager.py b/src/sardana/macroserver/test/test_msrecordermanager.py old mode 100755 new mode 100644 diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py old mode 100755 new mode 100644 diff --git a/src/sardana/pool/poolcontrollers/TaurusController.py b/src/sardana/pool/poolcontrollers/TaurusController.py old mode 100755 new mode 100644 diff --git a/src/sardana/pool/test/fake.py b/src/sardana/pool/test/fake.py old mode 100755 new mode 100644 diff --git a/src/sardana/sardanamodulemanager.py b/src/sardana/sardanamodulemanager.py old mode 100755 new mode 100644 diff --git a/src/sardana/spock/spockms.py b/src/sardana/spock/spockms.py old mode 100755 new mode 100644 diff --git a/src/sardana/tango/macroserver/test/base.py b/src/sardana/tango/macroserver/test/base.py old mode 100755 new mode 100644 diff --git a/src/sardana/taurus/core/tango/sardana/macro.py b/src/sardana/taurus/core/tango/sardana/macro.py old mode 100755 new mode 100644 diff --git a/src/sardana/taurus/core/tango/sardana/macroserver.py b/src/sardana/taurus/core/tango/sardana/macroserver.py old mode 100755 new mode 100644 diff --git a/src/sardana/taurus/core/tango/sardana/test/__init__.py b/src/sardana/taurus/core/tango/sardana/test/__init__.py old mode 100755 new mode 100644 diff --git a/src/sardana/taurus/core/tango/sardana/test/paramdef.py b/src/sardana/taurus/core/tango/sardana/test/paramdef.py old mode 100755 new mode 100644 diff --git a/src/sardana/taurus/core/tango/sardana/test/test_macro.py b/src/sardana/taurus/core/tango/sardana/test/test_macro.py old mode 100755 new mode 100644 diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py old mode 100755 new mode 100644 diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py old mode 100755 new mode 100644 diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py old mode 100755 new mode 100644 diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py b/src/sardana/taurus/qt/qtgui/extra_sardana/sardanaeditor.py old mode 100755 new mode 100644 diff --git a/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py b/src/sardana/taurus/qt/qtgui/macrolistener/__init__.py old mode 100755 new mode 100644 From e458333033ffd4b04129f1e1c9e92d4dbdf05e11 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 5 Feb 2019 10:45:08 +0100 Subject: [PATCH 594/652] Bump version 2.6.1 to 2.6.2-alpha --- .bumpversion.cfg | 2 +- src/sardana/release.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index c362a0c235..709ead02fc 100755 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ commit = True message = Bump version {current_version} to {new_version} tag = False tag_name = {new_version} -current_version = 2.6.1 +current_version = 2.6.2-alpha parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} diff --git a/src/sardana/release.py b/src/sardana/release.py index f2804659d5..614bd22d2e 100644 --- a/src/sardana/release.py +++ b/src/sardana/release.py @@ -47,7 +47,7 @@ # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '2.6.1' +version = '2.6.2-alpha' # generate version_info and revision (**deprecated** since v 2.1.2--alpha). if '-' in version: From 5854c2a9891cd7b6c5e6ae3f7f906a5609569af6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 5 Feb 2019 10:45:09 +0100 Subject: [PATCH 595/652] Bump version 2.6.2-alpha to 2.6.2 --- .bumpversion.cfg | 2 +- src/sardana/release.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 709ead02fc..5368bdbd5d 100755 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ commit = True message = Bump version {current_version} to {new_version} tag = False tag_name = {new_version} -current_version = 2.6.2-alpha +current_version = 2.6.2 parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} diff --git a/src/sardana/release.py b/src/sardana/release.py index 614bd22d2e..63ba972ef6 100644 --- a/src/sardana/release.py +++ b/src/sardana/release.py @@ -47,7 +47,7 @@ # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '2.6.2-alpha' +version = '2.6.2' # generate version_info and revision (**deprecated** since v 2.1.2--alpha). if '-' in version: From 7b737f21f619041965c5a0fcb818db08999b7445 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 5 Feb 2019 10:48:32 +0100 Subject: [PATCH 596/652] Bump version in manpages --- doc/man/MacroServer.1 | 4 ++-- doc/man/Pool.1 | 4 ++-- doc/man/Sardana.1 | 4 ++-- doc/man/diffractometeralignment.1 | 4 ++-- doc/man/hklscan.1 | 4 ++-- doc/man/macroexecutor.1 | 4 ++-- doc/man/sardanatestsuite.1 | 4 ++-- doc/man/sequencer.1 | 4 ++-- doc/man/spock.1 | 4 ++-- doc/man/ubmatrix.1 | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/doc/man/MacroServer.1 b/doc/man/MacroServer.1 index c2d22cfb81..cb4b562354 100644 --- a/doc/man/MacroServer.1 +++ b/doc/man/MacroServer.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH MACROSERVER "1" "February 2019" "MacroServer 2.6.1" "User Commands" +.TH MACROSERVER "1" "February 2019" "MacroServer 2.6.2" "User Commands" .SH NAME -MacroServer \- manual page for MacroServer 2.6.1 +MacroServer \- manual page for MacroServer 2.6.2 .SH SYNOPSIS .B usage: \fI\,MacroServer instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/Pool.1 b/doc/man/Pool.1 index 1ba8241fdf..70155acde4 100644 --- a/doc/man/Pool.1 +++ b/doc/man/Pool.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH POOL "1" "February 2019" "Pool 2.6.1" "User Commands" +.TH POOL "1" "February 2019" "Pool 2.6.2" "User Commands" .SH NAME -Pool \- manual page for Pool 2.6.1 +Pool \- manual page for Pool 2.6.2 .SH SYNOPSIS .B usage: \fI\,Pool instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/Sardana.1 b/doc/man/Sardana.1 index f540e0ca3a..6480a5e55f 100644 --- a/doc/man/Sardana.1 +++ b/doc/man/Sardana.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SARDANA "1" "February 2019" "Sardana 2.6.1" "User Commands" +.TH SARDANA "1" "February 2019" "Sardana 2.6.2" "User Commands" .SH NAME -Sardana \- manual page for Sardana 2.6.1 +Sardana \- manual page for Sardana 2.6.2 .SH SYNOPSIS .B usage: \fI\,Sardana instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/diffractometeralignment.1 b/doc/man/diffractometeralignment.1 index 439a52fd7a..7f8358cf47 100644 --- a/doc/man/diffractometeralignment.1 +++ b/doc/man/diffractometeralignment.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH DIFFRACTOMETERALIGNMENT "1" "February 2019" "diffractometeralignment 2.6.1" "User Commands" +.TH DIFFRACTOMETERALIGNMENT "1" "February 2019" "diffractometeralignment 2.6.2" "User Commands" .SH NAME -diffractometeralignment \- manual page for diffractometeralignment 2.6.1 +diffractometeralignment \- manual page for diffractometeralignment 2.6.2 .SH SYNOPSIS .B diffractometeralignment \fI\, \/\fR[\fI\,door_name\/\fR] diff --git a/doc/man/hklscan.1 b/doc/man/hklscan.1 index dd019a39eb..ff1a4e8eaa 100644 --- a/doc/man/hklscan.1 +++ b/doc/man/hklscan.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH HKLSCAN "1" "February 2019" "hklscan 2.6.1" "User Commands" +.TH HKLSCAN "1" "February 2019" "hklscan 2.6.2" "User Commands" .SH NAME -hklscan \- manual page for hklscan 2.6.1 +hklscan \- manual page for hklscan 2.6.2 .SH SYNOPSIS .B hklscan \fI\, \/\fR[\fI\,door_name\/\fR] diff --git a/doc/man/macroexecutor.1 b/doc/man/macroexecutor.1 index b81b8d70c6..15178a970c 100644 --- a/doc/man/macroexecutor.1 +++ b/doc/man/macroexecutor.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH MACROEXECUTOR "1" "February 2019" "macroexecutor 2.6.1" "User Commands" +.TH MACROEXECUTOR "1" "February 2019" "macroexecutor 2.6.2" "User Commands" .SH NAME -macroexecutor \- manual page for macroexecutor 2.6.1 +macroexecutor \- manual page for macroexecutor 2.6.2 .SH SYNOPSIS .B macroexecutor [\fI\,options\/\fR] diff --git a/doc/man/sardanatestsuite.1 b/doc/man/sardanatestsuite.1 index 5e202cf342..c8891e87f3 100644 --- a/doc/man/sardanatestsuite.1 +++ b/doc/man/sardanatestsuite.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SARDANATESTSUITE "1" "February 2019" "sardanatestsuite 2.6.1" "User Commands" +.TH SARDANATESTSUITE "1" "February 2019" "sardanatestsuite 2.6.2" "User Commands" .SH NAME -sardanatestsuite \- manual page for sardanatestsuite 2.6.1 +sardanatestsuite \- manual page for sardanatestsuite 2.6.2 .SH DESCRIPTION usage: sardanatestsuite [\-h] [\-e EXCLUDE_PATTERN] [\-\-version] .PP diff --git a/doc/man/sequencer.1 b/doc/man/sequencer.1 index 026957801f..97e1835ab5 100644 --- a/doc/man/sequencer.1 +++ b/doc/man/sequencer.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SEQUENCER "1" "February 2019" "sequencer 2.6.1" "User Commands" +.TH SEQUENCER "1" "February 2019" "sequencer 2.6.2" "User Commands" .SH NAME -sequencer \- manual page for sequencer 2.6.1 +sequencer \- manual page for sequencer 2.6.2 .SH SYNOPSIS .B sequencer [\fI\,options\/\fR] diff --git a/doc/man/spock.1 b/doc/man/spock.1 index f0966bceba..f8d35389b5 100644 --- a/doc/man/spock.1 +++ b/doc/man/spock.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SPOCK "1" "February 2019" "spock 2.6.1" "User Commands" +.TH SPOCK "1" "February 2019" "spock 2.6.2" "User Commands" .SH NAME -spock \- manual page for spock 2.6.1 +spock \- manual page for spock 2.6.2 .SH DESCRIPTION ========= .IP diff --git a/doc/man/ubmatrix.1 b/doc/man/ubmatrix.1 index b4af81bcd3..e4a7160177 100644 --- a/doc/man/ubmatrix.1 +++ b/doc/man/ubmatrix.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH UBMATRIX "1" "February 2019" "ubmatrix 2.6.1" "User Commands" +.TH UBMATRIX "1" "February 2019" "ubmatrix 2.6.2" "User Commands" .SH NAME -ubmatrix \- manual page for ubmatrix 2.6.1 +ubmatrix \- manual page for ubmatrix 2.6.2 .SH SYNOPSIS .B ubmatrix \fI\,\/\fR From d8f7fc50b45ab7d75852527bb4115ffffb6d590d Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 5 Feb 2019 10:49:33 +0100 Subject: [PATCH 597/652] Bump version 2.6.2 to 2.6.3-alpha --- .bumpversion.cfg | 2 +- src/sardana/release.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 5368bdbd5d..ece9e34534 100755 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ commit = True message = Bump version {current_version} to {new_version} tag = False tag_name = {new_version} -current_version = 2.6.2 +current_version = 2.6.3-alpha parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} diff --git a/src/sardana/release.py b/src/sardana/release.py index 63ba972ef6..597cf8621c 100644 --- a/src/sardana/release.py +++ b/src/sardana/release.py @@ -47,7 +47,7 @@ # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '2.6.2' +version = '2.6.3-alpha' # generate version_info and revision (**deprecated** since v 2.1.2--alpha). if '-' in version: From 993fbcb660e774a00c0c2fdf42b00783b187205a Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 5 Feb 2019 16:03:15 +0100 Subject: [PATCH 598/652] Add default timer getter to PoolController --- src/sardana/pool/poolcontroller.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sardana/pool/poolcontroller.py b/src/sardana/pool/poolcontroller.py index fe617468ad..10eec61fc7 100644 --- a/src/sardana/pool/poolcontroller.py +++ b/src/sardana/pool/poolcontroller.py @@ -922,6 +922,28 @@ def write_one(self, axis, value): # END SPECIFIC TO IOR CONTROLLER ----------------------------------------- + # START SPECIFIC TO TIMERABLE CONTROLLER --------------------------------- + + def get_default_timer(self): + """Get default timer as announced by the controller (plug-in). + + Only for *Timerable* controllers, e.g. + :class:`~sardana.pool.controller.CounterTimerController`, + :class:`~sardana.pool.controller.OneDController`, + :class:`~sardana.pool.controller.TwoDController`. + + :return: axis of the default timer or :obj:`None` if not defined + :rtype: :obj:`int` or :obj:`None` + """ + if not self.is_timerable(): + raise TypeError("non-timerable controller") + try: + return self.ctrl.default_timer + except AttributeError: + return None + + # END SPECIFIC TO IOR CONTROLLER ----------------------------------------- + class PoolPseudoMotorController(PoolController): From 230f77ac2c3a191fd3854d5b2dd4b21597ef61da Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 5 Feb 2019 16:03:55 +0100 Subject: [PATCH 599/652] Add doc for integration_timer getter/setter --- src/sardana/pool/poolbasechannel.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 0d32e5a857..87d78c7c74 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -291,13 +291,23 @@ def clear_value_buffer(self): # -------------------------------------------------------------------------- def get_integration_time(self): - """Returns the integration time for this object. + """Return the integration time for this object. :return: the current integration time - :rtype: :ob:`float`""" + :rtype: :obj:`float`""" return self._integration_time def set_integration_time(self, integration_time, propagate=1): + """Set the integration time for this object. + + :param integration_time: integration time in seconds to set + :type integration_time: :obj:`float` + :param propagate: + 0 for not propagating, 1 to propagate, 2 propagate with priority + :type propagate: :obj:`int` + :return: the current integration time + :rtype: :obj:`float` + """ if integration_time == self._integration_time: # integration time is not changed. Do nothing return From 2fa5bbc6674690a3c4bf9608ec37e5b17abf00ab Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Wed, 6 Feb 2019 03:09:05 +0100 Subject: [PATCH 600/652] polish and add post-newfile hook --- src/sardana/macroserver/macros/standard.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index 27773378f0..1609b6d3bd 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -862,12 +862,13 @@ class newfile(Macro): If ScanFilePath is only a file name, the ScanDir must be set externally via senv ScanDir PathToScanFile or using the %expconf. Otherwise, the path in ScanFilePath must be absolute and existing on the MacroServer host. - The ScanID should be set to the value of the upcoming scan number. Default - value is 1. + The ScanID should be set to the value before the upcoming scan number. + Default value is 0. """ env = ('ScanDir', 'ScanFile', 'ScanID') - + hints = {'allowsHooks': ('post-newfile')} + param_def = [ ['ScanFileDir_list', ParamRepeat(['ScanFileDir', Type.String, None, @@ -930,8 +931,6 @@ def run(self, ScanFileDir_list, ScanID): if ScanID < 1: ScanID = 0 - else: - ScanID = ScanID-1 self.setEnv('ScanFile', fileName_list) self.setEnv('ScanDir', path_list[0]) @@ -942,3 +941,6 @@ def run(self, ScanFileDir_list, ScanID): for ScanFile in fileName_list: self.output(' %s', ScanFile) self.output('Next scan is #%d', ScanID+1) + + for postNewfileHook in self.getHooks('post-newfile'): + postNewfileHook() From 11b7998d737cc86f2cd0bb2cbddbbd3bfa42bf0f Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Wed, 6 Feb 2019 04:17:26 +0100 Subject: [PATCH 601/652] add post-newfile hook and improved output format. Default input for ScanID is now n-1 when the next scan should be n --- src/sardana/macroserver/macros/standard.py | 36 ++++++++++++---------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index 6a741e35ba..ff74a8064b 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -895,18 +895,17 @@ def run(self, nr, macro_name_params): yield progress -class newfile(Macro): +class newfile(Hookable, Macro): """ Sets the ScanDir and ScanFile as well as ScanID in the environment. If ScanFilePath is only a file name, the ScanDir must be set externally via senv ScanDir PathToScanFile or using the %expconf. Otherwise, the path in ScanFilePath must be absolute and existing on the MacroServer host. - The ScanID should be set to the value before the upcoming scan number. + The ScanID should be set to the value before the upcoming scan number. Default value is 0. """ - env = ('ScanDir', 'ScanFile', 'ScanID') hints = {'allowsHooks': ('post-newfile')} - + param_def = [ ['ScanFileDir_list', ParamRepeat(['ScanFileDir', Type.String, None, @@ -924,11 +923,14 @@ def run(self, ScanFileDir_list, ScanID): fileName = os.path.basename(ScanFileDir) if not path and i == 0: # first entry and no given ScanDir: check if ScanDir exists - ScanDir = self.getEnv('ScanDir') + try: + ScanDir = self.getEnv('ScanDir') + except: + ScanDir = '' if not ScanDir: self.warning('Data is not stored until ScanDir is set! ' 'Provide ScanDir with newfile macro: ' - 'newfile [/] or' + 'newfile [/] or ' 'senv ScanDir or with %expconf') else: path = ScanDir @@ -967,18 +969,20 @@ def run(self, ScanFileDir_list, ScanID): self.debug('Filename is %s.' % fileName) fileName_list.append(fileName) - if ScanID < 1: - ScanID = 0 + if ScanID < 1: + ScanID = 0 - self.setEnv('ScanFile', fileName_list) - self.setEnv('ScanDir', path_list[0]) - self.setEnv('ScanID', ScanID) + self.setEnv('ScanFile', fileName_list) + self.setEnv('ScanDir', path_list[0]) + self.setEnv('ScanID', ScanID) - self.output('ScanDir is: %s', path_list[0]) - self.output('ScanFile set to: ') - for ScanFile in fileName_list: - self.output(' %s', ScanFile) - self.output('Next scan is #%d', ScanID+1) + self.output('ScanDir is\t: %s', path_list[0]) + for i, ScanFile in enumerate(fileName_list): + if i == 0: + self.output('ScanFile set to\t: %s', ScanFile) + else: + self.output('\t\t %s', ScanFile) + self.output('Next scan is\t: #%d', ScanID+1) for postNewfileHook in self.getHooks('post-newfile'): postNewfileHook() From cc38929f8cede2af18a79ad03f029ed1f064e02a Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 11:57:55 +0100 Subject: [PATCH 602/652] Configure tango events for Timer and IntegrationTime attributes --- src/sardana/pool/controller.py | 21 +++++++++++++++++++++ src/sardana/tango/pool/PoolDevice.py | 20 ++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index 35c4d9d511..259496a416 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -901,6 +901,11 @@ class CounterTimerController(Controller, Readable, Startable, Stopable, #: A :class:`dict` containing the standard attributes present on each axis #: device standard_axis_attributes = { + 'IntegrationTime': {'type': float, + 'description': 'Integration time used in ' + 'independent acquisition'}, + 'Timer': {'type': str, + 'description': 'Timer used in independent acquisition'}, 'Value': {'type': float, 'description': 'Value', }, 'Data': {'type': str, @@ -1033,6 +1038,9 @@ class ZeroDController(Controller, Readable, Stopable): #: A :class:`dict` containing the standard attributes present on each axis #: device standard_axis_attributes = { + 'IntegrationTime': {'type': float, + 'description': 'Integration time used in ' + 'independent acquisition'}, 'Value': {'type': float, 'description': 'Value', }, 'Data': {'type': str, @@ -1058,6 +1066,11 @@ class OneDController(Controller, Readable, Startable, Stopable, Loadable): .. versionadded:: 1.2""" standard_axis_attributes = { + 'IntegrationTime': {'type': float, + 'description': 'Integration time used in ' + 'independent acquisition'}, + 'Timer': {'type': str, + 'description': 'Timer used in independent acquisition'}, 'Value': {'type': (float,), 'description': 'Value', 'maxdimsize': (16 * 1024,)}, @@ -1094,6 +1107,11 @@ class TwoDController(Controller, Readable, Startable, Stopable, Loadable): implement your own 2D controller for the device pool.""" standard_axis_attributes = { + 'IntegrationTime': {'type': float, + 'description': 'Integration time used in ' + 'independent acquisition'}, + 'Timer': {'type': str, + 'description': 'Timer used in independent acquisition'}, 'Value': {'type': ((float,),), 'description': 'Value', 'maxdimsize': (4 * 1024, 4 * 1024)}, @@ -1402,6 +1420,9 @@ class PseudoCounterController(Controller): #: A :class:`dict` containing the standard attributes present on each axis #: device standard_axis_attributes = { + 'IntegrationTime': {'type': float, + 'description': 'Integration time used in ' + 'independent acquisition'}, 'Value': {'type': float, 'description': 'Value', }, 'Data': {'type': str, diff --git a/src/sardana/tango/pool/PoolDevice.py b/src/sardana/tango/pool/PoolDevice.py index 86edae222f..1b1872da50 100644 --- a/src/sardana/tango/pool/PoolDevice.py +++ b/src/sardana/tango/pool/PoolDevice.py @@ -866,6 +866,16 @@ def _encode_value_chunk(self, value_chunk): _, encoded_data = self._codec.encode(('', data)) return encoded_data + def initialize_dynamic_attributes(self): + attrs = PoolElementDevice.initialize_dynamic_attributes(self) + + non_detect_evts = "integrationtime", + + for attr_name in non_detect_evts: + if attr_name in attrs: + self.set_change_event(attr_name, True, False) + return attrs + def read_Data(self, attr): desc = "Data attribute is not foreseen for reading. It is used only "\ "as the communication channel for the continuous acquisitions." @@ -913,6 +923,16 @@ def __init__(self, dclass, name): """Constructor""" PoolExpChannelDevice.__init__(self, dclass, name) + def initialize_dynamic_attributes(self): + attrs = PoolExpChannelDevice.initialize_dynamic_attributes(self) + + detect_evts = "timer", + + for attr_name in detect_evts: + if attr_name in attrs: + self.set_change_event(attr_name, True, True) + return attrs + def read_Timer(self, attr): """Reads the timer for this channel. From a9b6d17e8c6102dd36adf5bc3d19a447bf19e14a Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 12:01:33 +0100 Subject: [PATCH 603/652] Cast None to string "None" when disabling timer --- src/sardana/pool/poolbasechannel.py | 4 ---- src/sardana/tango/pool/CTExpChannel.py | 4 +++- src/sardana/tango/pool/OneDExpChannel.py | 4 +++- src/sardana/tango/pool/TwoDExpChannel.py | 6 +++++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index 87d78c7c74..a705296ddd 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -417,10 +417,6 @@ def set_timer(self, timer, propagate=1): if not propagate: return - - if timer is None: - timer = 'None' - self.fire_event(EventType("timer", priority=propagate), timer) timer = property(get_timer, set_timer, diff --git a/src/sardana/tango/pool/CTExpChannel.py b/src/sardana/tango/pool/CTExpChannel.py index dca52172e8..ebea985c3e 100644 --- a/src/sardana/tango/pool/CTExpChannel.py +++ b/src/sardana/tango/pool/CTExpChannel.py @@ -138,7 +138,9 @@ def _on_ct_changed(self, event_source, event_type, event_value): timestamp = event_value.timestamp else: value = event_value - if name == "value": + if name == "timer" and value is None: + value = "None" + elif name == "value": w_value = event_source.get_value_attribute().w_value state = self.ct.get_state() if state == State.Moving: diff --git a/src/sardana/tango/pool/OneDExpChannel.py b/src/sardana/tango/pool/OneDExpChannel.py index 35def07e0f..e3096a3325 100644 --- a/src/sardana/tango/pool/OneDExpChannel.py +++ b/src/sardana/tango/pool/OneDExpChannel.py @@ -138,7 +138,9 @@ def _on_oned_changed(self, event_source, event_type, event_value): timestamp = event_value.timestamp else: value = event_value - if name == "value": + if name == "timer" and value is None: + value = "None" + elif name == "value": w_value = event_source.get_value_attribute().w_value state = self.oned.get_state() if state == State.Moving: diff --git a/src/sardana/tango/pool/TwoDExpChannel.py b/src/sardana/tango/pool/TwoDExpChannel.py index 634e835a30..12b7c81741 100644 --- a/src/sardana/tango/pool/TwoDExpChannel.py +++ b/src/sardana/tango/pool/TwoDExpChannel.py @@ -127,8 +127,12 @@ def _on_twod_changed(self, event_source, event_type, event_value): else: value = event_value.value timestamp = event_value.timestamp + else: + value = event_value - if name == "value": + if name == "timer" and value is None: + value = "None" + elif name == "value": state = self.twod.get_state() if state == State.Moving: quality = AttrQuality.ATTR_CHANGING From ac48f02f31c15ecf59c081e06335fb18cf3979f1 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 12:08:42 +0100 Subject: [PATCH 604/652] Fix emit of integration time change events --- src/sardana/tango/pool/CTExpChannel.py | 1 + src/sardana/tango/pool/OneDExpChannel.py | 1 + src/sardana/tango/pool/TwoDExpChannel.py | 1 + 3 files changed, 3 insertions(+) diff --git a/src/sardana/tango/pool/CTExpChannel.py b/src/sardana/tango/pool/CTExpChannel.py index ebea985c3e..5ba6f48dc4 100644 --- a/src/sardana/tango/pool/CTExpChannel.py +++ b/src/sardana/tango/pool/CTExpChannel.py @@ -107,6 +107,7 @@ def _on_ct_changed(self, event_source, event_type, event_value): timestamp = time.time() name = event_type.name.lower() + name = name.replace('_', '') # for integration_time events attr_name = name # TODO: remove this condition when Data attribute will be substituted # by ValueBuffer diff --git a/src/sardana/tango/pool/OneDExpChannel.py b/src/sardana/tango/pool/OneDExpChannel.py index e3096a3325..e491d0d96b 100644 --- a/src/sardana/tango/pool/OneDExpChannel.py +++ b/src/sardana/tango/pool/OneDExpChannel.py @@ -107,6 +107,7 @@ def _on_oned_changed(self, event_source, event_type, event_value): timestamp = time.time() name = event_type.name.lower() + name = name.replace('_', '') # for integration_time events attr_name = name # TODO: remove this condition when Data attribute will be substituted # by ValueBuffer diff --git a/src/sardana/tango/pool/TwoDExpChannel.py b/src/sardana/tango/pool/TwoDExpChannel.py index 12b7c81741..17e5fec83b 100644 --- a/src/sardana/tango/pool/TwoDExpChannel.py +++ b/src/sardana/tango/pool/TwoDExpChannel.py @@ -106,6 +106,7 @@ def _on_twod_changed(self, event_source, event_type, event_value): timestamp = time.time() name = event_type.name.lower() + name = name.replace('_', '') # for integration_time events try: attr = self.get_attribute_by_name(name) From b8600759ec6e9f9e68bf92761df214e0af1bc0a7 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 12:11:39 +0100 Subject: [PATCH 605/652] Improve test helper Add counter to controller already in the createPoolCounterTimer helper. --- src/sardana/pool/test/helper.py | 4 +++- src/sardana/pool/test/test_ctacquisition.py | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/test/helper.py b/src/sardana/pool/test/helper.py index 7b6e09b4a9..ce4649f0f3 100644 --- a/src/sardana/pool/test/helper.py +++ b/src/sardana/pool/test/helper.py @@ -94,7 +94,9 @@ def createPoolCounterTimer(pool, poolcontroller, conf): kwargs = copy.deepcopy(conf) kwargs['pool'] = pool kwargs['ctrl'] = poolcontroller - return PoolCounterTimer(**kwargs) + ct = PoolCounterTimer(**kwargs) + poolcontroller.add_element(ct) + return ct def createPoolZeroDExpChannel(pool, poolcontroller, conf): diff --git a/src/sardana/pool/test/test_ctacquisition.py b/src/sardana/pool/test/test_ctacquisition.py index 1f8295f046..37e6344150 100644 --- a/src/sardana/pool/test/test_ctacquisition.py +++ b/src/sardana/pool/test/test_ctacquisition.py @@ -50,7 +50,6 @@ def setUp(self): pc = createPoolController(pool, dummyPoolCTCtrlConf01) pct = createPoolCounterTimer(pool, pc, dummyCounterTimerConf01) - pc.add_element(pct) pool.add_element(pc) pool.add_element(pct) From 04cc80181614608f79f22f65747e6ded2d6a7105 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 14:38:20 +0100 Subject: [PATCH 606/652] Change default timer to __default and refactor code Setting default timer to __default required code refactoring. Now part of the configuration is created at the channel's construction time and other part (the one related to the timer) is created on demand when acquiring. This is because the default timer may not exist yet at the channel's construction time e.g. when Tango devices are initialized. --- src/sardana/pool/poolbasechannel.py | 154 +++++++++++++--------------- 1 file changed, 72 insertions(+), 82 deletions(-) diff --git a/src/sardana/pool/poolbasechannel.py b/src/sardana/pool/poolbasechannel.py index a705296ddd..fa2ec1c125 100644 --- a/src/sardana/pool/poolbasechannel.py +++ b/src/sardana/pool/poolbasechannel.py @@ -34,7 +34,7 @@ from sardana.sardanabuffer import SardanaBuffer from sardana.pool.poolelement import PoolElement from sardana.pool.poolacquisition import PoolAcquisitionSoftware,\ - get_timerable_ctrls + get_timerable_items from sardana.pool.poolmeasurementgroup import ChannelConfiguration,\ ControllerConfiguration from sardana.sardanaevent import EventType @@ -84,9 +84,7 @@ def __init__(self, **kwargs): if not self.AcquisitionClass is None: acq_name = "%s.Acquisition" % self._name self.set_action_cache(self.AcquisitionClass(self, name=acq_name)) - self._integration_time = False - self._timer = None - self.ctrls = None + self._integration_time = 0 def has_pseudo_elements(self): """Informs whether this channel forms part of any pseudo element @@ -305,8 +303,6 @@ def set_integration_time(self, integration_time, propagate=1): :param propagate: 0 for not propagating, 1 to propagate, 2 propagate with priority :type propagate: :obj:`int` - :return: the current integration time - :rtype: :obj:`float` """ if integration_time == self._integration_time: # integration time is not changed. Do nothing @@ -321,103 +317,97 @@ def set_integration_time(self, integration_time, propagate=1): doc="channel integration time") def start_acquisition(self): - self._aborted = False - self._stopped = False - if not self._simulation_mode: - if self._timer is not None: - if self.ctrls is None: - self.create_config() - self.acquisition.run(self.ctrls, - self.integration_time, - self.master, - None) - - def create_config(self): - if self._timer is None: - return - - ctrl = self.get_controller() - ctrl.set_ctrl_par("synchronization", - AcqSynch.SoftwareTrigger) - - self.conf_ctrl = ControllerConfiguration(ctrl) - # self has to be used. If not it is removed - self.conf_channel = ChannelConfiguration(self) - self.conf_ctrl.add_channel(self.conf_channel) - channel = self.conf_ctrl.get_channels(enabled=True)[0] - if self.timer == "__self": - self.conf_ctrl.timer = channel - else: - if self.timer == "__default": - self.conf_timer = ChannelConfiguration( - ctrl.get_element(axis=ctrl.ctrl.default_timer)) - else: - self.conf_timer = ChannelConfiguration( - self.pool.get_element_by_name(self.timer)) - self.conf_ctrl.add_channel(self.conf_timer) - ctimer = self.conf_ctrl.get_channels(enabled=True)[1] - self.conf_ctrl.timer = ctimer - - self.conf_ctrl.monitor = channel - self.ctrls = get_timerable_ctrls([self.conf_ctrl], AcqMode.Timer) - self.master = self.ctrls[0].master - if self.timer != "__self": - if self.timer == "__default": - self.acquisition.add_element( - ctrl.get_element(axis=ctrl.ctrl.default_timer)) - else: - self.acquisition.add_element( - self.pool.get_element_by_name(self.timer)) + msg = "{0} does not support independent acquisition".format( + self.__class__.__name__) + raise NotImplementedError(msg) class PoolTimerableChannel(PoolBaseChannel): def __init__(self, **kwargs): PoolBaseChannel.__init__(self, **kwargs) - - # ------------------------------------------------------------------------- + # TODO: part of the configuration could be moved to the base class + # so other experimental channels could reuse it + self._conf_channel = ChannelConfiguration(self) + self._conf_ctrl = ControllerConfiguration(self.controller) + self._conf_ctrl.add_channel(self._conf_channel) + self._timer = "__default" + self._conf_timer = None + + # ------------------------------------------------------------------------ # timer - # ------------------------------------------------------------------------- + # ------------------------------------------------------------------------ def get_timer(self): - """Returns the timer for this object. + """Return the timer for this object. :return: the current timer - :rtype: :obj:`str`""" + :rtype: :obj:`str` + """ return self._timer def set_timer(self, timer, propagate=1): + """Set timer for this object. + :param timer: new timer to set + :type timer: :obj:`str` + :param propagate: + 0 for not propagating, 1 to propagate, 2 propagate with priority + :type propagate: :obj:`int` + """ if timer == self._timer: - # timer is not changed. Do nothing return - - if timer == "__default": - try: - ctrl = self.get_controller() - self.default_timer_axis = ctrl.ctrl.default_timer - except Exception: - raise ValueError("Error reading default_timer") - return - if self.default_timer_axis is None: - raise ValueError("default_timer not defined in controller") - - if timer is not None and timer != "__self": - try: - if timer != "__default": - self.acquisition.remove_element( - self.pool.get_element_by_name(timer)) - else: - self.acquisition.remove_element( - ctrl.get_element(axis=self.default_timer_axis)) - except Exception: # The new timer does not belong to action - pass + if self._conf_timer is not None: + timer_elem = self._conf_timer.element + if timer_elem is not self: + self.acquisition.remove_element(timer_elem) + self._conf_ctrl.remove_channel(self._conf_timer) self._timer = timer - self.create_config() - + self._conf_timer = None if not propagate: return self.fire_event(EventType("timer", priority=propagate), timer) timer = property(get_timer, set_timer, doc="timer for the timerable channel") + + def _configure_timer(self): + timer = self.timer + if timer == "__self": + conf_timer = self._conf_channel + else: + ctrl = self.get_controller() + if timer == "__default": + axis = ctrl.get_default_timer() + if axis is None: + msg = "default_timer not defined in controller" + raise ValueError(msg) + timer_elem = ctrl.get_element(axis=axis) + else: + timer_elem = self.pool.get_element_by_name(timer) + if timer_elem is self: + conf_timer = self._conf_channel + else: + self.acquisition.add_element(timer_elem) + conf_timer = ChannelConfiguration(timer_elem) + self._conf_ctrl.add_channel(conf_timer) + self._conf_ctrl.timer = conf_timer + self._conf_timer = conf_timer + + def start_acquisition(self): + """Start software triggered acquisition""" + self._aborted = False + self._stopped = False + if self._simulation_mode: + return + if self.timer is None: + msg = "no timer configured - acquisition is not possible" + raise RuntimeError(msg) + + if self._conf_timer is None: + self._configure_timer() + self.controller.set_ctrl_par("synchronization", + AcqSynch.SoftwareTrigger) + ctrls, master = get_timerable_items( + [self._conf_ctrl], self._conf_timer, AcqMode.Timer) + self.acquisition.run(ctrls, self.integration_time, master, None) From b449ddbdb2a0b8c47408266a683891708f0356a6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 14:39:07 +0100 Subject: [PATCH 607/652] Add test for independent acquisition of counters --- src/sardana/pool/test/test_poolcountertimer.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sardana/pool/test/test_poolcountertimer.py b/src/sardana/pool/test/test_poolcountertimer.py index 14017643e8..dec8347bc3 100644 --- a/src/sardana/pool/test/test_poolcountertimer.py +++ b/src/sardana/pool/test/test_poolcountertimer.py @@ -23,7 +23,10 @@ ## ############################################################################## +import time + from taurus.external import unittest + from sardana.pool.poolcountertimer import PoolCounterTimer from sardana.pool.test import (FakePool, createPoolController, createPoolCounterTimer, dummyCounterTimerConf01, @@ -47,6 +50,14 @@ def test_init(self): 'PoolCounterTimer instance' self.assertIsInstance(self.pct, PoolCounterTimer, msg) + def test_acquisition(self): + self.pct.integration_time = 0.1 + self.pct.start_acquisition() + while self.pct.acquisition.is_running(): + time.sleep(0.01) + msg = "wrong value after acquisition" + self.assertEqual(self.pct.value.value, 0.1, msg) + def tearDown(self): unittest.TestCase.tearDown(self) self.pct = None From 8020bab1ffc5de02cb7cc595a6139ec43fa8e391 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 15:14:59 +0100 Subject: [PATCH 608/652] Add integration time method to ExpChannel taurus extension --- src/sardana/taurus/core/tango/sardana/pool.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 7b8fefd599..6033cfe17d 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -672,8 +672,24 @@ class ExpChannel(PoolElement): def __init__(self, name, **kw): """ExpChannel initialization.""" self.call__init__(PoolElement, name, **kw) + self._last_integ_time = None self._value_buffer = {} + def getIntegrationTime(self): + return self._getAttrValue('IntegrationTime') + + def getIntegrationTimeObj(self): + return self._getAttrEG('IntegrationTime') + + def setIntegrationTime(self, ctime): + self.getIntegrationTimeObj().write(ctime) + + def putIntegrationTime(self, ctime): + if self._last_integ_time == ctime: + return + self._last_integ_time = ctime + self.getIntegrationTimeObj().write(ctime) + def getValueObj_(self): """Retrurns Value attribute event generator object. From d2ac6f469cdf01a64ee9c86658dcddd53ff8c585 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 15:33:16 +0100 Subject: [PATCH 609/652] Add count method to ExpChannel taurus extension --- src/sardana/taurus/core/tango/sardana/pool.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 6033cfe17d..0cb9e99bfa 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -720,6 +720,24 @@ def valueBufferChanged(self, value_buffer): for index, value in zip(indexes, values): self._value_buffer[index] = value + def _start(self, *args, **kwargs): + self.Start() + + def go(self, *args, **kwargs): + start_time = time.time() + integration_time = args[0] + if integration_time is None or integration_time == 0: + return self.getStateEG().readValue(), self.getValues() + self.putIntegrationTime(integration_time) + PoolElement.go(self) + state = self.getStateEG().readValue() + values = self.getValue() + ret = state, values + self._total_go_time = time.time() - start_time + return ret + + count = go + class CTExpChannel(ExpChannel): """ Class encapsulating CTExpChannel functionality.""" From aec2d989cfad04e5418fc16230d6582b673e20e3 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 15:38:00 +0100 Subject: [PATCH 610/652] Add TimerableExpChannel taurus extension --- src/sardana/taurus/core/tango/sardana/pool.py | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py index 0cb9e99bfa..2c43502c60 100644 --- a/src/sardana/taurus/core/tango/sardana/pool.py +++ b/src/sardana/taurus/core/tango/sardana/pool.py @@ -739,26 +739,43 @@ def go(self, *args, **kwargs): count = go -class CTExpChannel(ExpChannel): +class TimerableExpChannel(ExpChannel): + + def getTimer(self): + return self._getAttrValue('Timer') + + def getTimerObj(self): + return self._getAttrEG('Timer') + + def setTimer(self, timer): + self.getTimerObj().write(timer) + + +class CTExpChannel(TimerableExpChannel): """ Class encapsulating CTExpChannel functionality.""" pass + class ZeroDExpChannel(ExpChannel): """ Class encapsulating ZeroDExpChannel functionality.""" pass -class OneDExpChannel(ExpChannel): + +class OneDExpChannel(TimerableExpChannel): """ Class encapsulating OneDExpChannel functionality.""" pass -class TwoDExpChannel(ExpChannel): + +class TwoDExpChannel(TimerableExpChannel): """ Class encapsulating TwoDExpChannel functionality.""" pass + class PseudoCounter(ExpChannel): """ Class encapsulating PseudoCounter functionality.""" pass + class TriggerGate(PoolElement): """ Class encapsulating TriggerGate functionality.""" pass From cda63498809295ba80e2694c365eff352485ac19 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Wed, 6 Feb 2019 15:38:41 +0100 Subject: [PATCH 611/652] Filter environmentChanged QDoor events, only experiment configs. --- .../qt/qtcore/tango/sardana/macroserver.py | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 066aca32c7..f8d5331895 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -43,6 +43,9 @@ class QDoor(BaseDoor, Qt.QObject): "recordDataUpdated", "macroStatusUpdated"] __pyqtSignals__ += ["%sUpdated" % l.lower() for l in BaseDoor.log_streams] + envExpConfigChangesAllowed = ['ActiveMntGrp', 'ScanDir', 'ScanFile', + 'DataCompressionRank'] + # sometimes we emit None hence the type is object # (but most of the data are passed with type list) resultUpdated = Qt.pyqtSignal(object) @@ -99,7 +102,7 @@ def _prepare_connections(self): if not self._use_experiment_configuration and \ not self._connections_prepared: self.macro_server.environmentChanged.connect( - self._onExperimentConfigurationChanged) + self._onExperimentConfigurationEnvironmentChanged) self.macro_server.elementsChanged.connect(self._elementsChanged) self._elementsChanged() self._connections_prepared = True @@ -121,6 +124,38 @@ def _elementsChanged(self): if mntgrp_changed: self._onExperimentConfigurationChanged() + def _onExperimentConfigurationEnvironmentChanged(self, args): + """ + Filter environment changes that affect to the experiment + configuration. + + + :param args: + The args order is : + added (environment added) + removed (environment removed) + changed (environment changed) + :return: + """ + + try: + envExpChanged = False + # Filter only the Environment added/removed/changes related with + # the experiment, not for all. + for envs in args: + val = envs.intersection(self.envExpConfigChangesAllowed) + if len(val) > 1: + envExpChanged = True + break + + if not envExpChanged: + return + except Exception as e: + print e + pass + + self._onExperimentConfigurationChanged() + def _onExperimentConfigurationChanged(self, *args): conf = copy.deepcopy(BaseDoor.getExperimentConfiguration(self)) self.experimentConfigurationChanged.emit(conf) From 29deafce0b7bb21039185232cc36e28430355c66 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 16:27:14 +0100 Subject: [PATCH 612/652] Document timer and integration_time attributes of timerable channels --- doc/source/devel/api/api_1D.rst | 18 ++++++++++++++++-- doc/source/devel/api/api_2D.rst | 18 ++++++++++++++++-- doc/source/devel/api/api_countertimer.rst | 22 +++++++++++++++++++--- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/doc/source/devel/api/api_1D.rst b/doc/source/devel/api/api_1D.rst index ef2628e39b..5d78caff37 100644 --- a/doc/source/devel/api/api_1D.rst +++ b/doc/source/devel/api/api_1D.rst @@ -18,10 +18,24 @@ The other attributes are: data source Unique identifier for the 1D data (value attribute) +timer + name of the timer channel (proceeding from the same controller) to be used + when the channel is acquired independently + + special values: + + * __default - controller's default timer + * __self - the same channel acts like a timer + * None - independent acquisition is disabled + +integration time + integration time (in seconds) to be used when the channel is acquired + independently + The available operations are: -start acquisition(integration time) - starts to acquire the 1D with the given integration time +start acquisition + starts to acquire the 1D :meth:`~PoolCounterTimer.start_acquisition` diff --git a/doc/source/devel/api/api_2D.rst b/doc/source/devel/api/api_2D.rst index c343a0ebc2..9b6641eb69 100644 --- a/doc/source/devel/api/api_2D.rst +++ b/doc/source/devel/api/api_2D.rst @@ -18,10 +18,24 @@ The other attributes are: data source Unique identifier for the 2D data (value attribute) +timer + name of the timer channel (proceeding from the same controller) to be used + when the channel is acquired independently + + special values: + + * __default - controller's default timer + * __self - the same channel acts like a timer + * None - independent acquisition is disabled + +integration time + integration time (in seconds) to be used when the channel is acquired + independently + The available operations are: -start acquisition(integration time) - starts to acquire the 2D with the given integration time +start acquisition + starts to acquire the 2Ds :meth:`~PoolCounterTimer.start_acquisition` diff --git a/doc/source/devel/api/api_countertimer.rst b/doc/source/devel/api/api_countertimer.rst index 4e25289bcf..3bcec1ad20 100644 --- a/doc/source/devel/api/api_countertimer.rst +++ b/doc/source/devel/api/api_countertimer.rst @@ -13,12 +13,28 @@ A counter/timer has a ``state``, and a ``value`` attributes. The state indicates at any time if the counter/timer is stopped, in alarm or moving. The value, indicates the current counter/timer value. +The other attributes are: + +timer + name of the timer channel (proceeding from the same controller) to be used + when the channel is acquired independently + + special values: + + * __default - controller's default timer + * __self - the same channel acts like a timer + * None - independent acquisition is disabled + +integration time + integration time (in seconds) to be used when the channel is acquired + independently + The available operations are: -start acquisition(integration time) - starts to acquire the counter/timer with the given integration time +start acquisition + starts to acquire the counter/timer - :meth:`~PoolCounterTimer.start_acquisition` + :meth:`~sardana.pool.poolbasechannel.PoolTimerableChannel.start_acquisition` stop stops the counter/timer acquisition in an orderly fashion From 76f21b361bae818445d6aa44257ed6d1cc34d13a Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 16:27:33 +0100 Subject: [PATCH 613/652] Document default_timer of the controller --- .../devel/howto_controllers/howto_countertimercontroller.rst | 3 +++ src/sardana/pool/controller.py | 1 + 2 files changed, 4 insertions(+) diff --git a/doc/source/devel/howto_controllers/howto_countertimercontroller.rst b/doc/source/devel/howto_controllers/howto_countertimercontroller.rst index 996b3149ab..b435b55a1e 100644 --- a/doc/source/devel/howto_controllers/howto_countertimercontroller.rst +++ b/doc/source/devel/howto_controllers/howto_countertimercontroller.rst @@ -231,6 +231,9 @@ this configuration (axis number) via the controller parameter ``timer`` and ``monitor``. The currently used acquisition mode is set via the controller parameter ``acquisition_mode``. +Controller may announce its default timer axis with the +:obj:`~sardana.pool.controller.Loadable.default_timer` class attribute. + .. _sardana-countertimercontroller-howto-advanced: Advanced topics diff --git a/src/sardana/pool/controller.py b/src/sardana/pool/controller.py index 259496a416..8bd75acec1 100644 --- a/src/sardana/pool/controller.py +++ b/src/sardana/pool/controller.py @@ -661,6 +661,7 @@ class Loadable(object): .. note: Do not inherit directly from Loadable.""" + #: axis of the default timer default_timer = None def PrepareOne(self, axis, value, repetitions, latency, nb_starts): From de1ef08f97f67e3a0ec6e8c744513a49482feb72 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 18:55:09 +0100 Subject: [PATCH 614/652] Change ScanFileDir to ScanFilePath According to macro documentation change the parameter names and internal variables. --- src/sardana/macroserver/macros/standard.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index ff74a8064b..dd7a7e1c30 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -897,9 +897,12 @@ def run(self, nr, macro_name_params): class newfile(Hookable, Macro): """ Sets the ScanDir and ScanFile as well as ScanID in the environment. - If ScanFilePath is only a file name, the ScanDir must be set externally via - senv ScanDir PathToScanFile or using the %expconf. Otherwise, the path in - ScanFilePath must be absolute and existing on the MacroServer host. + + If ScanFilePath is only a file name, the ScanDir must be set externally + via `senv ScanDir ` or using the %expconf. Otherwise, + the path in ScanFilePath must be absolute and existing on the + MacroServer host. + The ScanID should be set to the value before the upcoming scan number. Default value is 0. """ @@ -907,20 +910,20 @@ class newfile(Hookable, Macro): hints = {'allowsHooks': ('post-newfile')} param_def = [ - ['ScanFileDir_list', - ParamRepeat(['ScanFileDir', Type.String, None, + ['ScanFilePath_list', + ParamRepeat(['ScanFilePath', Type.String, None, '(ScanDir/)ScanFile']), None, 'List of (ScanDir/)ScanFile'], ['ScanID', Type.Integer, -1, 'Scan ID'], ] - def run(self, ScanFileDir_list, ScanID): + def run(self, ScanFilePath_list, ScanID): path_list = [] fileName_list = [] # traverse the repeat parameters for the ScanFilePath_list - for i, ScanFileDir in enumerate(ScanFileDir_list): - path = os.path.dirname(ScanFileDir) - fileName = os.path.basename(ScanFileDir) + for i, ScanFilePath in enumerate(ScanFilePath_list): + path = os.path.dirname(ScanFilePath) + fileName = os.path.basename(ScanFilePath) if not path and i == 0: # first entry and no given ScanDir: check if ScanDir exists try: From cee40b4c12fc1bfd9b18e1787f45aabb08ae2688 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 18:57:00 +0100 Subject: [PATCH 615/652] Use new API for repeat parameters --- src/sardana/macroserver/macros/standard.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index dd7a7e1c30..ea8a0568fc 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -911,8 +911,7 @@ class newfile(Hookable, Macro): param_def = [ ['ScanFilePath_list', - ParamRepeat(['ScanFilePath', Type.String, None, - '(ScanDir/)ScanFile']), + [['ScanFilePath', Type.String, None, '(ScanDir/)ScanFile']], None, 'List of (ScanDir/)ScanFile'], ['ScanID', Type.Integer, -1, 'Scan ID'], ] From 4d129049441dbfd67dc26281695ab7009cfe460e Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 18:59:25 +0100 Subject: [PATCH 616/652] Change ScanID default value to 0 According to the documentation the ScanID default value shuold be 0 --- src/sardana/macroserver/macros/standard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index ea8a0568fc..0a039ddba2 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -913,7 +913,7 @@ class newfile(Hookable, Macro): ['ScanFilePath_list', [['ScanFilePath', Type.String, None, '(ScanDir/)ScanFile']], None, 'List of (ScanDir/)ScanFile'], - ['ScanID', Type.Integer, -1, 'Scan ID'], + ['ScanID', Type.Integer, 0, 'Scan ID'], ] def run(self, ScanFilePath_list, ScanID): From db4a15621dfd95e25ea94ebdf1397e95ed820ef0 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 19:30:37 +0100 Subject: [PATCH 617/652] Improve protection of unknown or wrong ScanDir --- src/sardana/macroserver/macros/standard.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index 0a039ddba2..3dbc83a221 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -40,7 +40,7 @@ from sardana.macroserver.macro import Macro, macro, Type, ParamRepeat, \ ViewOption, iMacro, Hookable -from sardana.macroserver.msexception import StopException +from sardana.macroserver.msexception import StopException, UnknownEnv from sardana.macroserver.scan.scandata import Record from sardana.macroserver.macro import Optional @@ -927,13 +927,14 @@ def run(self, ScanFilePath_list, ScanID): # first entry and no given ScanDir: check if ScanDir exists try: ScanDir = self.getEnv('ScanDir') - except: + except UnknownEnv: ScanDir = '' - if not ScanDir: - self.warning('Data is not stored until ScanDir is set! ' - 'Provide ScanDir with newfile macro: ' - 'newfile [/] or ' - 'senv ScanDir or with %expconf') + if not (isinstance(ScanDir, basestring) and len(ScanDir) > 0): + msg = ('Data is not stored until ScanDir is correctly ' + 'set! Provide ScanDir with newfile macro: ' + '`newfile [/] ` ' + 'or `senv ScanDir ` or with %expconf') + self.warning(msg) else: path = ScanDir elif not path and i > 0: From 6095c7a661c8f0dc83f07826a9f2bb86faf20c64 Mon Sep 17 00:00:00 2001 From: zreszela Date: Wed, 6 Feb 2019 19:33:09 +0100 Subject: [PATCH 618/652] Return in case ScanDir is unknown --- src/sardana/macroserver/macros/standard.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py index 3dbc83a221..1354c13729 100644 --- a/src/sardana/macroserver/macros/standard.py +++ b/src/sardana/macroserver/macros/standard.py @@ -934,7 +934,8 @@ def run(self, ScanFilePath_list, ScanID): 'set! Provide ScanDir with newfile macro: ' '`newfile [/] ` ' 'or `senv ScanDir ` or with %expconf') - self.warning(msg) + self.error(msg) + return else: path = ScanDir elif not path and i > 0: From 6aa7b00efd6de41a642018dea95bf96a647751f0 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 6 Feb 2019 19:57:35 +0100 Subject: [PATCH 619/652] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f69e64e843..9e51922f43 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,12 @@ This file follows the formats and conventions from [keepachangelog.com] ### Added +* `newfile` macro for setting `ScanDir`, `ScanFile` and `ScanID` env variables (#777) + ## [2.6.1] 2019-02-04 +This is a special release for meeting the deadline of debian buster freeze (debian 10). + ### Fixed - String parameter editor in macroexecutor and sequencer (#1030, #1031) - Documentation on differences between `Hookable.hooks` and `Hookable.appendHook` @@ -16,6 +20,8 @@ This file follows the formats and conventions from [keepachangelog.com] ## [2.6.0] 2019-01-31 +This is a special release for meeting the deadline of debian buster freeze (debian 10). + ### Added - New acquisition and synchronization concepts (SEP18, #773): - Preparation of measurement group for a group of acquisitions is mandatory From 2db28769b42678959b80b33c9a6e7af1f57e88b2 Mon Sep 17 00:00:00 2001 From: Daniel Roldan Date: Thu, 7 Feb 2019 09:48:12 +0100 Subject: [PATCH 620/652] Include PreScanSnapshot as allowed envEvent --- .../qt/qtcore/tango/sardana/macroserver.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index f8d5331895..66fcfe8a63 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -32,7 +32,8 @@ from taurus.core.taurusbasetypes import TaurusEventType from taurus.external.qt import Qt -from sardana.taurus.core.tango.sardana.macroserver import BaseMacroServer, BaseDoor +from sardana.taurus.core.tango.sardana.macroserver import BaseMacroServer, \ + BaseDoor CHANGE_EVTS = TaurusEventType.Change, TaurusEventType.Periodic @@ -44,7 +45,7 @@ class QDoor(BaseDoor, Qt.QObject): __pyqtSignals__ += ["%sUpdated" % l.lower() for l in BaseDoor.log_streams] envExpConfigChangesAllowed = ['ActiveMntGrp', 'ScanDir', 'ScanFile', - 'DataCompressionRank'] + 'DataCompressionRank', 'PreScanSnapshot'] # sometimes we emit None hence the type is object # (but most of the data are passed with type list) @@ -247,7 +248,8 @@ def setError(self, err_type=None, err_value=None, err_traceback=None): msg = "
    %s
    " % err_value msgbox.setDetailedHtml(msg) - html_orig = """""" + html_orig = """""" exc_info = "".join(err_traceback) style = "" try: @@ -264,13 +266,16 @@ def setError(self, err_type=None, err_value=None, err_traceback=None): else: formatter = pygments.formatters.HtmlFormatter() html += pygments.highlight(exc_info, - pygments.lexers.PythonTracebackLexer(), formatter) + pygments.lexers.PythonTracebackLexer( + + ), formatter) html += "" msgbox.setOriginHtml(html) def registerExtensions(): - """Registers the macroserver extensions in the :class:`taurus.core.tango.TangoFactory`""" + """Registers the macroserver extensions in the + :class:taurus.core.tango.TangoFactory`""" import taurus factory = taurus.Factory() factory.registerDeviceClass('MacroServer', QMacroServer) @@ -280,8 +285,8 @@ def registerExtensions(): # handlers, maybe in TangoFactory & TaurusManager import sardana.taurus.core.tango.sardana.macro import taurus.qt.qtgui.panel - MacroRunException = sardana.taurus.core.tango.sardana.macro.MacroRunException + MacroRunExcep = sardana.taurus.core.tango.sardana.macro.MacroRunException TaurusMessagePanel = taurus.qt.qtgui.panel.TaurusMessagePanel - TaurusMessagePanel.registerErrorHandler( - MacroRunException, MacroServerMessageErrorHandler) + TaurusMessagePanel.registerErrorHandler(MacroRunExcep, + MacroServerMessageErrorHandler) From f21ffb0c6a9badd2ea405fe2054e83b0da8aa372 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 7 Feb 2019 10:24:29 +0100 Subject: [PATCH 621/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e51922f43..760ad4ecfb 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ This file follows the formats and conventions from [keepachangelog.com] ### Added +* Possibility to directly acquire an experimental channel (without the need to define + a measurement group) (#185, #997) * `newfile` macro for setting `ScanDir`, `ScanFile` and `ScanID` env variables (#777) ## [2.6.1] 2019-02-04 From c1217639e29fc75e8588516bcc600582c5a13547 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 7 Feb 2019 10:26:36 +0100 Subject: [PATCH 622/652] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 760ad4ecfb..5fee9f7830 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ This file follows the formats and conventions from [keepachangelog.com] * Possibility to directly acquire an experimental channel (without the need to define a measurement group) (#185, #997) + * `IntegrationTime` (Tango) and `integration_time` (core) attributes to all experimental + channels + * `Timer` (Tango) and `timer` (core) attribute to all timerable experimental channels * `newfile` macro for setting `ScanDir`, `ScanFile` and `ScanID` env variables (#777) ## [2.6.1] 2019-02-04 From 14a7afb0b304d8fe82dc0fda968ce72a8966a80b Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 7 Feb 2019 10:27:37 +0100 Subject: [PATCH 623/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fee9f7830..5fd67e2150 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ This file follows the formats and conventions from [keepachangelog.com] * `IntegrationTime` (Tango) and `integration_time` (core) attributes to all experimental channels * `Timer` (Tango) and `timer` (core) attribute to all timerable experimental channels + * `default_timer` class attribute to all timerable controllers (plugins) to let them + announce the default timer axis * `newfile` macro for setting `ScanDir`, `ScanFile` and `ScanID` env variables (#777) ## [2.6.1] 2019-02-04 From 351e300389f78f6901678b6c6400ca58f9a37d9e Mon Sep 17 00:00:00 2001 From: teresa Date: Thu, 7 Feb 2019 11:21:50 +0100 Subject: [PATCH 624/652] Keeping moveable as None in the kernel events --- src/sardana/pool/poolmeasurementgroup.py | 2 -- src/sardana/tango/pool/MeasurementGroup.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index 0dd816b1aa..a99312a169 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -1075,8 +1075,6 @@ def set_moveable(self, moveable, propagate=1, to_fqdn=True): moveable = _to_fqdn(moveable, logger=self) self._moveable_obj = self.pool.get_element_by_full_name(moveable) - if moveable is None: - moveable = 'None' self.fire_event(EventType("moveable", priority=propagate), moveable) diff --git a/src/sardana/tango/pool/MeasurementGroup.py b/src/sardana/tango/pool/MeasurementGroup.py index d11deab01d..1556926e2b 100644 --- a/src/sardana/tango/pool/MeasurementGroup.py +++ b/src/sardana/tango/pool/MeasurementGroup.py @@ -141,6 +141,8 @@ def _on_measurement_group_changed(self, event_source, event_type, elif name == "synchronization": codec = CodecFactory().getCodec('json') _, event_value = codec.encode(('', event_value)) + elif name == "moveable" and value == None: + value = 'None' else: if isinstance(event_value, SardanaAttribute): if event_value.error: From 3b676adf6c43ee3af7d9b1676095089b5ae06b8e Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 7 Feb 2019 11:56:11 +0100 Subject: [PATCH 625/652] Fix bug: use correct variable name Also fix comparison to None --- src/sardana/tango/pool/MeasurementGroup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sardana/tango/pool/MeasurementGroup.py b/src/sardana/tango/pool/MeasurementGroup.py index 1556926e2b..7daadbe3be 100644 --- a/src/sardana/tango/pool/MeasurementGroup.py +++ b/src/sardana/tango/pool/MeasurementGroup.py @@ -141,8 +141,8 @@ def _on_measurement_group_changed(self, event_source, event_type, elif name == "synchronization": codec = CodecFactory().getCodec('json') _, event_value = codec.encode(('', event_value)) - elif name == "moveable" and value == None: - value = 'None' + elif name == "moveable" and event_value is None: + event_value = 'None' else: if isinstance(event_value, SardanaAttribute): if event_value.error: From 236b06808a26d93772a84cf478a603937f0287ae Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 7 Feb 2019 11:58:06 +0100 Subject: [PATCH 626/652] Fix flake8 --- src/sardana/pool/poolmeasurementgroup.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py index a99312a169..dca9807fc6 100644 --- a/src/sardana/pool/poolmeasurementgroup.py +++ b/src/sardana/pool/poolmeasurementgroup.py @@ -1074,10 +1074,8 @@ def set_moveable(self, moveable, propagate=1, to_fqdn=True): if to_fqdn: moveable = _to_fqdn(moveable, logger=self) self._moveable_obj = self.pool.get_element_by_full_name(moveable) - self.fire_event(EventType("moveable", priority=propagate), moveable) - moveable = property(get_moveable, set_moveable, doc="moveable source used in synchronization") From cb1088629a91cbc7f767c2a3b07cfc027280cdf3 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 7 Feb 2019 12:22:45 +0100 Subject: [PATCH 627/652] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fd67e2150..f6b5b31d73 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ This file follows the formats and conventions from [keepachangelog.com] announce the default timer axis * `newfile` macro for setting `ScanDir`, `ScanFile` and `ScanID` env variables (#777) +### Fixed + +* MeasurementGroup's Moveable attribute when set to "None" in Tango is used as None + in the core (#1001) + ## [2.6.1] 2019-02-04 This is a special release for meeting the deadline of debian buster freeze (debian 10). From c0d3414860d883a757b729a8edff11302d72df1c Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 7 Feb 2019 13:04:50 +0100 Subject: [PATCH 628/652] Refactor code * rename variables * improve documentation * remove error handling --- .../qt/qtcore/tango/sardana/macroserver.py | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py index 66fcfe8a63..45168b9142 100644 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -44,8 +44,8 @@ class QDoor(BaseDoor, Qt.QObject): "recordDataUpdated", "macroStatusUpdated"] __pyqtSignals__ += ["%sUpdated" % l.lower() for l in BaseDoor.log_streams] - envExpConfigChangesAllowed = ['ActiveMntGrp', 'ScanDir', 'ScanFile', - 'DataCompressionRank', 'PreScanSnapshot'] + EXP_DESC_ENV_VARS = ['ActiveMntGrp', 'ScanDir', 'ScanFile', + 'DataCompressionRank', 'PreScanSnapshot'] # sometimes we emit None hence the type is object # (but most of the data are passed with type list) @@ -103,7 +103,7 @@ def _prepare_connections(self): if not self._use_experiment_configuration and \ not self._connections_prepared: self.macro_server.environmentChanged.connect( - self._onExperimentConfigurationEnvironmentChanged) + self._onEnvironmentChanged) self.macro_server.elementsChanged.connect(self._elementsChanged) self._elementsChanged() self._connections_prepared = True @@ -125,36 +125,29 @@ def _elementsChanged(self): if mntgrp_changed: self._onExperimentConfigurationChanged() - def _onExperimentConfigurationEnvironmentChanged(self, args): + def _onEnvironmentChanged(self, env_changes): """ Filter environment changes that affect to the experiment configuration. + :param env_changes: tuple with three elements in the following order: - :param args: - The args order is : - added (environment added) - removed (environment removed) - changed (environment changed) - :return: - """ - - try: - envExpChanged = False - # Filter only the Environment added/removed/changes related with - # the experiment, not for all. - for envs in args: - val = envs.intersection(self.envExpConfigChangesAllowed) - if len(val) > 1: - envExpChanged = True - break - - if not envExpChanged: - return - except Exception as e: - print e - pass + * added (environment variables added) + * removed (environment variables removed) + * changed (environment variables changed) + :type env_changes: :obj:`tuple` + """ + env_exp_changed = False + # Filter only the Environment added/removed/changes related with + # the experiment, not for all. + for envs in env_changes: + val = envs.intersection(self.EXP_DESC_ENV_VARS) + if len(val) > 0: + env_exp_changed = True + break + if not env_exp_changed: + return self._onExperimentConfigurationChanged() def _onExperimentConfigurationChanged(self, *args): From f6d23e34420c5636e178fb4c095c65278acbb6d7 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 7 Feb 2019 13:05:09 +0100 Subject: [PATCH 629/652] Fix flake8 --- src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py old mode 100644 new mode 100755 index 45168b9142..af882eddc1 --- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py +++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py @@ -248,7 +248,7 @@ def setError(self, err_type=None, err_value=None, err_traceback=None): try: import pygments.formatters import pygments.lexers - except: + except Exception: pygments = None if pygments is not None: formatter = pygments.formatters.HtmlFormatter() From c877a7ca63100dd48bb94c023110db384bebcf24 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 7 Feb 2019 15:10:47 +0100 Subject: [PATCH 630/652] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6b5b31d73..c8951b3519 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ This file follows the formats and conventions from [keepachangelog.com] ### Fixed +* `expconf` warns only about the following environment variables changes: `ScanFile`, + `ScanDir`, `ActiveMntGrp`, `PreScanSnapshot` and `DataCompressionRank` (#1040) * MeasurementGroup's Moveable attribute when set to "None" in Tango is used as None in the core (#1001) From 85a8bb7fdad912ab10c542bc6f67a4b80cac5e99 Mon Sep 17 00:00:00 2001 From: zreszela Date: Thu, 7 Feb 2019 15:46:38 +0100 Subject: [PATCH 631/652] Add newfile to standard macro catalog --- doc/source/users/standard_macro_catalog.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/source/users/standard_macro_catalog.rst b/doc/source/users/standard_macro_catalog.rst index 35e7cf22b3..1d5a7207f7 100644 --- a/doc/source/users/standard_macro_catalog.rst +++ b/doc/source/users/standard_macro_catalog.rst @@ -202,3 +202,11 @@ scan macros * :class:`~sardana.macroserver.macros.scan.d2scanct` * :class:`~sardana.macroserver.macros.scan.d3scanct` * :class:`~sardana.macroserver.macros.scan.d4scanct` + +scan related macros +------------------- + +.. hlist:: + :columns: 5 + + * :class:`~sardana.macroserver.macros.standard.newfile` From 49295ba57083b70de03f2bc3e00c731ee97f1556 Mon Sep 17 00:00:00 2001 From: teresa Date: Fri, 8 Feb 2019 13:43:18 +0100 Subject: [PATCH 632/652] Setting release number --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8951b3519..cd0bbcffd1 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). This file follows the formats and conventions from [keepachangelog.com] -## [Unreleased] +## [2.7.0] 2019-02-08 ### Added From f27ab4cab844321fddd8fbabf6af6bcc568d1fe5 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Mon, 18 Feb 2019 15:06:28 +0100 Subject: [PATCH 633/652] Bump version 2.6.3-alpha to 2.7.0-alpha --- .bumpversion.cfg | 2 +- src/sardana/release.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index ece9e34534..8f8dd8d5b5 100755 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ commit = True message = Bump version {current_version} to {new_version} tag = False tag_name = {new_version} -current_version = 2.6.3-alpha +current_version = 2.7.0-alpha parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} diff --git a/src/sardana/release.py b/src/sardana/release.py index 597cf8621c..6585941a60 100644 --- a/src/sardana/release.py +++ b/src/sardana/release.py @@ -47,7 +47,7 @@ # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '2.6.3-alpha' +version = '2.7.0-alpha' # generate version_info and revision (**deprecated** since v 2.1.2--alpha). if '-' in version: From c9195b7726d6dfef3d9b304f0566e55b302e5040 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Mon, 18 Feb 2019 15:06:28 +0100 Subject: [PATCH 634/652] Bump version 2.7.0-alpha to 2.7.0 --- .bumpversion.cfg | 2 +- src/sardana/release.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 8f8dd8d5b5..3c6abc7edb 100755 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ commit = True message = Bump version {current_version} to {new_version} tag = False tag_name = {new_version} -current_version = 2.7.0-alpha +current_version = 2.7.0 parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} diff --git a/src/sardana/release.py b/src/sardana/release.py index 6585941a60..521b44bbb7 100644 --- a/src/sardana/release.py +++ b/src/sardana/release.py @@ -47,7 +47,7 @@ # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '2.7.0-alpha' +version = '2.7.0' # generate version_info and revision (**deprecated** since v 2.1.2--alpha). if '-' in version: From c8482e3b5fa974b0367f0e3d34e77fa524262697 Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Mon, 18 Feb 2019 16:41:51 +0100 Subject: [PATCH 635/652] update manpages --- doc/man/MacroServer.1 | 6 +++--- doc/man/Pool.1 | 6 +++--- doc/man/Sardana.1 | 6 +++--- doc/man/diffractometeralignment.1 | 6 +++--- doc/man/hklscan.1 | 6 +++--- doc/man/macroexecutor.1 | 6 +++--- doc/man/sardanatestsuite.1 | 6 +++--- doc/man/sequencer.1 | 6 +++--- doc/man/spock.1 | 4 ++-- doc/man/ubmatrix.1 | 6 +++--- 10 files changed, 29 insertions(+), 29 deletions(-) diff --git a/doc/man/MacroServer.1 b/doc/man/MacroServer.1 index cb4b562354..4999b65801 100644 --- a/doc/man/MacroServer.1 +++ b/doc/man/MacroServer.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH MACROSERVER "1" "February 2019" "MacroServer 2.6.2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH MACROSERVER "1" "February 2019" "MacroServer 2.7.0" "User Commands" .SH NAME -MacroServer \- manual page for MacroServer 2.6.2 +MacroServer \- manual page for MacroServer 2.7.0 .SH SYNOPSIS .B usage: \fI\,MacroServer instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/Pool.1 b/doc/man/Pool.1 index 70155acde4..9ff11a4bc1 100644 --- a/doc/man/Pool.1 +++ b/doc/man/Pool.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH POOL "1" "February 2019" "Pool 2.6.2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH POOL "1" "February 2019" "Pool 2.7.0" "User Commands" .SH NAME -Pool \- manual page for Pool 2.6.2 +Pool \- manual page for Pool 2.7.0 .SH SYNOPSIS .B usage: \fI\,Pool instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/Sardana.1 b/doc/man/Sardana.1 index 6480a5e55f..b8f64980f3 100644 --- a/doc/man/Sardana.1 +++ b/doc/man/Sardana.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SARDANA "1" "February 2019" "Sardana 2.6.2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH SARDANA "1" "February 2019" "Sardana 2.7.0" "User Commands" .SH NAME -Sardana \- manual page for Sardana 2.6.2 +Sardana \- manual page for Sardana 2.7.0 .SH SYNOPSIS .B usage: \fI\,Sardana instance_name \/\fR[\fI\,options\/\fR] diff --git a/doc/man/diffractometeralignment.1 b/doc/man/diffractometeralignment.1 index 7f8358cf47..d42d20178f 100644 --- a/doc/man/diffractometeralignment.1 +++ b/doc/man/diffractometeralignment.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH DIFFRACTOMETERALIGNMENT "1" "February 2019" "diffractometeralignment 2.6.2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH DIFFRACTOMETERALIGNMENT "1" "February 2019" "diffractometeralignment 2.7.0" "User Commands" .SH NAME -diffractometeralignment \- manual page for diffractometeralignment 2.6.2 +diffractometeralignment \- manual page for diffractometeralignment 2.7.0 .SH SYNOPSIS .B diffractometeralignment \fI\, \/\fR[\fI\,door_name\/\fR] diff --git a/doc/man/hklscan.1 b/doc/man/hklscan.1 index ff1a4e8eaa..7fab5d20d1 100644 --- a/doc/man/hklscan.1 +++ b/doc/man/hklscan.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH HKLSCAN "1" "February 2019" "hklscan 2.6.2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH HKLSCAN "1" "February 2019" "hklscan 2.7.0" "User Commands" .SH NAME -hklscan \- manual page for hklscan 2.6.2 +hklscan \- manual page for hklscan 2.7.0 .SH SYNOPSIS .B hklscan \fI\, \/\fR[\fI\,door_name\/\fR] diff --git a/doc/man/macroexecutor.1 b/doc/man/macroexecutor.1 index 15178a970c..08995d5bb6 100644 --- a/doc/man/macroexecutor.1 +++ b/doc/man/macroexecutor.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH MACROEXECUTOR "1" "February 2019" "macroexecutor 2.6.2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH MACROEXECUTOR "1" "February 2019" "macroexecutor 2.7.0" "User Commands" .SH NAME -macroexecutor \- manual page for macroexecutor 2.6.2 +macroexecutor \- manual page for macroexecutor 2.7.0 .SH SYNOPSIS .B macroexecutor [\fI\,options\/\fR] diff --git a/doc/man/sardanatestsuite.1 b/doc/man/sardanatestsuite.1 index c8891e87f3..0a92987164 100644 --- a/doc/man/sardanatestsuite.1 +++ b/doc/man/sardanatestsuite.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SARDANATESTSUITE "1" "February 2019" "sardanatestsuite 2.6.2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH SARDANATESTSUITE "1" "February 2019" "sardanatestsuite 2.7.0" "User Commands" .SH NAME -sardanatestsuite \- manual page for sardanatestsuite 2.6.2 +sardanatestsuite \- manual page for sardanatestsuite 2.7.0 .SH DESCRIPTION usage: sardanatestsuite [\-h] [\-e EXCLUDE_PATTERN] [\-\-version] .PP diff --git a/doc/man/sequencer.1 b/doc/man/sequencer.1 index 97e1835ab5..1d8adc66b3 100644 --- a/doc/man/sequencer.1 +++ b/doc/man/sequencer.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SEQUENCER "1" "February 2019" "sequencer 2.6.2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH SEQUENCER "1" "February 2019" "sequencer 2.7.0" "User Commands" .SH NAME -sequencer \- manual page for sequencer 2.6.2 +sequencer \- manual page for sequencer 2.7.0 .SH SYNOPSIS .B sequencer [\fI\,options\/\fR] diff --git a/doc/man/spock.1 b/doc/man/spock.1 index f8d35389b5..677f7b8f62 100644 --- a/doc/man/spock.1 +++ b/doc/man/spock.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH SPOCK "1" "February 2019" "spock 2.6.2" "User Commands" +.TH SPOCK "1" "February 2019" "spock 2.7.0" "User Commands" .SH NAME -spock \- manual page for spock 2.6.2 +spock \- manual page for spock 2.7.0 .SH DESCRIPTION ========= .IP diff --git a/doc/man/ubmatrix.1 b/doc/man/ubmatrix.1 index e4a7160177..caaf39b711 100644 --- a/doc/man/ubmatrix.1 +++ b/doc/man/ubmatrix.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH UBMATRIX "1" "February 2019" "ubmatrix 2.6.2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. +.TH UBMATRIX "1" "February 2019" "ubmatrix 2.7.0" "User Commands" .SH NAME -ubmatrix \- manual page for ubmatrix 2.6.2 +ubmatrix \- manual page for ubmatrix 2.7.0 .SH SYNOPSIS .B ubmatrix \fI\,\/\fR From 154674d7e35ba936bc4f950636eac15655b6819b Mon Sep 17 00:00:00 2001 From: Grzegorz Kowalski Date: Mon, 18 Feb 2019 16:47:48 +0100 Subject: [PATCH 636/652] update deprecation warnings --- src/sardana/pool/poolacquisition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py index 527935bae1..e5b42c711d 100644 --- a/src/sardana/pool/poolacquisition.py +++ b/src/sardana/pool/poolacquisition.py @@ -725,7 +725,7 @@ def load(channel, value, repetitions, latency=0): try: res = ctrl.PreLoadOne(axis, value, repetitions) msg = ("PreLoadOne(axis, value, repetitions) is " - "deprecated since version Jan19. Use PreLoadOne(" + "deprecated since version 2.7.0. Use PreLoadOne(" "axis, value, repetitions, latency_time) instead.") self.warning(msg) except TypeError: From 61e8bee6dc3dfd47a036d01d19b22a1f257d818f Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 19 Feb 2019 18:44:55 +0100 Subject: [PATCH 637/652] Remove ms properties file in tests correctly on Windows --- src/sardana/tango/macroserver/test/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sardana/tango/macroserver/test/base.py b/src/sardana/tango/macroserver/test/base.py index 12efbaa72d..653ca0e257 100644 --- a/src/sardana/tango/macroserver/test/base.py +++ b/src/sardana/tango/macroserver/test/base.py @@ -97,6 +97,7 @@ def tearDown(self): ds_inst_name = self.ms_ds_name.split("/")[1] ms_properties = dft_ms_properties % {"ds_exec_name": "MacroServer", "ds_inst_name": ds_inst_name} + ms_properties = os.path.normpath(ms_properties) os.remove(ms_properties) self._msstarter.cleanDb(force=True) self._msstarter = None From da16b2a552f998d85f7e17b75e721945fd88b644 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Wed, 20 Feb 2019 16:21:33 +0100 Subject: [PATCH 638/652] Update how_to_release.md --- doc/how_to_release.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/how_to_release.md b/doc/how_to_release.md index 757332b593..cc84e0ce1f 100644 --- a/doc/how_to_release.md +++ b/doc/how_to_release.md @@ -112,8 +112,7 @@ Hint: this list can be used as a template to be copy-pasted on a release manual attribute. - [ ] Add the `sys/tg_test/1/double_scalar` attribute to the measurement group. -- [ ] Open online plot. -- [ ] Set JsonRecorder to true. In spock do `senv JsonRecorder True` +- [ ] Open online plot (This should ask to enable JsonRecorder, set it to true. Otherwise enable it in spock: `senv JsonRecorder True`). - [ ] Run step scan - [ ] Verify that records appear in spock output. - [ ] Verify that records were stored in scan files. From 7e6a41747c08496ba807076817470fd6ddd2ca2d Mon Sep 17 00:00:00 2001 From: reszelaz Date: Tue, 26 Feb 2019 17:09:41 +0100 Subject: [PATCH 639/652] Bump taurus requires to 3.11 --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 1078245737..f2f8634fe8 100644 --- a/setup.py +++ b/setup.py @@ -55,10 +55,10 @@ def get_release_info(): # when using PyTango < 9 the dependency is >= 0.0.1 and < 0.1.0 # when using PyTango >= 9 the dependency is >= 0.1.6 'itango (>=0.0.1)', - # for Taurus3 requires >= 3.10 (special version from + # for Taurus3 requires >= 3.11 (special version from # taurus-org/taurus@3.x-sdn2.5.1 branch) # for Taurus4 requires >= 4.5.0 - 'taurus (>= 3.10)', + 'taurus (>= 3.11)', 'lxml (>=2.1)', # ordereddict is necessary for Python < 2.6 'ordereddict' @@ -70,7 +70,7 @@ def get_release_info(): # for Taurus3 requires >= 3.10 (special version from # taurus-org/taurus@3.x-sdn2.5.1 branch) # for Taurus4 requires >= 4.5.0 - 'taurus>=3.10,!=4.0,!=4.1,!=4.3,!=4.4', + 'taurus>=3.11,!=4.0,!=4.1,!=4.3,!=4.4', 'lxml>=2.1' ] From 71a6db4effef21894e05b3467d175714bc82b6ca Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Fri, 22 Feb 2019 09:37:42 +0100 Subject: [PATCH 640/652] Merge pull request #1065 from cmft/fix-signalemit Fix wrong signal emit --- src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py index 9e1ecb2930..293332471c 100644 --- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py +++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py @@ -405,7 +405,7 @@ def onChooseScanDirButtonClicked(self): self, 'Choose directory for saving files', self.ui.pathLE.text()) if ret: self.ui.pathLE.setText(ret) - self.ui.pathLE.emit.textEdited.emit(ret) + self.ui.pathLE.textEdited.emit(ret) def onDialogButtonClicked(self, button): role = self.ui.buttonBox.buttonRole(button) From 7dcab6364e28fd76d3734e7f2f163d44fab3b8e7 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 28 Feb 2019 11:46:01 +0100 Subject: [PATCH 641/652] Remove ms_properties file after stopping MS To avoid problems in windows, remove the macroserver properties file after having stopped the MacroServer DS. --- src/sardana/tango/macroserver/test/base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sardana/tango/macroserver/test/base.py b/src/sardana/tango/macroserver/test/base.py index 653ca0e257..ef1d4dd40c 100644 --- a/src/sardana/tango/macroserver/test/base.py +++ b/src/sardana/tango/macroserver/test/base.py @@ -95,14 +95,14 @@ def tearDown(self): dft_ms_properties = os.path.join(MacroServerClass.DefaultEnvBaseDir, MacroServerClass.DefaultEnvRelDir) ds_inst_name = self.ms_ds_name.split("/")[1] - ms_properties = dft_ms_properties % {"ds_exec_name": "MacroServer", - "ds_inst_name": ds_inst_name} - ms_properties = os.path.normpath(ms_properties) - os.remove(ms_properties) self._msstarter.cleanDb(force=True) self._msstarter = None self.macroserver = None self.door = None + ms_properties = dft_ms_properties % {"ds_exec_name": "MacroServer", + "ds_inst_name": ds_inst_name} + ms_properties = os.path.normpath(ms_properties) + os.remove(ms_properties) if __name__ == '__main__': From a227cd15c94a2df0a4251718b5af649be706e867 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 28 Feb 2019 12:29:32 +0100 Subject: [PATCH 642/652] clear the event set, before macro commnads Clear the event set before running execution and before macro stop/abort. This is solving bugs found in Windows, where the spock prompt was returned before expected, as events arrived with the same timestamp, cause of poor time resolution of python on windows. --- src/sardana/taurus/core/tango/sardana/macroserver.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sardana/taurus/core/tango/sardana/macroserver.py b/src/sardana/taurus/core/tango/sardana/macroserver.py index 795cbc73a7..a24f37f106 100644 --- a/src/sardana/taurus/core/tango/sardana/macroserver.py +++ b/src/sardana/taurus/core/tango/sardana/macroserver.py @@ -458,6 +458,7 @@ def abort(self, synch=True): evt_wait.lock() try: time_stamp = time.time() + evt_wait.clearEventSet() self.command_inout("AbortMacro") evt_wait.waitEvent(self.Running, equal=False, after=time_stamp, timeout=self.InteractiveTimeout) @@ -474,6 +475,7 @@ def stop(self, synch=True): evt_wait.lock() try: time_stamp = time.time() + evt_wait.clearEventSet() self.command_inout("StopMacro") evt_wait.waitEvent(self.Running, equal=False, after=time_stamp, timeout=self.InteractiveTimeout) @@ -556,6 +558,7 @@ def _runMacro(self, xml, synch=False): try: evt_wait.waitEvent(self.Running, equal=False, timeout=timeout) ts = time.time() + evt_wait.clearEventSet() result = self.command_inout("RunMacro", [etree.tostring(xml)]) evt_wait.waitEvent(self.Running, after=ts, timeout=timeout) if synch: From bf671b415b25c4cd3389d69382f4249a87b975c5 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Thu, 28 Feb 2019 14:37:41 +0100 Subject: [PATCH 643/652] Get the time_stamp just before the macro commands Get the time_stamp just before execution of macro commands used for run, stop and abort a macro. --- src/sardana/taurus/core/tango/sardana/macroserver.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macroserver.py b/src/sardana/taurus/core/tango/sardana/macroserver.py index a24f37f106..04381163bd 100644 --- a/src/sardana/taurus/core/tango/sardana/macroserver.py +++ b/src/sardana/taurus/core/tango/sardana/macroserver.py @@ -457,8 +457,8 @@ def abort(self, synch=True): evt_wait = AttributeEventWait(self.getAttribute("state")) evt_wait.lock() try: - time_stamp = time.time() evt_wait.clearEventSet() + time_stamp = time.time() self.command_inout("AbortMacro") evt_wait.waitEvent(self.Running, equal=False, after=time_stamp, timeout=self.InteractiveTimeout) @@ -474,8 +474,8 @@ def stop(self, synch=True): evt_wait = AttributeEventWait(self.getAttribute("state")) evt_wait.lock() try: - time_stamp = time.time() evt_wait.clearEventSet() + time_stamp = time.time() self.command_inout("StopMacro") evt_wait.waitEvent(self.Running, equal=False, after=time_stamp, timeout=self.InteractiveTimeout) @@ -557,8 +557,8 @@ def _runMacro(self, xml, synch=False): evt_wait.lock() try: evt_wait.waitEvent(self.Running, equal=False, timeout=timeout) - ts = time.time() evt_wait.clearEventSet() + ts = time.time() result = self.command_inout("RunMacro", [etree.tostring(xml)]) evt_wait.waitEvent(self.Running, after=ts, timeout=timeout) if synch: From 3c54c7dd4989329a7df252c65fa6dca949f0df58 Mon Sep 17 00:00:00 2001 From: reszelaz Date: Thu, 28 Feb 2019 16:18:50 +0100 Subject: [PATCH 644/652] Bump taurus requires to 3.12 --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index f2f8634fe8..43d54bc37c 100644 --- a/setup.py +++ b/setup.py @@ -55,10 +55,10 @@ def get_release_info(): # when using PyTango < 9 the dependency is >= 0.0.1 and < 0.1.0 # when using PyTango >= 9 the dependency is >= 0.1.6 'itango (>=0.0.1)', - # for Taurus3 requires >= 3.11 (special version from + # for Taurus3 requires >= 3.12 (special version from # taurus-org/taurus@3.x-sdn2.5.1 branch) # for Taurus4 requires >= 4.5.0 - 'taurus (>= 3.11)', + 'taurus (>= 3.12)', 'lxml (>=2.1)', # ordereddict is necessary for Python < 2.6 'ordereddict' @@ -70,7 +70,7 @@ def get_release_info(): # for Taurus3 requires >= 3.10 (special version from # taurus-org/taurus@3.x-sdn2.5.1 branch) # for Taurus4 requires >= 4.5.0 - 'taurus>=3.11,!=4.0,!=4.1,!=4.3,!=4.4', + 'taurus>=3.12,!=4.0,!=4.1,!=4.3,!=4.4', 'lxml>=2.1' ] From 4c0ee7222c293b36f34aec6dc330dd1fd97b6aa6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Mar 2019 18:28:30 +0100 Subject: [PATCH 645/652] Avoid memory errors on testsuite execution Dummy 2D controller generates an array of zeros (1024x1024) for each axis, many axes may increase the VM memory consumption of testsuite and this apparently causes OSError: [Errno 12] Cannot allocate memory on the os.fork() call. Avoid this by just creating one axis of dummy 2D. --- src/sardana/pool/test/base.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sardana/pool/test/base.py b/src/sardana/pool/test/base.py index 19493afe0c..05bf3c7566 100644 --- a/src/sardana/pool/test/base.py +++ b/src/sardana/pool/test/base.py @@ -114,10 +114,14 @@ def createPMElement(self, ctrl_obj, name, axis, elements=[]): def setUp(self): """Create a collection of controllers and elements. """ - self.nctctrls = self.nzerodctrls = self.ntwodctrls = self.ntgctrls = \ - self.nmotctrls = 4 - self.nctelems = self.nzerodelems = self.ntwodelems = self.ntgelems = \ - self.nmotelems = 5 + self.nctctrls = self.nzerodctrls = self.ntgctrls = self.nmotctrls = 4 + # dummy controller generates an array of zeros (1024x1024) for each + # axis, many axes may increase the memory consumption of testsuite + self.ntwodctrls = 1 + self.nctelems = self.nzerodelems = self.ntgelems = self.nmotelems = 5 + # dummy controller generates an array of zeros (1024x1024) for each + # axis, many axes may increase the memory consumption of testsuite + self.ntwodelems = 1 self.pool = FakePool(self.POOLPATH, self.LOGLEVEL) # Use debug mode From f05d81efec72f25ddea75d7f3e4e2fb43d2047f6 Mon Sep 17 00:00:00 2001 From: zreszela Date: Fri, 1 Mar 2019 18:28:56 +0100 Subject: [PATCH 646/652] Fix some typos in variables names. --- src/sardana/pool/test/base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/pool/test/base.py b/src/sardana/pool/test/base.py index 05bf3c7566..3e5256f6fc 100644 --- a/src/sardana/pool/test/base.py +++ b/src/sardana/pool/test/base.py @@ -175,13 +175,13 @@ def setUp(self): name = '_test_tg_%s_%s' % (ctrl, axis) self.createTGElement(ctrl_obj, name, axis) # Create nctrls MOT ctrls - for ctrl in range(1, self.nctctrls + 1): + for ctrl in range(1, self.nmotctrls + 1): name = '_test_mot_ctrl_%s' % ctrl ctrl_obj = self.createController(name, 'DummyMotorController', 'DummyMotorController.py') # Create nelems CT elements for each ctrl - for axis in range(1, self.nctelems + 1): + for axis in range(1, self.nmotelems + 1): name = '_test_mot_%s_%s' % (ctrl, axis) self.createMotorElement(ctrl_obj, name, axis) @@ -190,7 +190,7 @@ def setUp(self): tgs = len(self.tgs.keys()) mots = len(self.mots.keys()) - expected_cts = self.ntgelems * self.ntgctrls + expected_cts = self.nctelems * self.nctctrls msg = 'Something happened during the creation of CT elements.\n' + \ 'Expected %s and there are %s, %s' % \ (expected_cts, cts, self.cts.keys()) From ad7dd9561c846352b489cf0a8bcfb2d5f6decb16 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Mon, 4 Mar 2019 12:05:27 +0100 Subject: [PATCH 647/652] Fix typo in test exception strings --- src/sardana/tango/pool/test/base_sartest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sardana/tango/pool/test/base_sartest.py b/src/sardana/tango/pool/test/base_sartest.py index 0c9531ef23..8fd8b3e65d 100644 --- a/src/sardana/tango/pool/test/base_sartest.py +++ b/src/sardana/tango/pool/test/base_sartest.py @@ -88,7 +88,7 @@ def setUp(self): except Exception, e: print e msg = 'Impossible to create ctrl: "%s"' % (ctrl_name) - raise Exception('Aborting SartestTesCase: %s' % (msg)) + raise Exception('Aborting SartestTestCase: %s' % (msg)) self.ctrl_list.append(ctrl_name) # create elements for axis in range(1, nelem + 1): @@ -100,7 +100,7 @@ def setUp(self): print e msg = 'Impossible to create element: "%s"' % ( elem_name) - raise Exception('Aborting SartestTesCase: %s' % (msg)) + raise Exception('Aborting SartestTestCase: %s' % (msg)) self.elem_list.append(elem_name) # pseudo controllers and elements for pseudo in self.pseudo_cls_list: @@ -115,7 +115,7 @@ def setUp(self): except Exception, e: print e msg = 'Impossible to create ctrl: "%s"' % (ctrl_name) - raise Exception('Aborting SartestTesCase: %s' % (msg)) + raise Exception('Aborting SartestTestCase: %s' % (msg)) self.ctrl_list.append(ctrl_name) for role in roles: elem = role.split("=")[1] From 28b0ff258a33daf9b48624aaf432fd24f045a23d Mon Sep 17 00:00:00 2001 From: Carlos Pascual Date: Mon, 4 Mar 2019 16:35:49 +0100 Subject: [PATCH 648/652] (m) change comments Change comments that were not properly adapted after a copy-paste --- src/sardana/pool/test/base.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sardana/pool/test/base.py b/src/sardana/pool/test/base.py index 3e5256f6fc..6308ff16e8 100644 --- a/src/sardana/pool/test/base.py +++ b/src/sardana/pool/test/base.py @@ -139,7 +139,7 @@ def setUp(self): ctrl_obj = self.createController(name, 'DummyCounterTimerController', 'DummyCounterTimerController.py') - # Create nelems CT elements for each ctrl + # Create nctelems CT elements for each ctrl for axis in range(1, self.nctelems + 1): name = '_test_ct_%s_%s' % (ctrl, axis) self.createCTElement(ctrl_obj, name, axis) @@ -149,7 +149,7 @@ def setUp(self): ctrl_obj = self.createController(name, 'DummyZeroDController', 'DummyZeroDController.py') - # Create nelems ZeroD elements for each ctrl + # Create nzerodelems ZeroD elements for each ctrl for axis in range(1, self.nzerodelems + 1): name = '_test_0d_%s_%s' % (ctrl, axis) self.createZeroDElement(ctrl_obj, name, axis) @@ -159,7 +159,7 @@ def setUp(self): ctrl_obj = self.createController(name, 'DummyTwoDController', 'DummyTwoDController.py') - # Create nelems TwoD elements for each ctrl + # Create ntwodelems TwoD elements for each ctrl for axis in range(1, self.ntwodelems + 1): name = '_test_2d_%s_%s' % (ctrl, axis) self.createTwoDElement(ctrl_obj, name, axis) @@ -170,17 +170,17 @@ def setUp(self): ctrl_obj = self.createController(name, 'DummyTriggerGateController', 'DummyTriggerGateController.py') - # Create nelems CT elements for each ctrl + # Create ntgelems TG elements for each ctrl for axis in range(1, self.ntgelems + 1): name = '_test_tg_%s_%s' % (ctrl, axis) self.createTGElement(ctrl_obj, name, axis) - # Create nctrls MOT ctrls + # Create nmotctrls MOT ctrls for ctrl in range(1, self.nmotctrls + 1): name = '_test_mot_ctrl_%s' % ctrl ctrl_obj = self.createController(name, 'DummyMotorController', 'DummyMotorController.py') - # Create nelems CT elements for each ctrl + # Create nmotelems MOT elements for each ctrl for axis in range(1, self.nmotelems + 1): name = '_test_mot_%s_%s' % (ctrl, axis) self.createMotorElement(ctrl_obj, name, axis) From 5f004c190d36ba8f80ddbe643b2bd99d346bff20 Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 5 Mar 2019 13:14:43 +0100 Subject: [PATCH 649/652] Remove clear event set in case of Abort and Stop It is not clear how this would react in case a macro ends right after calling stop/abort but before clearing the event set. Just in case, to not break anything new it is better to wait with this change. --- src/sardana/taurus/core/tango/sardana/macroserver.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sardana/taurus/core/tango/sardana/macroserver.py b/src/sardana/taurus/core/tango/sardana/macroserver.py index 04381163bd..8a14d846f9 100644 --- a/src/sardana/taurus/core/tango/sardana/macroserver.py +++ b/src/sardana/taurus/core/tango/sardana/macroserver.py @@ -457,7 +457,6 @@ def abort(self, synch=True): evt_wait = AttributeEventWait(self.getAttribute("state")) evt_wait.lock() try: - evt_wait.clearEventSet() time_stamp = time.time() self.command_inout("AbortMacro") evt_wait.waitEvent(self.Running, equal=False, after=time_stamp, @@ -474,7 +473,6 @@ def stop(self, synch=True): evt_wait = AttributeEventWait(self.getAttribute("state")) evt_wait.lock() try: - evt_wait.clearEventSet() time_stamp = time.time() self.command_inout("StopMacro") evt_wait.waitEvent(self.Running, equal=False, after=time_stamp, From 0f8e57563b6b614b33e2ca095c6c6845fe7e7f4f Mon Sep 17 00:00:00 2001 From: zreszela Date: Tue, 5 Mar 2019 13:18:55 +0100 Subject: [PATCH 650/652] Add comment in the code --- src/sardana/taurus/core/tango/sardana/macroserver.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sardana/taurus/core/tango/sardana/macroserver.py b/src/sardana/taurus/core/tango/sardana/macroserver.py index 8a14d846f9..ae400c53a4 100644 --- a/src/sardana/taurus/core/tango/sardana/macroserver.py +++ b/src/sardana/taurus/core/tango/sardana/macroserver.py @@ -555,6 +555,10 @@ def _runMacro(self, xml, synch=False): evt_wait.lock() try: evt_wait.waitEvent(self.Running, equal=False, timeout=timeout) + # Clear event set to not confuse the value coming from the + # connection with the event of of end of the macro execution + # in the next wait event. This was observed on Windows where + # the time stamp resolution is not better than 1 ms. evt_wait.clearEventSet() ts = time.time() result = self.command_inout("RunMacro", [etree.tostring(xml)]) From 94e4169b0a90162b5cc4be48954adf648dfa0364 Mon Sep 17 00:00:00 2001 From: mrosanes Date: Fri, 1 Mar 2019 16:58:11 +0100 Subject: [PATCH 651/652] Get ms_properties from db properties Get ms_properties from db properties; only in case it is None, build the path to ms_properties and normalize it to be adapted to the given OS (linux / windows). Try to remove the file, and if it is not possible, give an information message (removing the file macroserver.properties, sometimes is giving problems in Windows). --- src/sardana/tango/macroserver/test/base.py | 27 ++++++++++++++++------ 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/sardana/tango/macroserver/test/base.py b/src/sardana/tango/macroserver/test/base.py index ef1d4dd40c..ee8b7cd40c 100644 --- a/src/sardana/tango/macroserver/test/base.py +++ b/src/sardana/tango/macroserver/test/base.py @@ -90,19 +90,32 @@ def setUp(self, properties=None): self.tearDown() def tearDown(self): - """Remove the Pool instance. + """Remove the MacroServer instance and its properties file. """ - dft_ms_properties = os.path.join(MacroServerClass.DefaultEnvBaseDir, - MacroServerClass.DefaultEnvRelDir) - ds_inst_name = self.ms_ds_name.split("/")[1] + self._msstarter.cleanDb(force=True) self._msstarter = None self.macroserver = None self.door = None - ms_properties = dft_ms_properties % {"ds_exec_name": "MacroServer", - "ds_inst_name": ds_inst_name} + + db = PyTango.Database() + prop = db.get_device_property(self.ms_name, "EnvironmentDb") + ms_properties = prop["EnvironmentDb"] + if not ms_properties: + dft_ms_properties = os.path.join( + MacroServerClass.DefaultEnvBaseDir, + MacroServerClass.DefaultEnvRelDir) + ds_inst_name = self.ms_ds_name.split("/")[1] + ms_properties = dft_ms_properties % { + "ds_exec_name": "MacroServer", + "ds_inst_name": ds_inst_name} ms_properties = os.path.normpath(ms_properties) - os.remove(ms_properties) + try: + os.remove(ms_properties) + except Exception, e: + msg = "Not possible to remove macroserver environment file" + print(msg) + print("Details: %s" % e) if __name__ == '__main__': From e72550de9d1b1ca99da40079c24fc72c765ad2dc Mon Sep 17 00:00:00 2001 From: daneos Date: Mon, 11 Mar 2019 11:00:16 +0100 Subject: [PATCH 652/652] update CHANGELOG.md --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd0bbcffd1..1699c5275c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). This file follows the formats and conventions from [keepachangelog.com] -## [2.7.0] 2019-02-08 +## [Unreleased] + +## [2.7.0] 2019-03-11 ### Added @@ -587,7 +589,8 @@ Main improvements since sardana 1.5.0 (aka Jan15): [keepachangelog.com]: http://keepachangelog.com -[Unreleased]: https://github.com/sardana-org/sardana/compare/2.6.1...HEAD +[Unreleased]: https://github.com/sardana-org/sardana/compare/2.7.0...HEAD +[2.7.0]: https://github.com/sardana-org/sardana/compare/2.6.1...2.7.0 [2.6.1]: https://github.com/sardana-org/sardana/compare/2.6.0...2.6.1 [2.6.0]: https://github.com/sardana-org/sardana/compare/2.5.0...2.6.0 [2.5.0]: https://github.com/sardana-org/sardana/compare/2.4.0...2.5.0