[sardana] 04/06: New upstream version 2.1.0
Frédéric-Emmanuel Picca
picca at moszumanska.debian.org
Fri Sep 30 08:55:49 UTC 2016
This is an automated email from the git hooks/post-receive script.
picca pushed a commit to branch master
in repository sardana.
commit 523f1ff46fbbe9b666f13d0d72da5930096651bb
Author: Picca Frédéric-Emmanuel <picca at debian.org>
Date: Tue Sep 13 19:56:49 2016 +0200
New upstream version 2.1.0
---
PKG-INFO | 4 +-
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/sequencer.1 | 4 +-
doc/man/spock.1 | 4 +-
doc/man/ubmatrix.1 | 4 +-
doc/source/_static/macros/favouriteeditor01.png | Bin 0 -> 12205 bytes
doc/source/_static/macros/macroexecutor01.odg | Bin 0 -> 42236 bytes
doc/source/_static/macros/macroexecutor01.png | Bin 0 -> 1111166 bytes
doc/source/_static/macros/macroexecutor01_raw.png | Bin 0 -> 21869 bytes
.../_static/macros/macroparameterseditor01.png | Bin 0 -> 8124 bytes
.../_static/macros/macroparameterseditor02.png | Bin 0 -> 7635 bytes
.../_static/macros/macroparameterseditor03.odg | Bin 0 -> 20268 bytes
.../_static/macros/macroparameterseditor03.png | Bin 0 -> 604944 bytes
.../_static/macros/macroparameterseditor03_raw.png | Bin 0 -> 7773 bytes
.../_static/macros/macroparameterseditor04.odg | Bin 0 -> 23179 bytes
.../_static/macros/macroparameterseditor04.png | Bin 0 -> 604944 bytes
.../_static/macros/macroparameterseditor04_raw.png | Bin 0 -> 10110 bytes
.../_static/macros/macroparameterseditor05.odg | Bin 0 -> 22524 bytes
.../_static/macros/macroparameterseditor05.png | Bin 0 -> 604944 bytes
doc/source/_static/macros/sequenceeditor01.png | Bin 0 -> 13687 bytes
doc/source/_static/macros/sequenceeditor02.odg | Bin 0 -> 27793 bytes
doc/source/_static/macros/sequenceeditor02.png | Bin 0 -> 672669 bytes
doc/source/_static/macros/sequenceeditor02_raw.png | Bin 0 -> 13687 bytes
doc/source/_static/macros/sequenceeditor03.odg | Bin 0 -> 30108 bytes
doc/source/_static/macros/sequenceeditor03.png | Bin 0 -> 628299 bytes
doc/source/_static/macros/sequenceeditor03_raw.png | Bin 0 -> 15806 bytes
doc/source/_static/macros/sequenceeditor04.odg | Bin 0 -> 29610 bytes
doc/source/_static/macros/sequenceeditor04.png | Bin 0 -> 628299 bytes
doc/source/_static/macros/sequenceeditor05_raw.png | Bin 0 -> 19830 bytes
doc/source/_static/macros/sequencer01.odg | Bin 0 -> 47998 bytes
doc/source/_static/macros/sequencer01.png | Bin 0 -> 1233154 bytes
doc/source/_static/macros/sequencer01_raw.png | Bin 0 -> 29047 bytes
.../devel/howto_controllers/howto_0dcontroller.rst | 35 ++++-
.../howto_controllers/howto_motorcontroller.rst | 4 -
doc/source/devel/howto_macros/macros_general.rst | 30 ++--
doc/source/devel/overview/overview_0D.rst | 18 ++-
doc/source/users/index.rst | 1 +
.../users/taurus/experimentconfiguration.rst | 15 ++
doc/source/users/taurus/index.rst | 15 ++
doc/source/users/taurus/macroexecutor.rst | 152 +++++++++++++++++++
doc/source/users/taurus/sardanaeditor.rst | 15 ++
doc/source/users/taurus/sequencer.rst | 123 +++++++++++++++
setup.py | 2 +-
src/sardana/macroserver/macro.py | 48 +++++-
src/sardana/macroserver/macros/demo.py | 30 ++--
src/sardana/macroserver/macros/examples/motion.py | 56 +++++++
.../macroserver/macros/examples/parameters.py | 4 +-
src/sardana/macroserver/macros/hkl.py | 72 ++++-----
src/sardana/macroserver/macros/standard.py | 3 +-
.../macroserver/macros/test/macroexecutor.py | 6 +-
src/sardana/macroserver/msmacromanager.py | 52 ++++++-
src/sardana/macroserver/msoptions.py | 1 +
src/sardana/macroserver/msparameter.py | 165 ++++++++++++++++++++-
src/sardana/macroserver/recorders/output.py | 9 +-
src/sardana/macroserver/scan/gscan.py | 19 ++-
src/sardana/pool/pool.py | 9 +-
src/sardana/pool/poolacquisition.py | 8 +-
src/sardana/pool/poolbasegroup.py | 9 +-
.../poolcontrollers/HklPseudoMotorController.py | 28 +++-
src/sardana/pool/poolmeasurementgroup.py | 21 +--
src/sardana/pool/poolzerodexpchannel.py | 15 +-
src/sardana/release.py | 2 +-
src/sardana/requirements.py | 3 +
src/sardana/spock/ipython_00_10/genutils.py | 23 ++-
src/sardana/spock/ipython_00_11/genutils.py | 92 ++++++++----
src/sardana/spock/ipython_01_00/genutils.py | 100 +++++++++----
src/sardana/spock/magic.py | 56 ++++---
src/sardana/spock/release.py | 2 +-
src/sardana/spock/spockms.py | 14 +-
.../taurus/core/tango/sardana/macroserver.py | 28 +++-
src/sardana/taurus/core/tango/sardana/motion.py | 2 +-
src/sardana/taurus/core/tango/sardana/pool.py | 91 ++++++++++--
.../taurus/qt/qtcore/tango/sardana/macroserver.py | 31 +++-
.../taurus/qt/qtgui/extra_macroexecutor/common.py | 10 +-
.../qt/qtgui/extra_macroexecutor/macrobutton.py | 18 +--
.../qt/qtgui/extra_macroexecutor/macroexecutor.py | 31 +++-
.../extra_macroexecutor/sequenceeditor/model.py | 2 +-
.../sequenceeditor/sequenceeditor.py | 31 +++-
.../taurus/qt/qtgui/extra_pool/poolchannel.py | 2 +-
.../taurus/qt/qtgui/extra_pool/poolioregister.py | 6 +-
.../taurus/qt/qtgui/extra_pool/poolmotor.py | 52 ++++---
.../taurus/qt/qtgui/extra_pool/ui/PoolMotorSlim.ui | 148 ++++++++----------
.../qt/qtgui/extra_sardana/expdescription.py | 19 ++-
.../qt/qtgui/extra_sardana/measurementgroup.py | 62 +++++++-
89 files changed, 1421 insertions(+), 409 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index 32dacfe..27b64b6 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: sardana
-Version: 2.0.0
+Version: 2.1.0
Summary: instrument control and data acquisition system
Home-page: http://www.sardana-controls.org
Author: Zbigniew Reszela
@@ -32,9 +32,9 @@ Classifier: Programming Language :: Python
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Libraries
Requires: PyTango (>=7.2.3)
+Requires: itango (>=0.1.4)
Requires: taurus (>= 3.6.0)
Requires: lxml (>=2.1)
-Requires: ipython (>=0.10, !=0.11)
Provides: sardana
Provides: sardana.pool
Provides: sardana.macroserver
diff --git a/doc/man/MacroServer.1 b/doc/man/MacroServer.1
index 1558828..f7a6133 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.43.3.
-.TH MACROSERVER "1" "April 2016" "MacroServer 2.0.0" "User Commands"
+.TH MACROSERVER "1" "September 2016" "MacroServer 2.1.0" "User Commands"
.SH NAME
-MacroServer \- manual page for MacroServer 2.0.0
+MacroServer \- manual page for MacroServer 2.1.0
.SH SYNOPSIS
.B usage:
\fIMacroServer instance_name \fR[\fIoptions\fR]
diff --git a/doc/man/Pool.1 b/doc/man/Pool.1
index 352b116..dbd19e6 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.43.3.
-.TH POOL "1" "April 2016" "Pool 2.0.0" "User Commands"
+.TH POOL "1" "September 2016" "Pool 2.1.0" "User Commands"
.SH NAME
-Pool \- manual page for Pool 2.0.0
+Pool \- manual page for Pool 2.1.0
.SH SYNOPSIS
.B usage:
\fIPool instance_name \fR[\fIoptions\fR]
diff --git a/doc/man/Sardana.1 b/doc/man/Sardana.1
index d6fae7f..ae4cc6c 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.43.3.
-.TH SARDANA "1" "April 2016" "Sardana 2.0.0" "User Commands"
+.TH SARDANA "1" "September 2016" "Sardana 2.1.0" "User Commands"
.SH NAME
-Sardana \- manual page for Sardana 2.0.0
+Sardana \- manual page for Sardana 2.1.0
.SH SYNOPSIS
.B usage:
\fISardana instance_name \fR[\fIoptions\fR]
diff --git a/doc/man/diffractometeralignment.1 b/doc/man/diffractometeralignment.1
index 9110451..0cb837d 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.43.3.
-.TH DIFFRACTOMETERALIGNMENT "1" "April 2016" "diffractometeralignment 2.0.0" "User Commands"
+.TH DIFFRACTOMETERALIGNMENT "1" "September 2016" "diffractometeralignment 2.1.0" "User Commands"
.SH NAME
-diffractometeralignment \- manual page for diffractometeralignment 2.0.0
+diffractometeralignment \- manual page for diffractometeralignment 2.1.0
.SH SYNOPSIS
.B diffractometeralignment
\fI<model> \fR[\fIdoor_name\fR]
diff --git a/doc/man/hklscan.1 b/doc/man/hklscan.1
index 796e032..8ef6b21 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.43.3.
-.TH HKLSCAN "1" "April 2016" "hklscan 2.0.0" "User Commands"
+.TH HKLSCAN "1" "September 2016" "hklscan 2.1.0" "User Commands"
.SH NAME
-hklscan \- manual page for hklscan 2.0.0
+hklscan \- manual page for hklscan 2.1.0
.SH SYNOPSIS
.B hklscan
\fI<model> \fR[\fIdoor_name\fR]
diff --git a/doc/man/macroexecutor.1 b/doc/man/macroexecutor.1
index 039a949..1e73a9f 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.43.3.
-.TH MACROEXECUTOR "1" "April 2016" "macroexecutor 2.0.0" "User Commands"
+.TH MACROEXECUTOR "1" "September 2016" "macroexecutor 2.1.0" "User Commands"
.SH NAME
-macroexecutor \- manual page for macroexecutor 2.0.0
+macroexecutor \- manual page for macroexecutor 2.1.0
.SH SYNOPSIS
.B macroexecutor
[\fIoptions\fR]
diff --git a/doc/man/sequencer.1 b/doc/man/sequencer.1
index 19dcc3e..8fecd58 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.43.3.
-.TH SEQUENCER "1" "April 2016" "sequencer 2.0.0" "User Commands"
+.TH SEQUENCER "1" "September 2016" "sequencer 2.1.0" "User Commands"
.SH NAME
-sequencer \- manual page for sequencer 2.0.0
+sequencer \- manual page for sequencer 2.1.0
.SH SYNOPSIS
.B sequencer
[\fIoptions\fR]
diff --git a/doc/man/spock.1 b/doc/man/spock.1
index 8e67216..e57623c 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.43.3.
-.TH SPOCK "1" "April 2016" "spock 2.0.0" "User Commands"
+.TH SPOCK "1" "September 2016" "spock 2.1.0" "User Commands"
.SH NAME
-spock \- manual page for spock 2.0.0
+spock \- manual page for spock 2.1.0
.SH DESCRIPTION
=========
.IP
diff --git a/doc/man/ubmatrix.1 b/doc/man/ubmatrix.1
index 40c78df..13e52f5 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.43.3.
-.TH UBMATRIX "1" "April 2016" "ubmatrix 2.0.0" "User Commands"
+.TH UBMATRIX "1" "September 2016" "ubmatrix 2.1.0" "User Commands"
.SH NAME
-ubmatrix \- manual page for ubmatrix 2.0.0
+ubmatrix \- manual page for ubmatrix 2.1.0
.SH SYNOPSIS
.B ubmatrix
\fI<model>\fR
diff --git a/doc/source/_static/macros/favouriteeditor01.png b/doc/source/_static/macros/favouriteeditor01.png
new file mode 100644
index 0000000..808e060
Binary files /dev/null and b/doc/source/_static/macros/favouriteeditor01.png differ
diff --git a/doc/source/_static/macros/macroexecutor01.odg b/doc/source/_static/macros/macroexecutor01.odg
new file mode 100644
index 0000000..75113e2
Binary files /dev/null and b/doc/source/_static/macros/macroexecutor01.odg differ
diff --git a/doc/source/_static/macros/macroexecutor01.png b/doc/source/_static/macros/macroexecutor01.png
new file mode 100644
index 0000000..055b58f
Binary files /dev/null and b/doc/source/_static/macros/macroexecutor01.png differ
diff --git a/doc/source/_static/macros/macroexecutor01_raw.png b/doc/source/_static/macros/macroexecutor01_raw.png
new file mode 100644
index 0000000..a244370
Binary files /dev/null and b/doc/source/_static/macros/macroexecutor01_raw.png differ
diff --git a/doc/source/_static/macros/macroparameterseditor01.png b/doc/source/_static/macros/macroparameterseditor01.png
new file mode 100644
index 0000000..69ba02a
Binary files /dev/null and b/doc/source/_static/macros/macroparameterseditor01.png differ
diff --git a/doc/source/_static/macros/macroparameterseditor02.png b/doc/source/_static/macros/macroparameterseditor02.png
new file mode 100644
index 0000000..8847a38
Binary files /dev/null and b/doc/source/_static/macros/macroparameterseditor02.png differ
diff --git a/doc/source/_static/macros/macroparameterseditor03.odg b/doc/source/_static/macros/macroparameterseditor03.odg
new file mode 100644
index 0000000..1002357
Binary files /dev/null and b/doc/source/_static/macros/macroparameterseditor03.odg differ
diff --git a/doc/source/_static/macros/macroparameterseditor03.png b/doc/source/_static/macros/macroparameterseditor03.png
new file mode 100644
index 0000000..10ed847
Binary files /dev/null and b/doc/source/_static/macros/macroparameterseditor03.png differ
diff --git a/doc/source/_static/macros/macroparameterseditor03_raw.png b/doc/source/_static/macros/macroparameterseditor03_raw.png
new file mode 100644
index 0000000..db86a09
Binary files /dev/null and b/doc/source/_static/macros/macroparameterseditor03_raw.png differ
diff --git a/doc/source/_static/macros/macroparameterseditor04.odg b/doc/source/_static/macros/macroparameterseditor04.odg
new file mode 100644
index 0000000..244c2a5
Binary files /dev/null and b/doc/source/_static/macros/macroparameterseditor04.odg differ
diff --git a/doc/source/_static/macros/macroparameterseditor04.png b/doc/source/_static/macros/macroparameterseditor04.png
new file mode 100644
index 0000000..c908572
Binary files /dev/null and b/doc/source/_static/macros/macroparameterseditor04.png differ
diff --git a/doc/source/_static/macros/macroparameterseditor04_raw.png b/doc/source/_static/macros/macroparameterseditor04_raw.png
new file mode 100644
index 0000000..86c2a57
Binary files /dev/null and b/doc/source/_static/macros/macroparameterseditor04_raw.png differ
diff --git a/doc/source/_static/macros/macroparameterseditor05.odg b/doc/source/_static/macros/macroparameterseditor05.odg
new file mode 100644
index 0000000..8007ac6
Binary files /dev/null and b/doc/source/_static/macros/macroparameterseditor05.odg differ
diff --git a/doc/source/_static/macros/macroparameterseditor05.png b/doc/source/_static/macros/macroparameterseditor05.png
new file mode 100644
index 0000000..ab65c57
Binary files /dev/null and b/doc/source/_static/macros/macroparameterseditor05.png differ
diff --git a/doc/source/_static/macros/sequenceeditor01.png b/doc/source/_static/macros/sequenceeditor01.png
new file mode 100644
index 0000000..34dbcfa
Binary files /dev/null and b/doc/source/_static/macros/sequenceeditor01.png differ
diff --git a/doc/source/_static/macros/sequenceeditor02.odg b/doc/source/_static/macros/sequenceeditor02.odg
new file mode 100644
index 0000000..5f4cedb
Binary files /dev/null and b/doc/source/_static/macros/sequenceeditor02.odg differ
diff --git a/doc/source/_static/macros/sequenceeditor02.png b/doc/source/_static/macros/sequenceeditor02.png
new file mode 100644
index 0000000..89b9db3
Binary files /dev/null and b/doc/source/_static/macros/sequenceeditor02.png differ
diff --git a/doc/source/_static/macros/sequenceeditor02_raw.png b/doc/source/_static/macros/sequenceeditor02_raw.png
new file mode 100644
index 0000000..34dbcfa
Binary files /dev/null and b/doc/source/_static/macros/sequenceeditor02_raw.png differ
diff --git a/doc/source/_static/macros/sequenceeditor03.odg b/doc/source/_static/macros/sequenceeditor03.odg
new file mode 100644
index 0000000..497a5f6
Binary files /dev/null and b/doc/source/_static/macros/sequenceeditor03.odg differ
diff --git a/doc/source/_static/macros/sequenceeditor03.png b/doc/source/_static/macros/sequenceeditor03.png
new file mode 100644
index 0000000..b51ab80
Binary files /dev/null and b/doc/source/_static/macros/sequenceeditor03.png differ
diff --git a/doc/source/_static/macros/sequenceeditor03_raw.png b/doc/source/_static/macros/sequenceeditor03_raw.png
new file mode 100644
index 0000000..06acb0b
Binary files /dev/null and b/doc/source/_static/macros/sequenceeditor03_raw.png differ
diff --git a/doc/source/_static/macros/sequenceeditor04.odg b/doc/source/_static/macros/sequenceeditor04.odg
new file mode 100644
index 0000000..3493675
Binary files /dev/null and b/doc/source/_static/macros/sequenceeditor04.odg differ
diff --git a/doc/source/_static/macros/sequenceeditor04.png b/doc/source/_static/macros/sequenceeditor04.png
new file mode 100644
index 0000000..cada20e
Binary files /dev/null and b/doc/source/_static/macros/sequenceeditor04.png differ
diff --git a/doc/source/_static/macros/sequenceeditor05_raw.png b/doc/source/_static/macros/sequenceeditor05_raw.png
new file mode 100644
index 0000000..abc285c
Binary files /dev/null and b/doc/source/_static/macros/sequenceeditor05_raw.png differ
diff --git a/doc/source/_static/macros/sequencer01.odg b/doc/source/_static/macros/sequencer01.odg
new file mode 100644
index 0000000..37868ec
Binary files /dev/null and b/doc/source/_static/macros/sequencer01.odg differ
diff --git a/doc/source/_static/macros/sequencer01.png b/doc/source/_static/macros/sequencer01.png
new file mode 100644
index 0000000..8a563d8
Binary files /dev/null and b/doc/source/_static/macros/sequencer01.png differ
diff --git a/doc/source/_static/macros/sequencer01_raw.png b/doc/source/_static/macros/sequencer01_raw.png
new file mode 100644
index 0000000..a14b78c
Binary files /dev/null and b/doc/source/_static/macros/sequencer01_raw.png differ
diff --git a/doc/source/devel/howto_controllers/howto_0dcontroller.rst b/doc/source/devel/howto_controllers/howto_0dcontroller.rst
index 23c5af6..6be50bd 100644
--- a/doc/source/devel/howto_controllers/howto_0dcontroller.rst
+++ b/doc/source/devel/howto_controllers/howto_0dcontroller.rst
@@ -6,10 +6,39 @@
How to write a 0D controller
============================
-The basics
-----------
+.. todo:: complete 0D controller howto
+
+Get 0D state
+~~~~~~~~~~~~~~~
+
+To get the state of a 0D, sardana calls the
+:meth:`~sardana.pool.controller.Controller.StateOne` method. During the
+acquisition loop this method is called only once when it is about to
+exit. This method receives an axis as parameter and should return either:
+
+ - state (:obj:`~sardana.sardanadefs.State`) or
+ - a sequence of two elements:
+ - state (:obj:`~sardana.sardanadefs.State`)
+ - status (:obj:`str`)
+
+The state should be a member of :obj:`~sardana.sardanadefs.State` (For backward
+compatibility reasons, it is also supported to return one of
+:class:`PyTango.DevState`). The status could be any string.
+
+If you don't return a status, sardana will compose a status string with:
+
+ <axis name> is in <state name>
+
+The controller could return on of the four states **On**, **Alarm**, **Fault**
+or **Unknown**. Apart of that sardana could set **Moving** or **Fault** state
+to the 0D. The Moving state is set during the acquisition loop to indicate that
+it is acquiring data. The Fault state is set when the controller software is
+not available (impossible to load it).
+The controller should return Fault if a fault is reported from the hardware
+controller or if the controller software returns an unforeseen state.
+The controller should return Unknown state if an exception occurs during the
+communication between the pool and the hardware controller.
-.. todo:: document 0D controller howto
.. _ALBA: http://www.cells.es/
.. _ANKA: http://http://ankaweb.fzk.de/
diff --git a/doc/source/devel/howto_controllers/howto_motorcontroller.rst b/doc/source/devel/howto_controllers/howto_motorcontroller.rst
index bb2aa27..8237bb9 100644
--- a/doc/source/devel/howto_controllers/howto_motorcontroller.rst
+++ b/doc/source/devel/howto_controllers/howto_motorcontroller.rst
@@ -68,10 +68,6 @@ Get motor state
To get the state of a motor, sardana calls the
:meth:`~sardana.pool.controller.Controller.StateOne` method. This method
-receives an axis as parameter and should return a sequence of three values:
-
-To get the state of a motor, sardana calls the
-:meth:`~sardana.pool.controller.Controller.StateOne` method. This method
receives an axis as parameter and should return either:
- state (:obj:`~sardana.sardanadefs.State`) or
diff --git a/doc/source/devel/howto_macros/macros_general.rst b/doc/source/devel/howto_macros/macros_general.rst
index 8f6144d..3f658e6 100644
--- a/doc/source/devel/howto_macros/macros_general.rst
+++ b/doc/source/devel/howto_macros/macros_general.rst
@@ -343,7 +343,7 @@ of items.
::
@macro([["moveables", [
- "moveable", Type.Moveable, None, "moveable to get position"
+ ["moveable", Type.Moveable, None, "moveable to get position"]
],
None, "list of moveables to get positions"]])
def where_moveables(self, moveables):
@@ -363,7 +363,7 @@ each item is an internal list of the members.
None, "list of moveables and positions to be moved to"]])
def move_multiple(self, m_p_pairs):
"""This macro moves moveables to the specified positions"""
- for moveable, position in zip(*m_p_pairs):
+ for moveable, position in m_p_pairs:
moveable.move(position)
self.output("%s is now at %s", moveable.getName(), moveable.getPosition())
@@ -419,7 +419,7 @@ Here is the new version of *where_moveable* ::
@macro([["moveable", Type.Moveable, None, "moveable to get position"]])
def where_moveable(self, moveable):
"""This macro prints the current moveable position"""
- self.wm([moveable])
+ self.wm([moveable]) # self.wm(moveable) backwards compatibility - see note
... and the new version of *move* ::
@@ -427,15 +427,19 @@ Here is the new version of *where_moveable* ::
["position", Type.Float, None, "absolute position"] ])
def move(self, moveable, position):
"""This macro moves a moveable to the specified position"""
- self.mv([[moveable, position]])
+ self.mv([moveable, position]) # self.mv(moveable, position) backwards compatibility - see note
self.output("%s is now at %s", moveable.getName(), moveable.getPosition())
.. note::
- Both :class:`~sardana.macroserver.macros.standard.wm` and
- :class:`~sardana.macroserver.macros.standard.mv`
- use :ref:`repeat parameters <sardana-macro-repeat-parameters>`.
- From Sardana 2.0 the repeat parameter values must be passed as lists of
- items. An item of a repeat parameter containing more than one member is a list.
+ Both :class:`~sardana.macroserver.macros.standard.wm` and
+ :class:`~sardana.macroserver.macros.standard.mv`
+ use :ref:`repeat parameters <sardana-macro-repeat-parameters>`.
+ From Sardana 2.0 the repeat parameter values must be passed as lists of
+ items. An item of a repeat parameter containing more than one member is a
+ list. In case when a macro defines only one repeat parameter
+ and it is the last parameter, for the backwards compatibility reasons, the
+ plain list of items' members is allowed.
+
.. _sardana-macro-environment:
@@ -590,6 +594,7 @@ parameters with different *flavors*:
self.execMacro('ascan', motor.getName(), '0', '100', '10', '0.2')
self.execMacro('mv', [[motor.getName(), '0']])
+ self.execMacro('mv', motor.getName(), '0') # backwards compatibility - see note
* parameters as space separated string (this is not compatible with multiple
or nested repeat parameters, furthermore the repeat parameter must be the last one)::
@@ -601,12 +606,17 @@ parameters with different *flavors*:
self.execMacro(['ascan', motor, 0, 100, 10, 0.2])
self.execMacro(['mv', [[motor, 0]]])
+ self.execMacro(['mv', motor, 0]) # backwards compatibility - see note
.. note::
Macro :class:`~sardana.macroserver.macros.standard.mv`
use :ref:`repeat parameters <sardana-macro-repeat-parameters>`.
From Sardana 2.0 the repeat parameter values must be passed as lists of
- items. An item of a repeat parameter containing more than one member is a list.
+ items. An item of a repeat parameter containing more than one member is a
+ list. In case when a macro defines only one repeat parameter
+ and it is the last parameter, for the backwards compatibility reasons, the
+ plain list of items' members is allowed.
+
Accessing macro data
~~~~~~~~~~~~~~~~~~~~
diff --git a/doc/source/devel/overview/overview_0D.rst b/doc/source/devel/overview/overview_0D.rst
index e3d6553..f5ccf05 100644
--- a/doc/source/devel/overview/overview_0D.rst
+++ b/doc/source/devel/overview/overview_0D.rst
@@ -6,12 +6,22 @@
0D channel overview
=======================
-.. todo:: document 0D experiment channel overview
+The ZeroDExpChannel is used to access any kind of device which returns a scalar
+value and which are not counter or timer. Very often (but not always), this is
+a commercial measurement equipment connected to a GPIB bus. In order to have as
+precise as possible measurement, an acquisition loop is implemented for the
+ZeroDExpChannel device. This acquisition loop will simply read the data from
+the hardware as fast as it can (only “sleeping” 10 mS between each reading) and
+a computation is done on the resulting data set to return only one value.
+Three types of computation are foreseen. The user selects which one he needs
+with an attribute. The time during which this acquisition loop will get data is
+controlled by the counters & timers present in the measurement group - when all
+of them finish acquiring the ZeroD acquisition action will also stop.
+
+.. seealso::
-.. seealso::
-
:ref:`sardana-0d-api`
the 0D experiment channel :term:`API`
-
+
:class:`~sardana.tango.pool.ZeroDExpChannel.ZeroDExpChannel`
the 0D experiment channel tango device :term:`API`
diff --git a/doc/source/users/index.rst b/doc/source/users/index.rst
index a137e8a..0651fb4 100644
--- a/doc/source/users/index.rst
+++ b/doc/source/users/index.rst
@@ -10,6 +10,7 @@ User's Guide
Overview <overview>
Getting started <getting_started/index>
Spock <spock>
+ Sardana-Taurus Widgets <taurus/index>
Scans <scan>
Standard macro catalog <standard_macro_catalog>
Screenshots <screenshots>
diff --git a/doc/source/users/taurus/experimentconfiguration.rst b/doc/source/users/taurus/experimentconfiguration.rst
new file mode 100644
index 0000000..d6bcd3e
--- /dev/null
+++ b/doc/source/users/taurus/experimentconfiguration.rst
@@ -0,0 +1,15 @@
+.. currentmodule:: sardana.taurus.qt.qtgui.extra_sardana
+
+.. _expconf_ui:
+
+
+=======================================
+Experiment Configuration user interface
+=======================================
+
+.. contents::
+
+.. todo::
+ Experiment Configuration documentation to be written
+
+
\ No newline at end of file
diff --git a/doc/source/users/taurus/index.rst b/doc/source/users/taurus/index.rst
new file mode 100644
index 0000000..9e13137
--- /dev/null
+++ b/doc/source/users/taurus/index.rst
@@ -0,0 +1,15 @@
+
+================================
+Sardana Taurus Extension widgets
+================================
+
+
+Sardana provides several :mod:`taurus`-based widgets for being used in GUIs
+
+.. toctree::
+ :maxdepth: 3
+
+ MacroExecutor <macroexecutor>
+ Sequencer <sequencer>
+ Experiment Configuration <experimentconfiguration>
+ Sardana Editor <sardanaeditor>
diff --git a/doc/source/users/taurus/macroexecutor.rst b/doc/source/users/taurus/macroexecutor.rst
new file mode 100644
index 0000000..b3675df
--- /dev/null
+++ b/doc/source/users/taurus/macroexecutor.rst
@@ -0,0 +1,152 @@
+.. _macroexecutor_ui:
+
+==========================================
+MacroExecutor User's Interface
+==========================================
+
+
+.. contents::
+
+
+*MacroExecutor* provides an user-friendly graphical interface to macro execution.
+It is divided into 3 main areas: `actions bar`, `parameters editor` and `favourites list`.
+Their functionalities are supported by `Spock command line` and `macro progress bar`.
+User has full control over macros thanks to action buttons: Start(Resume), Stop, Pause located in `actions bar`
+Graphical `parameters editor` provides a clear way to set and modify macro execution settings (parameters).
+Macros which are more frequently used can be permanently stored in `favourites list`.
+Once macro was started Door's state led and `macro progress bar` informs user about its status.
+Current macro settings (parameters) are translated to spock syntax, and represented in non editable
+`spock command line`.
+
+.. figure:: /_static/macros/macroexecutor01.png
+ :align: center
+
+
+.. _macroexecutor_stand-alone:
+
+
+MacroExecutor as a stand-alone application
+------------------------------------------
+
+You may also use *MacroExecutor* as a stand-alone application. In this case it appears embedded
+in window and some extra functionalities are provided.
+You can launch the stand-alone *MacroExecutor* with the following command::
+
+ macroexecutor [options] [<macro_executor_dev_name> <door_dev_name>]
+
+Options::
+
+ --taurus-log-level=LEVEL
+ taurus log level. Allowed values are (case
+ insensitive): critical, error, warning/warn, info,
+ debug, trace
+
+ --taurus-polling-period=MILLISEC
+ taurus global polling period in milliseconds
+
+ --taurus-serialization-mode=SERIAL
+ taurus serialization mode. Allowed values are (case
+ insensitive): serial, concurrent (default)
+
+ --tango-host=TANGO_HOST
+ Tango host name
+
+
+The model list is optional and is a space-separated list of two device names: macro server and door.
+If not provided at the application startup, models can be later on changed in configuration dialog.
+
+Extra functionalities:
+
+- Changing macro configuration
+
+.. todo::
+ This chapter is not ready... Sorry for inconvenience.
+
+- Configuring custom editors
+
+.. todo::
+ This chapter is not ready... Sorry for inconvenience.
+
+
+.. _editing_macro_parameters:
+
+Editing macro parameters
+------------------------
+
+.. _editing_macro_parameters_standard:
+
+Using standard editor
+'''''''''''''''''''''
+
+If no custom parameter editor is assigned to macro, default editor is used to configure execution settings (parameters).
+Parameters are represented in form of tree (with hidden root node) - every parameter is a separate branch with two columns:
+parameter name and parameter value.
+Editor is populated with default values of parameters, if this in not a case 'None' values are used. (If macro execution settings
+were restored e.g. from favourites list, editor is populated with stored values). Values become editable either by double-clicking on them,
+or by pressing F2 button when value is selected. This action opens default parameter editor (combobox with predefined values, spin box etc.).
+
+In case of macros with single parameters only, tree has only a one level branch, and then tree representation looks more like a list
+(because of hidden root node)
+
+.. figure:: /_static/macros/macroparameterseditor01.png
+ :align: center
+
+In case of macros which contain repeat parameters, concept of tree is more visible.
+
+.. figure:: /_static/macros/macroparameterseditor02.png
+ :align: center
+
+- adding new parameter repetition
+
+First select parameter node and if its maximum number of repetition is not exceeded, button with '+' sign appears enabled.
+After pressing this button child branch with new repetition appears in tree editor.
+
+.. figure:: /_static/macros/macroparameterseditor03.png
+ :align: center
+
+- modifying repetition order
+
+First select repetition node (with #<number> text), and buttons with arrows becomes enable (if it is feasible to change order)
+
+.. figure:: /_static/macros/macroparameterseditor04.png
+ :align: center
+
+- removing parameter repetition
+
+First select repetition node (with #<number> text), and if it's minimum number of repetition is not reached, button with '-' sign appears enabled.
+After pressing this button child branch disappears from tree editor. (see previous picture)
+
+.. figure:: /_static/macros/macroparameterseditor05.png
+ :align: center
+
+.. _editing_macro_parameters_custom:
+
+Using custom editors
+''''''''''''''''''''
+
+.. todo::
+ This chapter is not ready... Sorry for inconvenince.
+
+.. _editing_favourites_list:
+
+Editing favourites list
+-----------------------
+
+Once macro parameters are configured they can be easily stored in favourites list for later reuse.
+
+- adding a favourite
+
+Clicking in Add to favourites button (the one with yellow star), adds a new entry in favourite list,
+with current macro and its current settings.
+
+- restoring a favourite
+
+To restore macro from favourites list just select it in the list and macro parameters editor will immediately populate with stored settings.
+
+- modifying favouites list
+
+First select favourite macro and buttons with arrows becomes enable (if it is feasible to change order)
+
+- removing a favourite
+
+First select favourite macro, button with '-' sign appears enabled. After pressing this button, previously selected macro disappears from the list.
\ No newline at end of file
diff --git a/doc/source/users/taurus/sardanaeditor.rst b/doc/source/users/taurus/sardanaeditor.rst
new file mode 100644
index 0000000..fe2e89a
--- /dev/null
+++ b/doc/source/users/taurus/sardanaeditor.rst
@@ -0,0 +1,15 @@
+.. currentmodule:: sardana.taurus.qt.qtgui.extra_sardana
+
+.. _sardanaeditor_ui:
+
+
+==========================
+Sardana Editor's interface
+==========================
+
+.. contents::
+
+.. todo::
+ Sardana Editor documentation to be written
+
+
\ No newline at end of file
diff --git a/doc/source/users/taurus/sequencer.rst b/doc/source/users/taurus/sequencer.rst
new file mode 100644
index 0000000..6eca58d
--- /dev/null
+++ b/doc/source/users/taurus/sequencer.rst
@@ -0,0 +1,123 @@
+.. _sequencer_ui:
+
+==========================================
+Sequencer User's Interface
+==========================================
+
+
+.. contents::
+
+
+`Sequencer` provides an user-friendly interface to compose and execute sequences of macros. Sequence of macros allows execution
+of ordered set of macros with just one trigger. It also allows using a concept of hooks (macros attached and executed in defined places of other macros).
+It is divided into 3 main areas: `actions bar`, `sequence editor` and `parameters editor`.
+`Sequence editor` allows you modifying sequences in many ways: appending new macros, changing macros locations and removing macros.
+Graphical `parameters editor` (standard/custom) provides a clear way to set/modify macro execution settings(parameters).
+Once sequence of macros is in execution phase, `Sequencer` informs user about its state with Door's state led and macros progress bars.
+User has full control over sequence, with action buttons: Start, Stop, Pause, Resume.
+If desirable, sequences can be permanently stored into a file and later on restored from there.
+This functionality is provided thanks to action buttons: Save and Open a sequence.
+
+.. figure:: /_static/macros/sequencer01.png
+ :align: center
+
+
+.. _sequencer_stand-alone:
+
+Sequencer as a stand-alone application
+--------------------------------------
+
+You may also use *Sequencer* as a stand-alone application. In this case it appears embedded
+in window and some extra functionalities are provided.
+You can launch the stand-alone *Sequencer* with the following command::
+
+ sequencer [options] [<macro_executor_dev_name> <door_dev_name>]
+
+Options::
+
+ --taurus-log-level=LEVEL
+ taurus log level. Allowed values are (case
+ insensitive): critical, error, warning/warn, info,
+ debug, trace
+
+ --taurus-polling-period=MILLISEC
+ taurus global polling period in milliseconds
+
+ --taurus-serialization-mode=SERIAL
+ taurus serialization mode. Allowed values are (case
+ insensitive): serial, concurrent (default)
+
+ --tango-host=TANGO_HOST
+ Tango host name
+
+
+The model list is optional and is a space-separated list of two device names: macro server and door.
+If not provided at the application startup, device names can be later on selected from Macro Configuration Dialog.
+
+Extra functionalities:
+
+- MacroConfigurationDialog
+
+.. todo::
+ This chapter in not ready... Sorry for inconvenience.
+
+- CustomEditorsPathDialog
+
+.. todo::
+ This chapter in not ready... Sorry for inconvenience.
+
+.. _editing_sequence:
+
+Editing sequence
+----------------
+
+Sequence is represented as a flat list of ordered macros, in this view each macro is represented as a new line with 4 columns:
+Macro (macro name), Parameters (comma separated parameter values), Progress (macro progress bar) and Pause
+(pause point before macro execution - not implemented yet). Macros which contain hooks, expand with branched macros.
+Macro parameters values can be edited from `parameters editor`, to do so select one macro in sequence editor by clicking on it.
+Selected macro becomes highlighted, and `parameters editor` populate with its current parameters values.
+
+.. figure:: /_static/macros/sequenceeditor01.png
+ :align: center
+
+- adding a new macro
+
+First select macro from macro combo box, and when you are sure to add it to the sequence, press '+' button.
+To add macro as a hook of other macro, before adding it, please select its parent macro in the sequence, and then press '+' button.
+If no macro was selected as a parent, macro will be automatically appended at the end of the list.
+
+.. figure:: /_static/macros/sequenceeditor02.png
+ :align: center
+
+- reorganizing sequence
+
+Macros which are already part of a sequence, can be freely moved around, either in execution order or in hook place (if new macro accepts hooks).
+To move macro first select it in the sequence by single clicking on it (it will become highlighted). Then a set of buttons with arrows
+become enabled. Clicking on them will cause selected macro changin its position in the sequence (either vertically - execution order or horizontal
+parent macro - hook macro relationship)
+
+.. figure:: /_static/macros/sequenceeditor03.png
+ :align: center
+
+- remove macro
+
+Macros which are already part of a sequence, can be freely removed from it. To do so first select macro in a sequence by
+single clicking on it (it will become highlighted). Then button with '-' becomes enabled. Clicking on it removes selected macro.
+
+.. figure:: /_static/macros/sequenceeditor04.png
+ :align: center
+
+- configuring hook execution place
+
+If macro is embedded as a hook in parent macro, please follow these instructions to configure its hook execution place.
+First select macro in a sequence by single clicking on it (it will become highlighted).
+Then using right mouse button open context menu, go to 'Hook places' sub-menu and select hook places which interest you
+(you can select more than one).
+
+.. figure:: /_static/macros/sequenceeditor05_raw.png
+ :align: center
+
+
+Editing macro parameters
+------------------------
+To obtain information about editing macro parameters, please refer to the following link :ref:`Editing macro parameters <editing_macro_parameters>`
\ No newline at end of file
diff --git a/setup.py b/setup.py
index d94528b..8b9dff5 100644
--- a/setup.py
+++ b/setup.py
@@ -374,9 +374,9 @@ def main():
requires = [
'PyTango (>=7.2.3)',
+ 'itango (>=0.1.4)',
'taurus (>= 3.6.0)',
'lxml (>=2.1)',
- 'ipython (>=0.10, !=0.11)'
]
scripts = [
diff --git a/src/sardana/macroserver/macro.py b/src/sardana/macroserver/macro.py
index 17e800c..34d6cb5 100644
--- a/src/sardana/macroserver/macro.py
+++ b/src/sardana/macroserver/macro.py
@@ -1051,20 +1051,27 @@ class Macro(Logger):
# several parameters:
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)
self.execMacro('mv', [[motor.getName(), 0]])
+ self.execMacro('mv', motor.getName(), 0) # backwards compatibility - see note
th = self.getObj('th')
self.execMacro('ascan', th, 0, 100, 10, 1.0)
- self.execMacro('mv', [th, 0]])
+ self.execMacro('mv', [[th, 0]])
+ self.execMacro('mv', th, 0) # backwards compatibility - see note
# a sequence of parameters:
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))
self.execMacro(['mv', [[motor.getName(), 0]]])
+ self.execMacro(['mv', motor.getName(), 0]) # backwards compatibility - see note
th = self.getObj('th')
self.execMacro(['ascan', th, 0, 100, 10, 1.0])
self.execMacro(['mv', [[th, 0]]])
+ self.execMacro(['mv', th, 0]) # backwards compatibility - see note
+
# a space separated string of parameters (this is not compatible
# with multiple or nested repeat parameters, furthermore the repeat
@@ -1072,6 +1079,13 @@ class Macro(Logger):
self.execMacro('ascan th 0 100 10 1.0')
self.execMacro('mv %s 0' % motor.getName())
+ .. note:: From Sardana 2.0 the repeat parameter values must be passed
+ as lists of items. An item of a repeat parameter containing more
+ than one member is a list. In case when a macro defines only one
+ repeat parameter and it is the last parameter, for the backwards
+ compatibility reasons, the plain list of items' members is allowed.
+
+
:param pars: the command parameters as explained above
:return:
a sequence of two elements: the macro object and the result of
@@ -1108,20 +1122,26 @@ class Macro(Logger):
# several parameters:
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)
self.execMacro('mv', [[motor.getName(), 0]])
+ self.execMacro('mv', motor.getName(), 0) # backwards compatibility - see note
th = self.getObj('th')
self.execMacro('ascan', th, 0, 100, 10, 1.0)
- self.execMacro('mv', [th, 0]])
+ self.execMacro('mv', [[th, 0]])
+ self.execMacro('mv', th, 0) # backwards compatibility - see note
# a sequence of parameters:
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))
self.execMacro(['mv', [[motor.getName(), 0]]])
+ self.execMacro(['mv', motor.getName(), 0]) # backwards compatibility - see note
th = self.getObj('th')
self.execMacro(['ascan', th, 0, 100, 10, 1.0])
self.execMacro(['mv', [[th, 0]]])
+ self.execMacro(['mv', th, 0]) # backwards compatibility - see note
# a space separated string of parameters (this is not compatible
# with multiple or nested repeat parameters, furthermore the repeat
@@ -1129,11 +1149,18 @@ class Macro(Logger):
self.execMacro('ascan th 0 100 10 1.0')
self.execMacro('mv %s 0' % motor.getName())
+ .. note:: From Sardana 2.0 the repeat parameter values must be passed
+ as lists of items. An item of a repeat parameter containing more
+ than one member is a list. In case when a macro defines only one
+ repeat parameter and it is the last parameter, for the backwards
+ compatibility reasons, the plain list of items' members is allowed.
+
:param args: the command parameters as explained above
:param kwargs: keyword optional parameters for prepare
:return:
a sequence of two elements: the macro object and the result of
- preparing the macro"""
+ preparing the macro
+ """
# sync our log before calling the child macro prepare in order to avoid
# mixed outputs between this macro and the child macro
self.syncLog()
@@ -1190,20 +1217,26 @@ class Macro(Logger):
# several parameters:
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)
self.execMacro('mv', [[motor.getName(), 0]])
+ self.execMacro('mv', motor.getName(), 0) # backwards compatibility - see note
th = self.getObj('th')
self.execMacro('ascan', th, 0, 100, 10, 1.0)
self.execMacro('mv', [th, 0]])
+ self.execMacro('mv', th, 0) # backwards compatibility - see note
# a sequence of parameters:
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))
self.execMacro(['mv', [[motor.getName(), 0]]])
+ self.execMacro(['mv', motor.getName(), 0]) # backwards compatibility - see note
th = self.getObj('th')
self.execMacro(['ascan', th, 0, 100, 10, 1.0])
self.execMacro(['mv', [[th, 0]]])
+ self.execMacro(['mv', th, 0]) # backwards compatibility - see note
# a space separated string of parameters (this is not compatible
# with multiple or nested repeat parameters, furthermore the repeat
@@ -1211,9 +1244,16 @@ class Macro(Logger):
self.execMacro('ascan th 0 100 10 1.0')
self.execMacro('mv %s 0' % motor.getName())
+ .. note:: From Sardana 2.0 the repeat parameter values must be passed
+ as lists of items. An item of a repeat parameter containing more
+ than one member is a list. In case when a macro defines only one
+ repeat parameter and it is the last parameter, for the backwards
+ compatibility reasons, the plain list of items' members is allowed.
+
:param pars: the command parameters as explained above
- :return: a macro object"""
+ :return: a macro object
+ """
# obtaining macro name
macro_name = None
arg0 = args[0]
diff --git a/src/sardana/macroserver/macros/demo.py b/src/sardana/macroserver/macros/demo.py
index 50536a2..6e8b8df 100644
--- a/src/sardana/macroserver/macros/demo.py
+++ b/src/sardana/macroserver/macros/demo.py
@@ -264,21 +264,21 @@ def sar_demo_hkl(self):
self.print("Creating hkl controller", hkl_ctrl_name, "...")
self.defctrl("DiffracE6C", hkl_ctrl_name,
- "mu=" + motor_names[0], # motor role
- "omega=" + motor_names[1],
- "chi=" + motor_names[2],
- "phi=" + motor_names[3],
- "gamma=" + motor_names[4],
- "delta=" + motor_names[5],
- "h=" + pseudo_names[0], # pseudo role
- "k=" + pseudo_names[1],
- "l=" + pseudo_names[2],
- "psi=" + pseudo_names[3],
- "q=" + pseudo_names[4],
- "alpha=" + pseudo_names[5],
- "qper=" + pseudo_names[6],
- "qpar=" + pseudo_names[7],
- "diffractometertype", "E6C")
+ ["mu=" + motor_names[0], # motor role
+ "omega=" + motor_names[1],
+ "chi=" + motor_names[2],
+ "phi=" + motor_names[3],
+ "gamma=" + motor_names[4],
+ "delta=" + motor_names[5],
+ "h=" + pseudo_names[0], # pseudo role
+ "k=" + pseudo_names[1],
+ "l=" + pseudo_names[2],
+ "psi=" + pseudo_names[3],
+ "q=" + pseudo_names[4],
+ "alpha=" + pseudo_names[5],
+ "qper=" + pseudo_names[6],
+ "qpar=" + pseudo_names[7],
+ "diffractometertype", "E6C"])
controllers = motor_ctrl_name, hkl_ctrl_name
elements = pseudo_names + motor_names
diff --git a/src/sardana/macroserver/macros/examples/motion.py b/src/sardana/macroserver/macros/examples/motion.py
new file mode 100755
index 0000000..e1b2e1d
--- /dev/null
+++ b/src/sardana/macroserver/macros/examples/motion.py
@@ -0,0 +1,56 @@
+##############################################################################
+##
+## 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 <http://www.gnu.org/licenses/>.
+##
+##############################################################################
+
+"""This module contains macros that demonstrate the usage of motion"""
+
+__all__ = ["move_async"]
+
+__docformat__ = 'restructuredtext'
+
+from sardana.macroserver.macro import *
+
+
+class move_async(Macro):
+ """A macro that executes an asynchronous movement of a motor. The movement
+ can be cancelled by a Ctrl-C signal.
+
+ This macro is part of the examples package. It was written for
+ demonstration purposes"""
+
+ param_def = [['moveable', Type.Moveable, None, 'moveable to be moved'],
+ ['pos', Type.Float, None, 'target position'],
+ ]
+
+ def run(self, moveable, pos):
+ try:
+ motion = self.getMotion([moveable])
+ self.info('initial position: %s' % motion.readPosition())
+ _id = motion.startMove([pos])
+ # Do whatever here (while the moveable is moving)
+ self.info('state: %s' % motion.readState())
+ # End Do whatever here
+ finally:
+ motion.waitMove(id=_id)
+ # this line will not be printed in case of abort (Ctrl-C)
+ # due to https://sourceforge.net/p/sardana/tickets/9/
+ self.info('final position: %s' % motion.readPosition())
\ No newline at end of file
diff --git a/src/sardana/macroserver/macros/examples/parameters.py b/src/sardana/macroserver/macros/examples/parameters.py
index b164a1c..8704eca 100644
--- a/src/sardana/macroserver/macros/examples/parameters.py
+++ b/src/sardana/macroserver/macros/examples/parameters.py
@@ -208,7 +208,7 @@ class twice(Macro):
# uncomment the following lines as necessary. Otherwise you may delete them
param_def = [ [ "value", Type.Float, 23, "value to be doubled" ] ]
- result_def = [ [ "result", Type.Float, 23, "the double of the given value" ] ]
+ result_def = [ [ "result", Type.Float, None, "the double of the given value" ] ]
#hints = {}
#env = (,)
@@ -219,4 +219,4 @@ class twice(Macro):
def run(self, n):
ret = 2*n
self.setData({'in':n, 'out':ret})
- return ret
\ No newline at end of file
+ return ret
diff --git a/src/sardana/macroserver/macros/hkl.py b/src/sardana/macroserver/macros/hkl.py
index afdb968..2cde50e 100644
--- a/src/sardana/macroserver/macros/hkl.py
+++ b/src/sardana/macroserver/macros/hkl.py
@@ -27,6 +27,7 @@ import numpy as np
from sardana.macroserver.macro import *
from sardana.macroserver.macros.scan import aNscan
+from sardana.macroserver.msexception import UnknownEnv
from taurus.core.util.log import Logger
@@ -171,9 +172,6 @@ class _diffrac:
if mat:
return regx.sub(repl, ch)
-# TODO: Revrite this macro in order to use events instead of polling to obtain
-# the position updates. See umv macro as an example
-# TODO: H, K, L parameters should be of type float and not string
class br(Macro, _diffrac):
"""Move the diffractometer to the reciprocal space coordinates given by
H, K and L.
@@ -187,13 +185,16 @@ class br(Macro, _diffrac):
['L', Type.String, None, "L value"],
['AnglesIndex', Type.Integer, -1, "Angles index"],
['FlagNotBlocking', Type.Integer, 0,
- "If 1 not block. Return without finish movement"]
+ "If 1 not block. Return without finish movement"],
+ ['FlagPrinting', Type.Integer, 0,
+ "If 1 printing. Used by ubr"]
]
- def prepare(self, H, K, L, AnglesIndex, FlagNotBlocking):
+ def prepare(self, H, K, L, AnglesIndex, FlagNotBlocking, FlagPrinting):
_diffrac.prepare(self)
- def run(self, H, K, L, AnglesIndex, FlagNotBlocking):
+ def run(self, H, K, L, AnglesIndex, FlagNotBlocking, FlagPrinting):
+ h_idx = 0; k_idx = 1; l_idx = 2
if AnglesIndex != -1:
sel_tr = AnglesIndex
@@ -205,43 +206,42 @@ class br(Macro, _diffrac):
if H in hkl_labels or K in hkl_labels or L in hkl_labels:
try:
q_vector = self.getEnv('Q')
- q_dict = {}
- q_dict["H"] = q_vector[0]
- q_dict["K"] = q_vector[1]
- q_dict["L"] = q_vector[2]
-
+ except UnknownEnv:
+ self.error("Environment Q not defined. Run wh to define it")
+ return
+ try:
if H in hkl_labels:
- H = float(q_dict[H])
+ H = float(q_vector[h_idx])
if K in hkl_labels:
- K = float(q_dict[K])
+ K = float(q_vector[k_idx])
if L in hkl_labels:
- L = float(q_dict[L])
+ L = float(q_vector[l_idx])
except:
- self.error("Environment Q not defined. Run wh to define it")
+ self.error("Wrong format of Q vector")
return
-
hkl_values = [float(H), float(K), float(L)]
self.diffrac.write_attribute("computetrajectoriessim", hkl_values)
angles_list = self.diffrac.trajectorylist[sel_tr]
- i = 0
- for angle in self.angle_names:
- angle_dev = self.getDevice(self.angle_device_names[angle])
- angle_dev.write_attribute("Position", angles_list[i])
- i = i + 1
- self.checkPoint()
-
- self.checkPoint()
-
if FlagNotBlocking == 0:
- self.execMacro('_blockprintmove', 0)
+ cmd = "mv"
+ for name, angle in zip(self.angle_names, angles_list):
+ cmd = cmd + " " + str(self.angle_device_names[name])
+ cmd = cmd + " " + str(angle)
+ if FlagPrinting == 1:
+ cmd = "u" + cmd
+ self.execMacro(cmd)
+ else:
+ for name, angle in zip(self.angle_names, angles_list):
+ angle_dev = self.getObj(self.angle_device_names[name])
+ angle_dev.write_attribute("Position", angle)
+
+ self.setEnv('Q', [hkl_values[h_idx], hkl_values[k_idx],
+ hkl_values[l_idx], self.diffrac.WaveLength])
- self.setEnv('Q', [hkl_values[0], hkl_values[1],
- hkl_values[2], self.diffrac.WaveLength])
-# TODO: hh, kk, ll parameters should be of type float and not string
class ubr(Macro, _diffrac):
"""Move the diffractometer to the reciprocal space coordinates given by
H, K and L und update.
@@ -258,20 +258,8 @@ class ubr(Macro, _diffrac):
_diffrac.prepare(self)
def run(self, hh, kk, ll, AnglesIndex):
-
- hkl_labels = ["H", "K", "L"]
-
- if hh in hkl_labels or kk in hkl_labels or ll in hkl_labels: # Needs to be checked also here
- try:
- q_vector = self.getEnv('Q')
- except:
- self.error("Environment Q not defined. Run wh to define it")
- return
-
if ll != "Not set":
- br, pars = self.createMacro("br", hh, kk, ll, AnglesIndex, 1)
- self.runMacro(br)
- self.execMacro('_blockprintmove', 1)
+ self.execMacro("br", hh, kk, ll, AnglesIndex, 0, 1)
else:
self.output("usage: ubr H K L [Trajectory]")
diff --git a/src/sardana/macroserver/macros/standard.py b/src/sardana/macroserver/macros/standard.py
index c8c72d4..d41aee7 100644
--- a/src/sardana/macroserver/macros/standard.py
+++ b/src/sardana/macroserver/macros/standard.py
@@ -472,6 +472,7 @@ class umv(Macro):
posObj.subscribeEvent(self.positionChanged, motor)
def run(self, motor_pos_list):
+ self.print_pos = True
self.execMacro('mv', motor_pos_list)
self.finish()
@@ -632,7 +633,7 @@ class ct(Macro):
state, data = self.mnt_grp.count(integ_time)
names, counts = [], []
- for ch_info in self.mnt_grp.getChannelsInfo():
+ for ch_info in self.mnt_grp.getChannelsEnabledInfo():
names.append(' %s' % ch_info.label)
ch_data = data.get(ch_info.full_name)
if ch_info.shape > [1]:
diff --git a/src/sardana/macroserver/macros/test/macroexecutor.py b/src/sardana/macroserver/macros/test/macroexecutor.py
index bf01c5b..39e43ac 100644
--- a/src/sardana/macroserver/macros/test/macroexecutor.py
+++ b/src/sardana/macroserver/macros/test/macroexecutor.py
@@ -295,7 +295,11 @@ class MacroExecutorFactory(Singleton):
# For the moment I implement it by calling an internal member of
# TaurusManager
from taurus.core import TaurusManager
- scheme = TaurusManager()._get_scheme(door_name)
+ try:
+ scheme = TaurusManager()._get_scheme(door_name)
+ except AttributeError:
+ # TODO: For Taurus 4 compatibility
+ scheme = TaurusManager().getScheme(door_name)
#======================================================================
if scheme == 'tango':
diff --git a/src/sardana/macroserver/msmacromanager.py b/src/sardana/macroserver/msmacromanager.py
index cc99d9c..b867538 100644
--- a/src/sardana/macroserver/msmacromanager.py
+++ b/src/sardana/macroserver/msmacromanager.py
@@ -54,7 +54,8 @@ from sardana.sardanautils import is_pure_str, is_non_str_seq
from sardana.macroserver.msmanager import MacroServerManager
from sardana.macroserver.msmetamacro import MACRO_TEMPLATE, MacroLibrary, \
MacroClass, MacroFunction
-from sardana.macroserver.msparameter import ParamDecoder
+from sardana.macroserver.msparameter import ParamDecoder, FlatParamDecoder, \
+ WrongParam
from sardana.macroserver.macro import Macro, MacroFunc
from sardana.macroserver.msexception import UnknownMacroLibrary, \
LibraryError, UnknownMacro, MissingEnv, AbortException, StopException, \
@@ -125,13 +126,20 @@ def is_macro(macro, abs_file=None, logger=None):
return False
return True
-def recur_map(fun, data):
+def recur_map(fun, data, keep_none=False):
"""Recursive map. Similar to map, but maintains the list objects structure
+
+ :param fun: <callable> the same purpose as in map function
+ :param data: <object> the same purpose as in map function
+ :param keep_none: <bool> keep None elements without applying fun
"""
if hasattr(data, "__iter__"):
- return [recur_map(fun, elem) for elem in data]
+ return [recur_map(fun, elem, keep_none) for elem in data]
else:
- return fun(data)
+ if keep_none is True and data is None:
+ return data
+ else:
+ return fun(data)
class MacroManager(MacroServerManager):
@@ -674,7 +682,24 @@ class MacroManager(MacroServerManager):
macro_meta = self.getMacro(macro_name)
params_def = macro_meta.get_parameter()
type_manager = door.type_manager
- out_par_list = ParamDecoder(type_manager, params_def, raw_params)
+ try:
+ out_par_list = ParamDecoder(type_manager, params_def, raw_params)
+ except WrongParam, out_e:
+ # only if raw params are passed as a list e.g. using macro API
+ # execMacro("mv", mot01, 0.0) and parameters definition allows to
+ # decode it from a flat list we give it a try
+ if (isinstance(raw_params, list) and
+ FlatParamDecoder.isPossible(params_def)):
+ self.debug("Trying flat parameter decoder due to: %s" % out_e)
+ try:
+ out_par_list = FlatParamDecoder(type_manager, params_def,
+ raw_params)
+ except WrongParam, in_e:
+ msg = ("Either of: %s or %s made it impossible to decode"
+ " parameters" % (out_e.message, in_e.message))
+ raise WrongParam, msg
+ else:
+ raise out_e
return macro_meta, raw_params, out_par_list
def strMacroParamValues(self, par_list):
@@ -954,25 +979,37 @@ class MacroExecutor(Logger):
1. several parameters:
1.1 executor.prepareMacro('ascan', 'th', '0', '100', '10', '1.0')
executor.prepareMacro('mv', [['th', '0']])
+ executor.prepareMacro('mv', 'th', '0') # backwards compatibility - see note
1.2 executor.prepareMacro('ascan', 'th', 0, 100, 10, 1.0)
executor.prepareMacro('mv', [['th', 0]])
+ executor.prepareMacro('mv', 'th', 0) # backwards compatibility - see note
1.3 th = self.getObj('th');
executor.prepareMacro('ascan', th, 0, 100, 10, 1.0)
executor.prepareMacro('mv', [[th, 0]])
+ executor.prepareMacro('mv', th, 0) # backwards compatibility - see note
2. a sequence of parameters:
2.1 executor.prepareMacro(['ascan', 'th', '0', '100', '10', '1.0')
executor.prepareMacro(['mv', [['th', '0']]])
+ executor.prepareMacro(['mv', 'th', '0']) # backwards compatibility - see note
2.2 executor.prepareMacro(('ascan', 'th', 0, 100, 10, 1.0))
executor.prepareMacro(['mv', [['th', 0]]])
+ executor.prepareMacro(['mv', 'th', 0]) # backwards compatibility - see note
2.3 th = self.getObj('th');
executor.prepareMacro(['ascan', th, 0, 100, 10, 1.0])
executor.prepareMacro(['mv', [[th, 0]]])
+ executor.prepareMacro(['mv', th, 0]) # backwards compatibility - see note
3. a space separated string of parameters (this is not compatible
with multiple or nested repeat parameters, furthermore the repeat
parameter must be the last one):
executor.prepareMacro('ascan th 0 100 10 1.0')
executor.prepareMacro('mv %s 0' % motor.getName())
+ .. note:: From Sardana 2.0 the repeat parameter values must be passed
+ as lists of items. An item of a repeat parameter containing more
+ than one member is a list. In case when a macro defines only one
+ repeat parameter and it is the last parameter, for the backwards
+ compatibility reasons, the plain list of items' members is allowed.
+
:param pars: the command parameters as explained above
:param opts: keyword optional parameters for prepare
:return: a tuple of two elements: macro object, the result of preparing the macro
@@ -993,7 +1030,8 @@ class MacroExecutor(Logger):
# or args = ('mv', [[mot01, 0], [mot02, 0]])
# in case parameters were passed as objects cast them to strings
- pars = recur_map(str, pars)
+ # but maintain None's to be able to discover missing params
+ pars = recur_map(str, pars, keep_none=True)
meta_macro, _, macro_params = self._decodeMacroParameters(pars)
macro_name = meta_macro.name
@@ -1210,7 +1248,7 @@ class MacroExecutor(Logger):
except Exception, err:
exc_info = sys.exc_info()
exp_pars = {'type' : err.__class__.__name__,
- 'msg' : err.args[0],
+ 'msg' : str(err),
'args' : err.args,
'traceback' : traceback.format_exc() }
macro_exp = MacroServerException(exp_pars)
diff --git a/src/sardana/macroserver/msoptions.py b/src/sardana/macroserver/msoptions.py
index 0d3b099..def2573 100644
--- a/src/sardana/macroserver/msoptions.py
+++ b/src/sardana/macroserver/msoptions.py
@@ -44,6 +44,7 @@ class ViewOption(object):
'ShowDial' : True,
'ShowCtrlAxis' : False,
'PosFormat': -1,
+ 'OutputBlock': False
}
@classmethod
diff --git a/src/sardana/macroserver/msparameter.py b/src/sardana/macroserver/msparameter.py
index a888582..d608670 100644
--- a/src/sardana/macroserver/msparameter.py
+++ b/src/sardana/macroserver/msparameter.py
@@ -26,13 +26,15 @@
"""This module contains the definition of the macroserver parameters for
macros"""
-__all__ = ["WrongParam", "MissingParam", "UnknownParamObj", "WrongParamType",
- "TypeNames", "Type", "ParamType", "ParamRepeat", "ElementParamType",
- "ElementParamInterface", "AttrParamType", "AbstractParamTypes",
- "ParamDecoder"]
+__all__ = ["WrongParam", "MissingParam", "SupernumeraryParam",
+ "UnknownParamObj", "WrongParamType", "MissingRepeat",
+ "SupernumeraryRepeat", "TypeNames", "Type", "ParamType",
+ "ParamRepeat", "ElementParamType", "ElementParamInterface",
+ "AttrParamType", "AbstractParamTypes", "ParamDecoder"]
__docformat__ = 'restructuredtext'
+from copy import deepcopy
from lxml import etree
from taurus.core.util.containers import CaselessDict
@@ -57,6 +59,13 @@ class MissingParam(WrongParam):
self.type = 'Missing parameter'
+class SupernumeraryParam(WrongParam):
+
+ def __init__(self, *args):
+ WrongParam.__init__(self, *args)
+ self.type = 'Supernumerary parameter'
+
+
class UnknownParamObj(WrongParam):
def __init__(self, *args):
@@ -71,6 +80,20 @@ class WrongParamType(WrongParam):
self.type = 'Unknown parameter type'
+class MissingRepeat(WrongParam):
+
+ def __init__(self, *args):
+ WrongParam.__init__(self, *args)
+ self.type = 'Missing repeat'
+
+
+class SupernumeraryRepeat(WrongParam):
+
+ def __init__(self, *args):
+ WrongParam.__init__(self, *args)
+ self.type = 'Supernumerary repeat'
+
+
class TypeNames:
"""Class that holds the list of registered macro parameter types"""
@@ -321,7 +344,9 @@ class ParamDecoder:
"""Decode raw representation of parameters to parameters as passed
to the prepare or run methods.
"""
- raw_params = self.raw_params
+ # make a copy since in case of XML it could be necessary to modify
+ # the raw_params - filter out elements different than params
+ raw_params = deepcopy(self.raw_params)
params_def = self.params_def
# ignore other tags than "param" and "paramRepeat"
# e.g. sequencer may create tags like "hookPlace"
@@ -331,6 +356,12 @@ class ParamDecoder:
raw_params.remove(raw_param)
params = []
+ # check if too many parameters were passed
+ len_params_def = len(params_def)
+ if len(raw_params) > len_params_def:
+ msg = ("%r are supernumerary with respect to definition" %
+ raw_params[len_params_def:])
+ raise SupernumeraryParam, msg
# iterate over definition since missing values may just mean using
# the default values
for i, param_def in enumerate(params_def):
@@ -368,6 +399,9 @@ class ParamDecoder:
value = param_def['default_value']
if value is None:
raise MissingParam, "'%s' not specified" % name
+ else:
+ # cast to sting to fulfill with ParamType API
+ value = str(value)
param = param_type.getObj(value)
except ValueError, e:
raise WrongParamType, e.message
@@ -402,11 +436,11 @@ class ParamDecoder:
if min_rep and len_rep < min_rep:
msg = 'Found %d repetitions of param %s, min is %d' % \
(len_rep, name, min_rep)
- raise RuntimeError, msg
+ raise MissingRepeat, msg
if max_rep and len_rep > max_rep:
msg = 'Found %d repetitions of param %s, max is %d' % \
(len_rep, name, max_rep)
- raise RuntimeError, msg
+ raise SupernumeraryRepeat, msg
for raw_repeat in raw_param_repeat:
if len(param_type) > 1:
repeat = []
@@ -428,3 +462,120 @@ class ParamDecoder:
def __getattr__(self, name):
return getattr(self.params, name)
+
+
+class FlatParamDecoder:
+ """Parameter decoder useful for macros with only one repeat parameter
+ located at the very last place. It requires that the raw parameters are
+ passed as a flat list of strings.
+ """
+ def __init__(self, type_manager, params_def, raw_params):
+ self.type_manager = type_manager
+ self.params_def = params_def
+ self.raw_params = raw_params
+ self.params = None
+ if not self.isPossible(params_def):
+ msg = ("%s parameter definition is not compatible with"
+ " FlatParamDecoder" % params_def)
+ raise AttributeError, msg
+ self.decode()
+
+ @staticmethod
+ def isPossible(params_def):
+ for param_def in params_def:
+ param_type = param_def["type"]
+ if isinstance(param_type, list):
+ if param_def != params_def[-1]:
+ # repeat parameter is not the last one
+ # it won't be possible to decode it
+ return False
+ else:
+ for sub_param_def in param_type:
+ if isinstance(sub_param_def, list):
+ # nested repeat parameter
+ # it won't be possible to decode it
+ return False
+ return True
+
+ def decode(self):
+ params_def = self.params_def
+ raw_params = self.raw_params
+ _, self.params = self.decodeNormal(raw_params, params_def)
+ return self.params
+
+ def decodeNormal(self, raw_params, params_def):
+ str_len = len(raw_params)
+ obj_list = []
+ str_idx = 0
+ for i, par_def in enumerate(params_def):
+ name = par_def['name']
+ type_class = par_def['type']
+ def_val = par_def['default_value']
+ if str_idx == str_len:
+ if def_val is None:
+ if not isinstance(type_class, list):
+ raise MissingParam, "'%s' not specified" % name
+ elif isinstance(type_class, list):
+ min_rep = par_def['min']
+ if min_rep > 0:
+ msg = "'%s' demands at least %d values" %\
+ (name, min_rep)
+ raise WrongParam, msg
+ if not def_val is None:
+ new_obj = def_val
+ else:
+ if isinstance(type_class, list):
+ data = self.decodeRepeat(raw_params[str_idx:], par_def)
+ dec_token, new_obj = data
+ else:
+ type_manager = self.type_manager
+ type_name = type_class
+ type_class = type_manager.getTypeClass(type_name)
+ par_type = type_manager.getTypeObj(type_name)
+ par_str = raw_params[str_idx]
+ try:
+ val = par_type.getObj(par_str)
+ except ValueError, e:
+ raise WrongParamType, e.message
+ except UnknownParamObj, e:
+ raise WrongParam, e.message
+ if val is None:
+ msg = 'Could not create %s parameter "%s" for "%s"' % \
+ (par_type.getName(), name, par_str)
+ raise WrongParam, msg
+ dec_token = 1
+ new_obj = val
+ str_idx += dec_token
+ obj_list.append(new_obj)
+ return str_idx, obj_list
+
+ def decodeRepeat(self, raw_params, par_def):
+ name = par_def['name']
+ param_def = par_def['type']
+ min_rep = par_def['min']
+ max_rep = par_def['max']
+
+ dec_token = 0
+ obj_list = []
+ rep_nr = 0
+ while dec_token < len(raw_params):
+ if max_rep is not None and rep_nr == max_rep:
+ break
+ new_token, new_obj_list = self.decodeNormal(raw_params[dec_token:],
+ param_def)
+ dec_token += new_token
+ if len(new_obj_list) == 1:
+ new_obj_list = new_obj_list[0]
+ obj_list.append(new_obj_list)
+ rep_nr += 1
+ if rep_nr < min_rep:
+ msg = 'Found %d repetitions of param %s, min is %d' % \
+ (rep_nr, name, min_rep)
+ raise MissingRepeat, msg
+ return dec_token, obj_list
+
+ def getParamList(self):
+ return self.params
+
+ def __getattr__(self, name):
+ return getattr(self.params, name)
diff --git a/src/sardana/macroserver/recorders/output.py b/src/sardana/macroserver/recorders/output.py
index a25b898..b030f36 100644
--- a/src/sardana/macroserver/recorders/output.py
+++ b/src/sardana/macroserver/recorders/output.py
@@ -124,7 +124,7 @@ class JsonRecorder(DataRecorder):
class OutputRecorder(DataRecorder):
def __init__(self, stream, cols=None, number_fmt='%8.4f', col_width=8,
- col_sep=' ', **pars):
+ col_sep=' ', output_block=False, **pars):
DataRecorder.__init__(self, **pars)
self._stream = stream
if not number_fmt.startswith('%'):
@@ -140,6 +140,7 @@ class OutputRecorder(DataRecorder):
else:
cols = None
self._columns = cols
+ self._output_block = output_block
def _startRecordList(self, recordlist):
starttime = recordlist.getEnvironValue('starttime').ctime()
@@ -259,7 +260,11 @@ class OutputRecorder(DataRecorder):
cells.append(cell)
scan_line = self._col_sep.join(cells)
- self._stream.output(scan_line)
+ if self._output_block:
+ self._stream.outputBlock(scan_line)
+ else:
+ self._stream.output(scan_line)
+
self._stream.flushOutput()
def _addCustomData(self, value, name, **kwargs):
diff --git a/src/sardana/macroserver/scan/gscan.py b/src/sardana/macroserver/scan/gscan.py
index 8de7866..9ab29dc 100644
--- a/src/sardana/macroserver/scan/gscan.py
+++ b/src/sardana/macroserver/scan/gscan.py
@@ -370,14 +370,23 @@ class GScan(Logger):
def _getOutputRecorder(self):
cols = None
+ output_block = False
try:
cols = self.macro.getEnv('OutputCols')
except InterruptException:
raise
except:
pass
+
+ try:
+ output_block = self.macro.getViewOption('OutputBlock')
+ except InterruptException:
+ raise
+ except:
+ pass
+
return self._rec_manager.getRecorderClass("OutputRecorder")(
- self.macro, cols=cols, number_fmt='%g')
+ self.macro, cols=cols, number_fmt='%g', output_block=output_block)
def _getFileRecorders(self):
macro = self.macro
@@ -558,7 +567,7 @@ class GScan(Logger):
instrument = master['instrument']
#add channels from measurement group
- channels_info = self.measurement_group.getChannelsInfo()
+ channels_info = self.measurement_group.getChannelsEnabledInfo()
counters = []
for ci in channels_info:
instrument = ci.instrument or ''
@@ -592,7 +601,11 @@ class GScan(Logger):
data_units=ci.unit)
data_desc.append(column)
counters.append(column.name)
- counters.remove(master['full_name'])
+ try:
+ counters.remove(master['full_name'])
+ except ValueError:
+ # timer may be disabled
+ pass
env['counters'] = counters
for extra_column in self._extra_columns:
diff --git a/src/sardana/pool/pool.py b/src/sardana/pool/pool.py
index 9ef4f35..e4cdba1 100644
--- a/src/sardana/pool/pool.py
+++ b/src/sardana/pool/pool.py
@@ -35,7 +35,12 @@ __docformat__ = 'restructuredtext'
import os.path
import logging.handlers
-from taurus.core.taurusvalidator import AttributeNameValidator
+try:
+ from taurus.core.taurusvalidator import AttributeNameValidator as\
+ TangoAttributeNameValidator
+except ImportError:
+ #TODO: For Taurus 4 compatibility
+ from taurus.core.tango.tangovalidator import TangoAttributeNameValidator
from taurus.core.util.containers import CaselessDict
from sardana import InvalidId, ElementType, TYPE_ACQUIRABLE_ELEMENTS, \
@@ -515,7 +520,7 @@ class Pool(PoolContainer, PoolObject, SardanaElementManager, SardanaIDManager):
if type(elem_id) is int:
self.pool.get_element(id=elem_id)
else:
- tg_attr_validator = AttributeNameValidator()
+ tg_attr_validator = TangoAttributeNameValidator()
params = tg_attr_validator.getParams(elem_id)
if params is None:
raise Exception("Invalid channel name %s" % elem_id)
diff --git a/src/sardana/pool/poolacquisition.py b/src/sardana/pool/poolacquisition.py
index 9833ce3..2ee1061 100644
--- a/src/sardana/pool/poolacquisition.py
+++ b/src/sardana/pool/poolacquisition.py
@@ -454,20 +454,18 @@ class Pool0DAcquisition(PoolAction):
return True
def action_loop(self):
- i = 0
-
states, values = {}, {}
for element in self._channels:
states[element] = None
values[element] = None
nap = self._acq_sleep_time
- while not (self._stopped or self._aborted):
+ while True:
self.read_value(ret=values)
for acquirable, value in values.items():
acquirable.put_value(value)
-
- i += 1
+ if self._stopped or self._aborted:
+ break
time.sleep(nap)
with ActionContext(self):
diff --git a/src/sardana/pool/poolbasegroup.py b/src/sardana/pool/poolbasegroup.py
index 37ff0aa..8986730 100644
--- a/src/sardana/pool/poolbasegroup.py
+++ b/src/sardana/pool/poolbasegroup.py
@@ -30,7 +30,12 @@ __all__ = ["PoolBaseGroup"]
__docformat__ = 'restructuredtext'
-from taurus.core.taurusvalidator import AttributeNameValidator
+try:
+ from taurus.core.taurusvalidator import AttributeNameValidator as\
+ TangoAttributeNameValidator
+except ImportError:
+ #TODO: For Taurus 4 compatibility
+ from taurus.core.tango.tangovalidator import TangoAttributeNameValidator
from sardana import State, ElementType, TYPE_PHYSICAL_ELEMENTS
from sardana.pool.poolexternal import PoolExternalObject
@@ -168,7 +173,7 @@ class PoolBaseGroup(PoolContainer):
# a tango channel or non internal element (ex: ioregister or motor
# in measurement group)
if not internal:
- validator = AttributeNameValidator()
+ validator = TangoAttributeNameValidator()
params = validator.getParams(user_element_id)
params['pool'] = self._get_pool()
user_element = PoolExternalObject(**params)
diff --git a/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py b/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py
index 0fd2162..ef3b85f 100644
--- a/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py
+++ b/src/sardana/pool/poolcontrollers/HklPseudoMotorController.py
@@ -469,6 +469,9 @@ class DiffracBasis(PseudoMotorController):
elif engine_name == "eulerians":
values = [pseudo_pos[8], pseudo_pos[9], pseudo_pos[10]]
+ # getWavelength updates wavelength in the library in case automatic
+ # energy update is set. Needed before computing trajectories.
+
self.getWavelength()
solutions = self._solutions(values, curr_physical_pos)
@@ -484,6 +487,9 @@ class DiffracBasis(PseudoMotorController):
# physical values are not equal to the expected len of the
# geometry axes.
+ # getWavelength updates wavelength in the library in case automatic
+ # energy update is set. Needed before computing trajectories.
+
self.getWavelength()
@@ -748,6 +754,11 @@ class DiffracBasis(PseudoMotorController):
# (len(values),
# len(self.engine.pseudo_axis_names_get()),
# self.engine.name_get())
+ # getWavelength updates wavelength in the library in case automatic
+ # energy update is set. Needed before computing trajectories.
+
+ self.getWavelength()
+
curr_physical_pos = self.geometry.axis_values_get(USER)
solutions = self._solutions(values, curr_physical_pos)
self.trajectorylist = [item.geometry_get().axis_values_get(USER)
@@ -960,9 +971,13 @@ class DiffracBasis(PseudoMotorController):
geometry.axis_values_set(values[6:], USER)
reflection.geometry_set(geometry)
- def setLoadCrystal(self, value): # value: complete path of the file with the crystal to set
+ def setLoadCrystal(self, value):
+ """Load crystal information from a file. Ignore wavelength information.
+
+ :param value: complete path of the file with the crystal to set
+ :type value: string
+ """
# Read the file
-
with open(value, 'r') as crystal_file:
self._loadcrystal = value
@@ -981,10 +996,6 @@ class DiffracBasis(PseudoMotorController):
# Remove all reflections from crystal (there should not be any ... but just in case)
for ref in self.sample.reflections_get():
self.sample.del_reflection(ref)
- elif line.find("Wavelength") != -1:
- line = line.replace(" ", "")
- wavelength = float(line.split("Wavelength",1)[1]) # The value will be set after creating the new geometry with the reflections
- self.geometry.wavelength_set(wavelength, USER)
elif line.find("A") != -1 and line.find("B") != -1 and line.find("C") != -1:
par_line = line.split(" ")
avalue = float(par_line[1])
@@ -1323,7 +1334,10 @@ class DiffracBasis(PseudoMotorController):
self._autoenergyupdate = value
def setComputeHKL(self, value):
-
+
+ # getWavelength updates wavelength in the library in case automatic
+ # energy update is set. Needed before computing trajectories.
+
self.getWavelength()
diff --git a/src/sardana/pool/poolmeasurementgroup.py b/src/sardana/pool/poolmeasurementgroup.py
index 25cab6d..7e9269e 100644
--- a/src/sardana/pool/poolmeasurementgroup.py
+++ b/src/sardana/pool/poolmeasurementgroup.py
@@ -30,7 +30,12 @@ __all__ = ["PoolMeasurementGroup"]
__docformat__ = 'restructuredtext'
-from taurus.core.taurusvalidator import AttributeNameValidator
+try:
+ from taurus.core.taurusvalidator import AttributeNameValidator as\
+ TangoAttributeNameValidator
+except ImportError:
+ #TODO: For Taurus 4 compatibility
+ from taurus.core.tango.tangovalidator import TangoAttributeNameValidator
from sardana import State, ElementType, \
TYPE_EXP_CHANNEL_ELEMENTS, TYPE_TIMERABLE_ELEMENTS
@@ -114,21 +119,9 @@ class PoolMeasurementGroup(PoolGroupElement):
acq_name = "%s.Acquisition" % self._name
return PoolAcquisition(self, acq_name)
- def _calculate_element_state(self, elem, elem_state_info):
- if elem.get_type() == ElementType.ZeroDExpChannel:
- if elem_state_info[0] == State.Moving:
- elem_state_info = State.On, elem_state_info[1]
- return PoolGroupElement._calculate_element_state(self, elem,
- elem_state_info)
-
def on_element_changed(self, evt_src, evt_type, evt_value):
name = evt_type.name
if name == 'state':
- if evt_src.get_type() == ElementType.ZeroDExpChannel:
- # 0D channels are "passive", which means they cannot contribute
- # to set the measurement group into a moving state
- if evt_value in (State.On, State.Moving):
- return
state, status = self._calculate_states()
self.set_state(state, propagate=2)
self.set_status("\n".join(status))
@@ -368,7 +361,7 @@ class PoolMeasurementGroup(PoolGroupElement):
unit_data['channels'] = channels = {}
for ch_name, ch_data in u_data['channels'].items():
if external:
- validator = AttributeNameValidator()
+ validator = TangoAttributeNameValidator()
params = validator.getParams(ch_data['full_name'])
params['pool'] = self.pool
channel = PoolExternalObject(**params)
diff --git a/src/sardana/pool/poolzerodexpchannel.py b/src/sardana/pool/poolzerodexpchannel.py
index 95da098..35c4168 100644
--- a/src/sardana/pool/poolzerodexpchannel.py
+++ b/src/sardana/pool/poolzerodexpchannel.py
@@ -80,14 +80,22 @@ class SumAccumulation(BaseAccumulation):
self.sum = 0.0
def update_value(self, value, timestamp):
- self.sum += value
+ if not value is None:
+ self.sum += value
+ self.value = self.sum
class AverageAccumulation(SumAccumulation):
+ def clear(self):
+ SumAccumulation.clear(self)
+ self.nb_valid_points = 0
+
def update_value(self, value, timestamp):
SumAccumulation.update_value(self, value, timestamp)
- self.value = self.sum / self.nb_points
+ if not value is None:
+ self.nb_valid_points += 1
+ self.value = self.sum / self.nb_valid_points
class IntegralAccumulation(BaseAccumulation):
@@ -152,7 +160,8 @@ class Value(SardanaAttribute):
def _get_value(self):
value = self._accumulation.value
if value is None:
- raise Exception("Value not available: no acquisition done so far!")
+ raise Exception("Value not available: no successful acquisition"
+ " done so far!")
return value
def get_value_buffer(self):
diff --git a/src/sardana/release.py b/src/sardana/release.py
index 29fdf54..681a7b2 100644
--- a/src/sardana/release.py
+++ b/src/sardana/release.py
@@ -49,7 +49,7 @@ name = 'sardana'
#: the new substring. We have to avoid using either dashes or underscores,
#: because bdist_rpm does not accept dashes (an RPM) convention, and
#: bdist_deb does not accept underscores (a Debian convention).
-version_info = (2, 0, 0, 'rc', 0)
+version_info = (2, 1, 0, 'rc', 0)
version = '.'.join(map(str, version_info[:3]))
revision = str(version_info[4])
diff --git a/src/sardana/requirements.py b/src/sardana/requirements.py
index f8e8de2..09db0e3 100644
--- a/src/sardana/requirements.py
+++ b/src/sardana/requirements.py
@@ -77,6 +77,9 @@ def check_requirements(exec_name=None):
print "%s requires PyTango %s. Installed version is %s" % (exec_name, pytangover_str_, pytangover_str)
sys.exit(-1)
+ # TODO: add itango as runtime dependency of spock
+ # now it is not possible because itango does not provide info about its version
+
taurusver = None
try:
import taurus
diff --git a/src/sardana/spock/ipython_00_10/genutils.py b/src/sardana/spock/ipython_00_10/genutils.py
index 4f27ffc..e1ec926 100644
--- a/src/sardana/spock/ipython_00_10/genutils.py
+++ b/src/sardana/spock/ipython_00_10/genutils.py
@@ -59,7 +59,7 @@ import imp
import IPython
import IPython.genutils
import PyTango
-import PyTango.ipython
+import itango
from taurus.core.taurushelper import Factory
from taurus.core.util.codecs import CodecFactory
@@ -78,6 +78,8 @@ requirements = {
"IPython" : ("0.10.0", "0.10.0"),
"Python" : ("2.6.0", "2.6.0"),
"PyTango" : ("7.1.2", "7.2.0"),
+ # for the moment just for reference since itango does not provide version
+ "itango" : ("0.1.4", "0.1.4"),
"taurus.core" : ("2.0.0", "2.1.0")
}
@@ -193,8 +195,8 @@ def get_python_version_number():
def get_ipython_dir():
"""Find the ipython local directory. Usually is <home>/.ipython"""
- if hasattr(PyTango.ipython, "get_ipython_dir"):
- return PyTango.ipython.get_ipython_dir()
+ if hasattr(itango, "get_ipython_dir"):
+ return itango.get_ipython_dir()
if hasattr(IPython.iplib, 'get_ipython_dir'):
# Starting from ipython 0.9 they hadded this method
@@ -215,8 +217,8 @@ def get_ipython_dir():
def get_ipython_profiles():
"""Helper function to find all ipython profiles"""
- if hasattr(PyTango.ipython, "get_ipython_profiles"):
- return PyTango.ipython.get_ipython_profiles()
+ if hasattr(itango, "get_ipython_profiles"):
+ return itango.get_ipython_profiles()
ret = []
ipydir = get_ipython_dir()
@@ -510,6 +512,12 @@ def check_requirements():
errMsg += "Current version is unknown (most surely too old)\n"
errPyTango = True
+ # TODO: verify the version whenever itango starts to provide it
+ try:
+ import itango
+ except ImportError:
+ errMsg += "Spock needs itango version >= 0.1.4. No itango installation found\n"
+
if currTaurusCore is None:
errMsg += "Spock needs taurus.core version >= %s. No taurus.core installation found\n" % requirements["taurus.core"][0]
errTaurusCore = True
@@ -550,7 +558,8 @@ def _get_dev(dev_type):
return ret
dev_obj_name = '%s_NAME' % dev_type
- dev_name = ip.user_ns[dev_obj_name]
+ # TODO: For Taurus 4 compatibility
+ dev_name = "tango://%s" % ip.user_ns[dev_obj_name]
factory = Factory()
dev_obj = factory.getDevice(dev_name)
ip.user_ns[dev_type] = PyTango.DeviceProxy(dev_name)
@@ -956,7 +965,7 @@ def init_post_spock(ip):
def init_spock(ip, macro_server, door):
init_pre_spock(ip, macro_server, door)
- PyTango.ipython.init_ipython(ip)
+ itango.init_ipython(ip)
init_post_spock(ip)
diff --git a/src/sardana/spock/ipython_00_11/genutils.py b/src/sardana/spock/ipython_00_11/genutils.py
index 823bd79..49ad81d 100644
--- a/src/sardana/spock/ipython_00_11/genutils.py
+++ b/src/sardana/spock/ipython_00_11/genutils.py
@@ -88,6 +88,8 @@ requirements = {
"IPython" : ("0.11.0", "0.12.0"),
"Python" : ("2.6.0", "2.6.0"),
"PyTango" : ("7.2.0", "7.2.3"),
+ # for the moment just for reference since itango does not provide version
+ "itango" : ("0.1.4", "0.1.4"),
"taurus.core" : ("3.0.0", "3.0.0")
}
@@ -471,6 +473,12 @@ def check_requirements():
errMsg += "Current version is unknown (most surely too old)\n"
errPyTango = True
+ # TODO: verify the version whenever itango starts to provide it
+ try:
+ import itango
+ except ImportError:
+ errMsg += "Spock needs itango version >= 0.1.4. No itango installation found\n"
+
if currTaurusCore is None:
errMsg += "Spock needs taurus.core version >= %s. No taurus.core installation found\n" % requirements["taurus.core"][0]
errTaurusCore = True
@@ -519,7 +527,8 @@ def _get_dev(dev_type):
if hasattr(spock_config, taurus_dev_var):
taurus_dev = getattr(spock_config, taurus_dev_var)
if taurus_dev is None:
- dev_name = getattr(spock_config, dev_type + '_name')
+ # TODO: For Taurus 4 compatibility
+ dev_name = "tango://%s" % getattr(spock_config, dev_type + '_name')
factory = Factory()
taurus_dev = factory.getDevice(dev_name)
import PyTango
@@ -593,19 +602,9 @@ def unexpose_variable(name):
user_ns = get_shell().user_ns
del user_ns[name]
-def create_spock_profile(userdir, dft_profile, profile, door_name=None):
- """Create a profile file from a profile template file """
- if not os.path.isdir(userdir):
- ProfileDir.create_profile_dir(userdir)
- p_dir = ProfileDir.create_profile_dir_by_name(userdir, profile)
+def _create_config_file(location, door_name=None):
config_file_name = BaseIPythonApplication.config_file_name.default_value
- abs_config_file_name = os.path.join(p_dir.location, config_file_name)
- create_config = True
- if os.path.isfile(abs_config_file_name):
- create_config = ask_yes_no("Spock configuration file already exists. "\
- "Do you wish to replace it?", default='y')
- if not create_config:
- return
+ abs_config_file_name = os.path.join(location, config_file_name)
src_data = """\
\"\"\"Settings for Spock session\"\"\"
@@ -617,7 +616,8 @@ def create_spock_profile(userdir, dft_profile, profile, door_name=None):
# door_name = {door_name}
#
-import PyTango.ipython
+import itango
+
import sardana.spock.genutils
from sardana.spock.config import Spock
@@ -636,7 +636,7 @@ config.IPKernelApp.pylab = 'inline'
# Discover door name
#
if door_name is None:
- door_name = get_device_from_user("Door", profile)
+ door_name = get_device_from_user("Door")
else:
full_door_name, door_name, _ = from_name_to_tango(door_name)
door_name = full_door_name
@@ -650,7 +650,7 @@ config.IPKernelApp.pylab = 'inline'
macroserver_name=ms_name,
door_name=door_name)
- sys.stdout.write('Storing %s in %s... ' % (config_file_name, p_dir.location))
+ sys.stdout.write('Storing %s in %s... ' % (config_file_name, location))
sys.stdout.flush()
@@ -659,18 +659,49 @@ config.IPKernelApp.pylab = 'inline'
f.close()
sys.stdout.write(MSG_DONE + '\n')
-def check_for_upgrade(ipy_profile_file, ipythondir, session, profile):
- # Check if the current profile is up to date with the spock version
+def create_spock_profile(userdir, profile, door_name=None):
+ """Create spock profile directory and configuration file from a template
+ file
+
+ :param userdir: directory where the spock profile will be created
+ :param profile: profile name
+ :param door_name: door name, if None, user will be asked for the door name
+ """
+
+ if not os.path.isdir(userdir):
+ ProfileDir.create_profile_dir(userdir)
+ p_dir = ProfileDir.create_profile_dir_by_name(userdir, profile)
+ ipy_profile_dir = p_dir.location
+
+ _create_config_file(ipy_profile_dir)
+
+def upgrade_spock_profile(ipy_profile_dir, door_name):
+ """Upgrade spock profile by recreating configuration file from scratch
+
+ :param ipy_profile_dir: directory with the spock profile
+ :param door_name: door name
+ """
+ _create_config_file(ipy_profile_dir, door_name)
+
+def check_for_upgrade(ipy_profile_dir):
+ """Check if the current profile is up to date with the spock version
+
+ :param ipy_profile_dir: directory with the spock profile
+ """
spock_profile_ver_str = '0.0.0'
door_name = None
+ config_file_name = BaseIPythonApplication.config_file_name.default_value
+ abs_config_file_name = os.path.join(ipy_profile_dir, config_file_name)
+
# search for version and door inside the ipy_profile file
- for i, line in enumerate(ipy_profile_file):
- if i > 20 : break; # give up after 20 lines
- if line.startswith('# spock_creation_version = '):
- spock_profile_ver_str = line[line.index('=')+1:].strip()
- if line.startswith('# door_name = '):
- door_name = line[line.index('=')+1:].strip()
+ with file(abs_config_file_name, "r") as ipy_config_file:
+ for i, line in enumerate(ipy_config_file):
+ if i > 20 : break; # give up after 20 lines
+ if line.startswith('# spock_creation_version = '):
+ spock_profile_ver_str = line[line.index('=')+1:].strip()
+ if line.startswith('# door_name = '):
+ door_name = line[line.index('=')+1:].strip()
# convert version from string to numbers
spocklib_ver = translate_version_str2int(release.version)
@@ -695,7 +726,7 @@ def check_for_upgrade(ipy_profile_file, ipythondir, session, profile):
prompt = 'Do you wish to upgrade now (warn: this will shutdown the current spock session) ([y]/n)? '
r = raw_input(prompt) or 'y'
if r.lower() == 'y':
- create_spock_profile(ipythondir, session, profile, door_name)
+ upgrade_spock_profile(ipy_profile_dir, door_name)
sys.exit(0)
def get_args(argv):
@@ -729,7 +760,7 @@ def get_args(argv):
'one now ([y]/n)? ' % profile
r = raw_input(prompt) or 'y'
if r.lower() == 'y':
- create_spock_profile(ipython_dir, session, profile)
+ create_spock_profile(ipython_dir, profile)
else:
sys.stdout.write('No spock door extension profile was created. Starting normal spock...\n')
sys.stdout.flush()
@@ -895,7 +926,7 @@ object? -> Details about 'object'. ?object also works, ?? prints more.
# ------------------------------------
i_app = config.BaseIPythonApplication
extensions = getattr(i_app, 'extensions', [])
- extensions.extend(["PyTango.ipython", "sardana.spock"])
+ extensions.extend(["itango", "sardana.spock"])
i_app.extensions = extensions
# ------------------------------------
@@ -1095,7 +1126,7 @@ def prepare_cmdline(argv=None):
ipython_dir = get_ipython_dir()
try:
- ProfileDir.find_profile_dir_by_name(ipython_dir, profile)
+ pd = ProfileDir.find_profile_dir_by_name(ipython_dir, profile)
except ProfileDirError:
r = ''
while not r in ('y', 'n'):
@@ -1103,7 +1134,7 @@ def prepare_cmdline(argv=None):
"one now ([y]/n)? " % profile
r = raw_input(prompt) or 'y'
if r.lower() == 'y':
- create_spock_profile(ipython_dir, session, profile)
+ create_spock_profile(ipython_dir, profile)
else:
sys.stdout.write('No spock profile was created. '
'Starting ipython with default profile...\n')
@@ -1113,6 +1144,9 @@ def prepare_cmdline(argv=None):
if arg.startswith('--profile='):
argv.remove(arg)
return
+ else:
+ ipy_profile_dir = pd.location # directory with the spock profile
+ check_for_upgrade(ipy_profile_dir)
if append_profile:
argv.append("--profile=" + profile)
diff --git a/src/sardana/spock/ipython_01_00/genutils.py b/src/sardana/spock/ipython_01_00/genutils.py
index 0ea510f..ccb6b10 100644
--- a/src/sardana/spock/ipython_01_00/genutils.py
+++ b/src/sardana/spock/ipython_01_00/genutils.py
@@ -95,6 +95,8 @@ requirements = {
"IPython" : ("0.11.0", "0.12.0"),
"Python" : ("2.6.0", "2.6.0"),
"PyTango" : ("7.2.0", "7.2.3"),
+ # for the moment just for reference since itango does not provide version
+ "itango" : ("0.1.4", "0.1.4"),
"taurus.core" : ("3.0.0", "3.0.0")
}
@@ -478,6 +480,12 @@ def check_requirements():
errMsg += "Current version is unknown (most surely too old)\n"
errPyTango = True
+ # TODO: verify the version whenever itango starts to provide it
+ try:
+ import itango
+ except ImportError:
+ errMsg += "Spock needs itango version >= 0.1.4. No itango installation found\n"
+
if currTaurusCore is None:
errMsg += "Spock needs taurus.core version >= %s. No taurus.core installation found\n" % requirements["taurus.core"][0]
errTaurusCore = True
@@ -526,7 +534,8 @@ def _get_dev(dev_type):
if hasattr(spock_config, taurus_dev_var):
taurus_dev = getattr(spock_config, taurus_dev_var)
if taurus_dev is None:
- dev_name = getattr(spock_config, dev_type + '_name')
+ # TODO: For Taurus 4 compatibility
+ dev_name = "tango://%s" % getattr(spock_config, dev_type + '_name')
factory = Factory()
taurus_dev = factory.getDevice(dev_name)
import PyTango
@@ -600,11 +609,7 @@ def unexpose_variable(name):
user_ns = get_shell().user_ns
del user_ns[name]
-def create_spock_profile(userdir, dft_profile, profile, door_name=None):
- """Create a profile file from a profile template file """
- if not os.path.isdir(userdir):
- ProfileDir.create_profile_dir(userdir)
- p_dir = ProfileDir.create_profile_dir_by_name(userdir, profile)
+def _create_config_file(location, door_name=None):
###########################################################################
# NOTE: BaseIPythonApplication.config_file_name.default_value should return
# the config file name, but it returns an empty string instead (at least
@@ -613,13 +618,7 @@ def create_spock_profile(userdir, dft_profile, profile, door_name=None):
config_file_name = BaseIPythonApplication.config_file_name.default_value
config_file_name = config_file_name or 'ipython_config.py'
###########################################################################
- abs_config_file_name = os.path.join(p_dir.location, config_file_name)
- create_config = True
- if os.path.isfile(abs_config_file_name):
- create_config = ask_yes_no("Spock configuration file already exists. "\
- "Do you wish to replace it?", default='y')
- if not create_config:
- return
+ abs_config_file_name = os.path.join(location, config_file_name)
src_data = """\
\"\"\"Settings for Spock session\"\"\"
@@ -631,7 +630,8 @@ def create_spock_profile(userdir, dft_profile, profile, door_name=None):
# door_name = {door_name}
#
-import PyTango.ipython
+import itango
+
import sardana.spock.genutils
from sardana.spock.config import Spock
@@ -650,7 +650,7 @@ config.IPKernelApp.pylab = 'inline'
# Discover door name
#
if door_name is None:
- door_name = get_device_from_user("Door", profile)
+ door_name = get_device_from_user("Door" )
else:
full_door_name, door_name, _ = from_name_to_tango(door_name)
door_name = full_door_name
@@ -664,7 +664,7 @@ config.IPKernelApp.pylab = 'inline'
macroserver_name=ms_name,
door_name=door_name)
- sys.stdout.write('Storing %s in %s... ' % (config_file_name, p_dir.location))
+ sys.stdout.write('Storing %s in %s... ' % (config_file_name, location))
sys.stdout.flush()
with file(abs_config_file_name, "w") as f:
@@ -672,18 +672,57 @@ config.IPKernelApp.pylab = 'inline'
f.close()
sys.stdout.write(MSG_DONE + '\n')
-def check_for_upgrade(ipy_profile_file, ipythondir, session, profile):
- # Check if the current profile is up to date with the spock version
+
+def create_spock_profile(userdir, profile, door_name=None):
+ """Create spock profile directory and configuration file from a template
+ file
+
+ :param userdir: directory where the spock profile will be created
+ :param profile: profile name
+ :param door_name: door name, if None, user will be asked for the door name
+ :"""
+ if not os.path.isdir(userdir):
+ ProfileDir.create_profile_dir(userdir)
+ p_dir = ProfileDir.create_profile_dir_by_name(userdir, profile)
+
+ ipy_profile_dir = p_dir.location
+
+ _create_config_file(ipy_profile_dir)
+
+def upgrade_spock_profile(ipy_profile_dir, door_name):
+ """Upgrade spock profile by recreating configuration file from scratch
+
+ :param ipy_profile_dir: directory with the spock profile
+ :param door_name: door name
+ """
+ _create_config_file(ipy_profile_dir, door_name)
+
+def check_for_upgrade(ipy_profile_dir):
+ """Check if the current profile is up to date with the spock version
+
+ :param ipy_profile_dir: directory with the spock profile
+ """
spock_profile_ver_str = '0.0.0'
door_name = None
+ ###########################################################################
+ # NOTE: BaseIPythonApplication.config_file_name.default_value should return
+ # the config file name, but it returns an empty string instead (at least
+ # in some cases). For now, we give a hardcoded name if it is empty
+ # TODO: Check why this is the case
+ config_file_name = BaseIPythonApplication.config_file_name.default_value
+ config_file_name = config_file_name or 'ipython_config.py'
+ ###########################################################################
+ abs_config_file_name = os.path.join(ipy_profile_dir, config_file_name)
+
# search for version and door inside the ipy_profile file
- for i, line in enumerate(ipy_profile_file):
- if i > 20 : break; # give up after 20 lines
- if line.startswith('# spock_creation_version = '):
- spock_profile_ver_str = line[line.index('=')+1:].strip()
- if line.startswith('# door_name = '):
- door_name = line[line.index('=')+1:].strip()
+ with file(abs_config_file_name, "r") as ipy_config_file:
+ for i, line in enumerate(ipy_config_file):
+ if i > 20 : break; # give up after 20 lines
+ if line.startswith('# spock_creation_version = '):
+ spock_profile_ver_str = line[line.index('=')+1:].strip()
+ if line.startswith('# door_name = '):
+ door_name = line[line.index('=')+1:].strip()
# convert version from string to numbers
spocklib_ver = translate_version_str2int(release.version)
@@ -708,7 +747,7 @@ def check_for_upgrade(ipy_profile_file, ipythondir, session, profile):
prompt = 'Do you wish to upgrade now (warn: this will shutdown the current spock session) ([y]/n)? '
r = raw_input(prompt) or 'y'
if r.lower() == 'y':
- create_spock_profile(ipythondir, session, profile, door_name)
+ upgrade_spock_profile(ipy_profile_dir, door_name)
sys.exit(0)
def get_args(argv):
@@ -742,7 +781,7 @@ def get_args(argv):
'one now ([y]/n)? ' % profile
r = raw_input(prompt) or 'y'
if r.lower() == 'y':
- create_spock_profile(ipython_dir, session, profile)
+ create_spock_profile(ipython_dir, profile)
else:
sys.stdout.write('No spock door extension profile was created. Starting normal spock...\n')
sys.stdout.flush()
@@ -909,7 +948,7 @@ object? -> Details about 'object'. ?object also works, ?? prints more.
# ------------------------------------
i_app = config.BaseIPythonApplication
extensions = getattr(i_app, 'extensions', [])
- extensions.extend(["PyTango.ipython", "sardana.spock"])
+ extensions.extend(["itango", "sardana.spock"])
i_app.extensions = extensions
# ------------------------------------
@@ -1103,7 +1142,7 @@ def prepare_cmdline(argv=None):
ipython_dir = get_ipython_dir()
try:
- ProfileDir.find_profile_dir_by_name(ipython_dir, profile)
+ pd = ProfileDir.find_profile_dir_by_name(ipython_dir, profile)
except ProfileDirError:
r = ''
while not r in ('y', 'n'):
@@ -1111,7 +1150,7 @@ def prepare_cmdline(argv=None):
"one now ([y]/n)? " % profile
r = raw_input(prompt) or 'y'
if r.lower() == 'y':
- create_spock_profile(ipython_dir, session, profile)
+ create_spock_profile(ipython_dir, profile)
else:
sys.stdout.write('No spock profile was created. '
'Starting ipython with default profile...\n')
@@ -1121,6 +1160,9 @@ def prepare_cmdline(argv=None):
if arg.startswith('--profile='):
argv.remove(arg)
return
+ else:
+ ipy_profile_dir = pd.location # directory with the spock profile
+ check_for_upgrade(ipy_profile_dir)
if append_profile:
argv.append("--profile=" + profile)
diff --git a/src/sardana/spock/magic.py b/src/sardana/spock/magic.py
index 325c8b8..e5ac0a3 100644
--- a/src/sardana/spock/magic.py
+++ b/src/sardana/spock/magic.py
@@ -31,7 +31,6 @@ __all__ = ['expconf', 'showscan', 'spsplot', 'debug_completer',
'post_mortem', 'macrodata', 'edmac', 'spock_late_startup_hook',
'spock_pre_prompt_hook']
-
from .genutils import page, get_door, get_macro_server, ask_yes_no, arg_split
from .genutils import MSG_DONE, MSG_FAILED
from .genutils import get_ipapi
@@ -43,11 +42,14 @@ def expconf(self, parameter_s=''):
try:
from sardana.taurus.qt.qtgui.extra_sardana import ExpDescriptionEditor
except:
- print "Error importing ExpDescriptionEditor "\
+ print "Error importing ExpDescriptionEditor " \
"(hint: is taurus extra_sardana installed?)"
return
- doorname = get_door().name()
-
+ try:
+ doorname = get_door().name()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorname = get_door().fullname
#===========================================================================
## ugly hack to avoid ipython/qt thread problems #e.g. see
## https://sourceforge.net/p/sardana/tickets/10/
@@ -55,14 +57,15 @@ def expconf(self, parameter_s=''):
## widget open after closing spock
## @todo: investigate cause of segfaults when using launching qt widgets from ipython
#
- #w = ExpDescriptionEditor(door=doorname)
- #w.show() #launching it like this, produces the problem of https://sourceforge.net/p/sardana/tickets/10/
+ # w = ExpDescriptionEditor(door=doorname)
+ # w.show() #launching it like this, produces the problem of https://sourceforge.net/p/sardana/tickets/10/
import subprocess
import sys
+
fname = sys.modules[ExpDescriptionEditor.__module__].__file__
args = ['python', fname, doorname]
subprocess.Popen(args)
- #===========================================================================
+ # ===========================================================================
def showscan(self, parameter_s=''):
@@ -122,6 +125,7 @@ def debug(self, parameter_s=''):
def www(self, parameter_s=''):
"""What went wrong. Prints the error message from the last macro execution"""
import PyTango
+
door = get_door()
try:
last_macro = door.getLastRunningMacro()
@@ -139,6 +143,7 @@ def www(self, parameter_s=''):
stream=door.Error)
door.writeln(str(e), stream=door.Error)
import traceback
+
traceback.print_exc()
@@ -156,7 +161,7 @@ def post_mortem(self, parameter_s='', from_www=False):
msg = "\n".join(logger.read(cache=False).value)
except:
from_www = True
-
+
if from_www:
msg = "------------------------------\n" \
"Server is offline.\n" \
@@ -165,6 +170,7 @@ def post_mortem(self, parameter_s='', from_www=False):
msg += "\n".join(logger.getLogBuffer())
page(msg)
+
def macrodata(self, parameter_s=''):
"""macrodata
@@ -173,10 +179,11 @@ def macrodata(self, parameter_s=''):
macro_data = door.read_attribute("RecordData")
from taurus.core.util.codecs import CodecFactory
+
factory = CodecFactory()
- data = factory.decode(macro_data.value)
+ data = factory.decode(macro_data.value)
return data
-
+
def edmac(self, parameter_s=''):
"""edmac <macro name> [<module>]
@@ -195,14 +202,27 @@ def edmac(self, parameter_s=''):
if len(pars) == 1:
macro_name = pars[0]
- macro_info = ms.getMacroInfoObj(macro_name)
- if macro_info is None:
- print "Macro '%s' could not be found" % macro_name
- return
- macro_lib = macro_info.module
+ is_new_macro = False
else:
+ is_new_macro = True
macro_name, macro_lib = pars
+ macro_info_obj = ms.getMacroInfoObj(macro_name)
+ if not is_new_macro:
+ if macro_info_obj is None:
+ print "Macro '%s' could not be found" % macro_name
+ return
+ macro_lib = macro_info_obj.module
+
+ if is_new_macro:
+ if macro_info_obj is not None:
+ msg = ('Do you want to create macro "%s" in module "%s" that will'
+ ' override the already existing macro in module "%s"'
+ % (macro_name, macro_lib, macro_info_obj.module))
+ if not ask_yes_no(msg, 'y'):
+ print "Aborting edition..."
+ return
+
macro_info = (macro_lib, macro_name)
print 'Opening %s.%s...' % macro_info
@@ -240,7 +260,7 @@ def edmac(self, parameter_s=''):
else:
print "Discarding changes..."
- #if os.path.exists(local_fname):
+ # if os.path.exists(local_fname):
# if ask_yes_no('Delete temporary file \'%s\'?' % local_fname, 'y'):
# os.remove(local_fname)
# bkp = '%s~' % local_fname
@@ -257,6 +277,7 @@ def spock_late_startup_hook(self):
get_door().setConsoleReady(True)
except:
import traceback
+
print "Exception in spock_late_startup_hook:"
traceback.print_exc()
@@ -266,9 +287,10 @@ def spock_pre_prompt_hook(self):
get_door().pre_prompt_hook(self)
except:
import traceback
+
print "Exception in spock_pre_prompt_hook:"
traceback.print_exc()
-#def spock_pre_runcode_hook(self):
+# def spock_pre_runcode_hook(self):
# print "spock_pre_runcode_hook"
# return None
diff --git a/src/sardana/spock/release.py b/src/sardana/spock/release.py
index 0888980..7d2d84c 100644
--- a/src/sardana/spock/release.py
+++ b/src/sardana/spock/release.py
@@ -39,7 +39,7 @@ name = 'spock'
revision = '1'
#version = '0.8.1.svn.r' + revision.rstrip('M')
-version = '2.0.0'
+version = '2.1.0'
description = "An enhanced interactive Macro Server shell."
diff --git a/src/sardana/spock/spockms.py b/src/sardana/spock/spockms.py
index 3cd53f9..dd6378f 100755
--- a/src/sardana/spock/spockms.py
+++ b/src/sardana/spock/spockms.py
@@ -52,6 +52,12 @@ else:
from sardana.taurus.core.tango.sardana.macroserver import BaseDoor, BaseMacroServer
BaseGUIViewer = object
+try:
+ RUNNING_STATE = TaurusSWDevState.Running
+except RuntimeError:
+ # TODO: For Taurus 4 compatibility
+ from taurus.core import TaurusDevState
+ RUNNING_STATE = TaurusDevState.Ready
class GUIViewer(BaseGUIViewer):
@@ -314,7 +320,7 @@ class SpockBaseDoor(BaseDoor):
def _runMacro(self, xml, **kwargs):
#kwargs like 'synch' are ignored in this re-implementation
- if self._spock_state != TaurusSWDevState.Running:
+ if self._spock_state != RUNNING_STATE:
print "Unable to run macro: No connection to door '%s'" % self.getSimpleName()
raise Exception("Unable to run macro: No connection")
if xml is None:
@@ -403,7 +409,7 @@ class SpockBaseDoor(BaseDoor):
def _updateState(self, old_sw_state, new_sw_state, silent=False):
user_ns = genutils.get_ipapi().user_ns
- if new_sw_state == TaurusSWDevState.Running:
+ if new_sw_state == RUNNING_STATE:
user_ns['DOOR_STATE'] = ""
else:
user_ns['DOOR_STATE'] = " (OFFLINE)"
@@ -414,9 +420,9 @@ class SpockBaseDoor(BaseDoor):
ss = self._spock_state
if ss is not None and ss != new_sw_state and not silent:
- if ss == TaurusSWDevState.Running:
+ if ss == RUNNING_STATE:
self.write_asynch("\nConnection to door '%s' was lost.\n" % self.getSimpleName())
- elif new_sw_state == TaurusSWDevState.Running:
+ elif new_sw_state == RUNNING_STATE:
self.write_asynch("\nConnection to the door (%s) has " \
"been restablished\n" % self.getSimpleName())
self._spock_state = new_sw_state
diff --git a/src/sardana/taurus/core/tango/sardana/macroserver.py b/src/sardana/taurus/core/tango/sardana/macroserver.py
old mode 100644
new mode 100755
index d31459c..d4e9bc8
--- a/src/sardana/taurus/core/tango/sardana/macroserver.py
+++ b/src/sardana/taurus/core/tango/sardana/macroserver.py
@@ -281,6 +281,7 @@ class BaseDoor(MacroServerDevice):
def __init__(self, name, **kw):
self._log_attr = CaselessDict()
self._block_lines = 0
+ self._in_block = False
self._macro_server = None
self._running_macros = None
self._running_macro = None
@@ -296,7 +297,12 @@ class BaseDoor(MacroServerDevice):
self.call__init__(MacroServerDevice, name, **kw)
self._old_door_state = PyTango.DevState.UNKNOWN
- self._old_sw_door_state = TaurusSWDevState.Uninitialized
+ try:
+ self._old_sw_door_state = TaurusSWDevState.Uninitialized
+ except RuntimeError:
+ #TODO: For Taurus 4 compatibility
+ from taurus.core import TaurusDevState
+ self._old_sw_door_state = TaurusDevState.Undefined
self.getStateObj().addListener(self.stateChanged)
@@ -542,7 +548,11 @@ class BaseDoor(MacroServerDevice):
def stateChanged(self, s, t, v):
self._old_door_state = self.getState()
- self._old_sw_door_state = self.getSWState()
+ try:
+ self._old_sw_door_state = self.getSWState()
+ except:
+ # TODO: For Taurus 4 compatibility
+ self._old_sw_door_state = self.state
def resultReceived(self, log_name, result):
"""Method invoked by the arrival of a change event on the Result attribute"""
@@ -644,14 +654,21 @@ class BaseDoor(MacroServerDevice):
for line in output:
if not self._debug:
if line == self.BlockStart:
+ self._in_block = True
for i in xrange(self._block_lines):
o += '\x1b[2K\x1b[1A\x1b[2K' #erase current line, up one line, erase current line
self._block_lines = 0
continue
elif line == self.BlockFinish:
+ self._in_block = False
continue
+ else:
+ if self._in_block:
+ self._block_lines += 1
+ else:
+ self._block_lines = 0
o += "%s\n" % line
- self._block_lines += 1
+
o += self.log_stop[log_name]
self.write(o)
@@ -701,6 +718,7 @@ class MacroPath(object):
self.rel_macro_path = [ osp.relpath for p in mp, self.base_macro_path ]
+
class Environment(dict):
def __init__(self, macro_server):
@@ -821,7 +839,9 @@ class BaseMacroServer(MacroServerDevice):
return MacroInfo(from_json=element_info._data)
def _createDeviceObject(self, element_info):
- return Factory().getDevice(element_info.full_name)
+ # TODO: For Taurus 4 compatibility
+ name = "tango://%s" % element_info.full_name
+ return Factory().getDevice(name)
def on_elements_changed(self, evt_src, evt_type, evt_value):
try:
diff --git a/src/sardana/taurus/core/tango/sardana/motion.py b/src/sardana/taurus/core/tango/sardana/motion.py
index f183983..547f97f 100644
--- a/src/sardana/taurus/core/tango/sardana/motion.py
+++ b/src/sardana/taurus/core/tango/sardana/motion.py
@@ -151,7 +151,7 @@ class MotionGroup(BaseMotion):
times = [ moveable.getLastMotionTime() for moveable in self.moveable_list ]
return max(times)
- def getTotalLastMotionTime():
+ def getTotalLastMotionTime(self):
return self.__total_motion_time
def startMove(self, pos_list, timeout=None):
diff --git a/src/sardana/taurus/core/tango/sardana/pool.py b/src/sardana/taurus/core/tango/sardana/pool.py
index 1194245..17f027b 100644
--- a/src/sardana/taurus/core/tango/sardana/pool.py
+++ b/src/sardana/taurus/core/tango/sardana/pool.py
@@ -38,6 +38,7 @@ __docformat__ = 'restructuredtext'
import os
import sys
import time
+import copy
import weakref
import operator
import traceback
@@ -48,7 +49,12 @@ from PyTango import DevState, AttrDataFormat, AttrQuality, DevFailed, \
from taurus import Factory, Device
from taurus.core.taurusbasetypes import TaurusEventType, TaurusSWDevState, \
TaurusSerializationMode
-from taurus.core.taurusvalidator import AttributeNameValidator
+try:
+ from taurus.core.taurusvalidator import AttributeNameValidator as\
+ TangoAttributeNameValidator
+except ImportError:
+ #TODO: For Taurus 4 compatibility
+ from taurus.core.tango.tangovalidator import TangoAttributeNameValidator
from taurus.core.util.log import Logger
from taurus.core.util.singleton import Singleton
from taurus.core.util.codecs import CodecFactory
@@ -1155,12 +1161,13 @@ class MGConfiguration(object):
self.non_tango_channels = n_tg_chs = CaselessDict()
self.cache = cache = {}
- tg_attr_validator = AttributeNameValidator()
+ tg_attr_validator = TangoAttributeNameValidator()
for channel_name, channel_data in self.channels.items():
cache[channel_name] = None
data_source = channel_data['source']
#external = ctrl_name.startswith("__")
- params = tg_attr_validator.getParams(data_source)
+ # TODO: For Taurus 4 compatibility
+ params = tg_attr_validator.getParams("tango://%s" % data_source)
if params is None:
# Handle NON tango channel
n_tg_chs[channel_name] = channel_data
@@ -1249,17 +1256,42 @@ class MGConfiguration(object):
if ch_info.name.lower() == channel_name:
return d_name, a_name, ch_info
- def getChannelsInfo(self):
+ def getChannelsInfo(self, only_enabled=False):
+ """Returns information about the channels present in the measurement
+ group in a form of dictionary, where key is a channel name and value is
+ a tuple of three elements:
+ - device name
+ - attribute name
+ - attribute information or None if there was an error trying to get
+ the information
+
+ :param only_enabled: flag to filter out disabled channels
+ :type only_enabled: bool
+ :return: dictionary with channels info
+ :rtype: dict<str, tuple<str, str, TangoChannelInfo>>
+ """
self.prepare()
ret = CaselessDict(self.tango_channels_info)
ret.update(self.non_tango_channels)
+ for ch_name, (_, _, ch_info) in ret.items():
+ if only_enabled and not ch_info.enabled:
+ ret.pop(ch_name)
return ret
- def getChannelsInfoList(self):
- channels_info = self.getChannelsInfo()
- ret = len(channels_info) * [None]
+ def getChannelsInfoList(self, only_enabled=False):
+ """Returns information about the channels present in the measurement
+ group in a form of ordered, based on the channel index, list.
+
+ :param only_enabled: flag to filter out disabled channels
+ :type only_enabled: bool
+ :return: list with channels info
+ :rtype: list<TangoChannelInfo>
+ """
+ channels_info = self.getChannelsInfo(only_enabled=only_enabled)
+ ret = []
for _, (_, _, ch_info) in channels_info.items():
- ret[ch_info.index] = ch_info
+ ret.append(ch_info)
+ ret = sorted(ret, lambda x,y: cmp(x.index, y.index))
return ret
def getCountersInfoList(self):
@@ -1273,6 +1305,29 @@ class MGConfiguration(object):
channels_info.pop(idx)
return channels_info
+ def getTangoDevChannels(self, only_enabled=False):
+ """Returns Tango channels (attributes) that could be used to read
+ measurement group results in a form of dict where key is a device name
+ and value is a list with two elements:
+ - A device proxy or None if there was an error building it
+ - A dict where keys are attribute names and value is a reference to
+ a dict representing channel data as received in raw data
+
+ :param only_enabled: flag to filter out disabled channels
+ :type only_enabled: bool
+ :return: dict with Tango channels
+ :rtype: dict<str, list[DeviceProxy, CaselessDict<str, dict>]>
+ """
+ if not only_enabled:
+ return self.tango_dev_channels
+ tango_dev_channels = copy.deepcopy(self.tango_dev_channels)
+ for _, dev_data in tango_dev_channels.items():
+ _, attrs = dev_data
+ for attr_name, channel_data in attrs.items():
+ if not channel_data["enabled"]:
+ attrs.pop(attr_name)
+ return tango_dev_channels
+
def read(self, parallel=True):
if parallel:
return self._read_parallel()
@@ -1284,7 +1339,8 @@ class MGConfiguration(object):
dev_replies = {}
# deposit read requests
- for _, dev_data in self.tango_dev_channels.items():
+ tango_dev_channels = self.getTangoDevChannels(only_enabled=True)
+ for _, dev_data in tango_dev_channels.items():
dev, attrs = dev_data
if dev is None:
continue
@@ -1314,7 +1370,8 @@ class MGConfiguration(object):
def _read(self):
self.prepare()
ret = CaselessDict(self.cache)
- for _, dev_data in self.tango_dev_channels.items():
+ tango_dev_channels = self.getTangoDevChannels(only_enabled=True)
+ for _, dev_data in tango_dev_channels.items():
dev, attrs = dev_data
try:
data = dev.read_attributes(attrs.keys())
@@ -1425,6 +1482,16 @@ class MeasurementGroup(PoolElement):
def getChannelsInfo(self):
return self.getConfiguration().getChannelsInfoList()
+ def getChannelsEnabledInfo(self):
+ """Returns information about **only enabled** channels present in the
+ measurement group in a form of ordered, based on the channel index,
+ list.
+
+ :return: list with channels info
+ :rtype: list<TangoChannelInfo>
+ """
+ return self.getConfiguration().getChannelsInfoList(only_enabled=True)
+
def getCountersInfo(self):
return self.getConfiguration().getCountersInfoList()
@@ -1588,7 +1655,9 @@ class Pool(TangoDevice, MoveableSource):
kwargs['_pool_data'] = data
kwargs['_pool_obj'] = self
return klass(**kwargs)
- obj = Factory().getDevice(element_info.full_name, _pool_obj=self,
+ # TODO: For Taurus 4 compatibility
+ fullname = "tango://%s" % element_info.full_name
+ obj = Factory().getDevice(fullname, _pool_obj=self,
_pool_data=data)
return obj
diff --git a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py
index b0a780f..fbcb0bb 100644
--- a/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py
+++ b/src/sardana/taurus/qt/qtcore/tango/sardana/macroserver.py
@@ -39,6 +39,19 @@ 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)
+ except AttributeError:
+ pass
def __init__(self, name, qt_parent=None, **kw):
self.call__init__wo_kw(Qt.QObject, qt_parent)
@@ -47,12 +60,18 @@ class QDoor(BaseDoor, Qt.QObject):
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)
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)
return res
def macroStatusReceived(self, s, t, v):
@@ -63,11 +82,21 @@ class QDoor(BaseDoor, Qt.QObject):
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)
return res
def logReceived(self, log_name, output):
res = BaseDoor.logReceived(self, log_name, output)
- self.emit(Qt.SIGNAL("%sUpdated" % log_name.lower()), 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
return res
diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py
index 51bea8b..0b1bcb3 100644
--- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py
+++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/common.py
@@ -31,7 +31,7 @@ from taurus.core.taurusbasetypes import TaurusEventType
from taurus.qt.qtgui.base import TaurusBaseWidget
from taurus.qt.qtgui.input import TaurusAttrListComboBox
from taurus.qt.qtgui.container import TaurusMainWindow
-from taurus.qt.qtgui.resource import getThemeIcon
+from taurus.qt.qtgui.resource import getThemeIcon, getIcon
def str2bool(text):
@@ -188,11 +188,11 @@ class TaurusMacroConfigurationDialog(Qt.QDialog):
pass
icon = None
if state == PyTango.DevState.ON:
- icon = Qt.QIcon(":/leds/images24/ledgreen.png")
+ icon = getIcon(":/leds/images24/ledgreen.png")
elif state == PyTango.DevState.FAULT:
- icon = Qt.QIcon(":/leds/images24/ledred.png")
+ icon = getIcon(":/leds/images24/ledred.png")
elif state == None:
- icon = Qt.QIcon(":/leds/images24/ledredoff.png")
+ icon = getIcon(":/leds/images24/ledredoff.png")
ms_stateIcons.append((macroServer, icon))
return ms_stateIcons
@@ -246,7 +246,7 @@ class MacroExecutionWindow(TaurusMainWindow):
self._customMacroEditorPaths = ""
self.registerConfigProperty("customMacroEditorPaths", "setCustomMacroEditorPaths", "customMacroEditorPaths")
self._qDoor = None
- self.setWindowIcon(Qt.QIcon(":/apps/preferences-system-session.svg"))
+ self.setWindowIcon(getIcon(":/apps/preferences-system-session.svg"))
toolBar = self.basicTaurusToolbar()
toolBar.setIconSize(Qt.QSize(24, 24))
self.configureAction = self.createConfigureAction()
diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py
index 6c5ded9..b35a718 100644
--- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py
+++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macrobutton.py
@@ -255,17 +255,15 @@ class MacroButton(TaurusWidget):
if self.door is None:
return
- # Thanks to gjover for the hint... :-D
- #macro_cmd = self.macro_name + ' ' + ' '.join(self.macro_args)
- self.macro_id = uuid.uuid1()
- macro_cmd_xml = '<macro name="%s" id="%s">\n' % \
- (self.macro_name, self.macro_id)
- for arg in self.macro_args:
- macro_cmd_xml += '<param value="%s"/>\n' % arg
- macro_cmd_xml += '</macro>'
+ # TODO: make macrobutton compatible with macros with advanced usage of
+ # repeat parameters e.g. multiple repeat parameters, nested repeat
+ # parameters, etc.
+ macro_cmd = self.macro_name + ' ' + ' '.join(self.macro_args)
try:
- #self.door.runMacro(macro_cmd)
- self.door.runMacro(macro_cmd_xml)
+ self.door.runMacro(macro_cmd)
+ sec_xml = self.door.getRunningXML()
+ # get the id of the current running macro
+ self.macro_id = sec_xml[0].get("id")
except Exception, e:
self.ui.button.setChecked(False)
raise e
diff --git a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py
index 5b2e24d..baa0494 100644
--- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py
+++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/macroexecutor.py
@@ -688,7 +688,11 @@ class TaurusMacroExecutorWidget(TaurusWidget):
def checkDoorState(self):
door = Device(self.doorName())
- doorState = door.state()
+ try:
+ doorState = door.state()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorState = door.getState()
if doorState == PyTango.DevState.RUNNING:
self.playMacroAction.setEnabled(False)
self.pauseMacroAction.setEnabled(True)
@@ -812,7 +816,12 @@ class TaurusMacroExecutorWidget(TaurusWidget):
self.doorStateLed.setModel(None)
return
self.doorStateLed.setModel(self.doorName() + "/State")
- doorState = Device(doorName).state()
+ door = Device(doorName)
+ try:
+ doorState = door.state()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorState = door.getState()
if doorState == PyTango.DevState.ON:
self.playMacroAction.setText("Start macro")
self.playMacroAction.setToolTip("Start macro")
@@ -822,7 +831,11 @@ class TaurusMacroExecutorWidget(TaurusWidget):
def onPlayMacro(self):
door = Device(self.doorName())
- doorState = door.state()
+ try:
+ doorState = door.state()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorState = door.getState()
if doorState == PyTango.DevState.ON or doorState == PyTango.DevState.ALARM:
self.setFocus()
paramEditorModel = self.paramEditorModel()
@@ -845,7 +858,11 @@ class TaurusMacroExecutorWidget(TaurusWidget):
def onStopMacro(self):
door = Device(self.doorName())
- doorState = door.state()
+ try:
+ doorState = door.state()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorState = door.getState()
if doorState in (PyTango.DevState.RUNNING, PyTango.DevState.STANDBY):
door.command_inout("StopMacro")
@@ -855,7 +872,11 @@ class TaurusMacroExecutorWidget(TaurusWidget):
def onPauseMacro(self):
door = Device(self.doorName())
- doorState = door.state()
+ try:
+ doorState = door.state()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorState = door.getState()
if doorState == PyTango.DevState.RUNNING:
door.command_inout("PauseMacro")
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 00ed7e5..5235c25 100644
--- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py
+++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/model.py
@@ -181,7 +181,7 @@ class MacroSequenceTreeModel(Qt.QAbstractItemModel):
index = index.parent()
node = self.nodeFromIndex(index)
if isinstance(node, macro.MacroNode):
- self.emit(Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index.sibling(index.row(), self.columnCount(index)))
+ self.emit(Qt.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index.sibling(index.row(), self.columnCount(index) - 1))
break
elif index.column() == 2:
progress = Qt.from_qvariant(value, float)
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 7c2e554..e198ed1 100644
--- a/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py
+++ b/src/sardana/taurus/qt/qtgui/extra_macroexecutor/sequenceeditor/sequenceeditor.py
@@ -460,7 +460,11 @@ class TaurusSequencerWidget(TaurusWidget):
about the macro status does not reach the sequencer widget.'''
door = Device(self.doorName())
- doorState = door.state()
+ try:
+ doorState = door.state()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorState = door.getState()
if doorState == PyTango.DevState.RUNNING:
self.playSequenceAction.setEnabled(False)
self.pauseSequenceAction.setEnabled(True)
@@ -604,7 +608,11 @@ class TaurusSequencerWidget(TaurusWidget):
def onPlaySequence(self):
door = Device(self.doorName())
- doorState = door.state()
+ try:
+ doorState = door.state()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorState = door.getState()
if doorState == PyTango.DevState.ON or doorState == PyTango.DevState.ALARM:
first, last, ids = self.tree.prepareMacroIds()
self.setFirstMacroId(first)
@@ -621,7 +629,11 @@ class TaurusSequencerWidget(TaurusWidget):
def onStopSequence(self):
door = Device(self.doorName())
- doorState = door.state()
+ try:
+ doorState = door.state()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorState = door.getState()
if doorState in (PyTango.DevState.RUNNING, PyTango.DevState.STANDBY):
door.command_inout("StopMacro")
else:
@@ -630,7 +642,11 @@ class TaurusSequencerWidget(TaurusWidget):
def onPauseSequence(self):
door = Device(self.doorName())
- doorState = door.state()
+ try:
+ doorState = door.state()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorState = door.getState()
if doorState == PyTango.DevState.RUNNING:
door.command_inout("PauseMacro")
else:
@@ -707,7 +723,12 @@ class TaurusSequencerWidget(TaurusWidget):
self.doorStateLed.setModel(None)
return
self.doorStateLed.setModel(self.doorName() + "/State")
- doorState = Device(doorName).state()
+ door = Device(doorName)
+ try:
+ doorState = door.state()
+ except TypeError:
+ # TODO: For Taurus 4 adaptation
+ doorState = door.getState()
if doorState == PyTango.DevState.ON:
self.playSequenceAction.setText("Start sequence")
self.playSequenceAction.setToolTip("Start sequence")
diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolchannel.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolchannel.py
index acbc0e2..042b244 100644
--- a/src/sardana/taurus/qt/qtgui/extra_pool/poolchannel.py
+++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolchannel.py
@@ -59,7 +59,7 @@ class PoolChannelTV(TaurusValue):
'''
def __init__(self, parent=None, designMode=False):
TaurusValue.__init__(self, parent=parent, designMode=designMode)
- self.setLabelWidgetClass("LabelWidgetDragsDeviceAndAttribute")
+ self.setLabelWidgetClass(LabelWidgetDragsDeviceAndAttribute)
self.setLabelConfig('dev_alias')
def getDefaultExtraWidgetClass(self):
diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolioregister.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolioregister.py
index 97d89b5..e2d8bf8 100644
--- a/src/sardana/taurus/qt/qtgui/extra_pool/poolioregister.py
+++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolioregister.py
@@ -127,10 +127,10 @@ class PoolIORegisterTV(TaurusValue):
'''
def __init__(self, parent=None, designMode=False):
TaurusValue.__init__(self, parent=parent, designMode=designMode)
- self.setLabelWidgetClass("LabelWidgetDragsDeviceAndAttribute")
+ self.setLabelWidgetClass(LabelWidgetDragsDeviceAndAttribute)
self.setLabelConfig('dev_alias')
- self.setReadWidgetClass('PoolIORegisterReadWidget')
- self.setWriteWidgetClass('PoolIORegisterWriteWidget')
+ self.setReadWidgetClass(PoolIORegisterReadWidget)
+ self.setWriteWidgetClass(PoolIORegisterWriteWidget)
self.ioreg_dev = None
def setModel(self, model):
diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py
index c05853a..a059a3e 100644
--- a/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py
+++ b/src/sardana/taurus/qt/qtgui/extra_pool/poolmotor.py
@@ -33,7 +33,12 @@ from taurus.external.qt import Qt
import taurus
from taurus.core.util.colors import DEVICE_STATE_PALETTE
from taurus.core.taurusbasetypes import TaurusEventType
-from taurus.core.taurusvalidator import DeviceNameValidator
+try:
+ from taurus.core.taurusvalidator import DeviceNameValidator as \
+ TangoDeviceNameValidator
+except ImportError:
+ # TODO: For Taurus 4 adaptation
+ from taurus.core.tango.tangovalidator import TangoDeviceNameValidator
import taurus.qt.qtcore.mimetypes
from taurus.qt.qtgui.base import TaurusBaseWritableWidget
from taurus.qt.qtgui.compact import TaurusReadWriteSwitcher
@@ -300,6 +305,7 @@ class PoolMotorSlim(TaurusWidget, PoolMotorClient):
#self.call__init__(TaurusBaseWidget, str(self.objectName()), designMode=designMode)
PoolMotorClient.__init__(self)
self.loadUi()
+ self.recheckTaurusParent()
self.show_context_menu = True
@@ -647,7 +653,9 @@ class PoolMotorSlim(TaurusWidget, PoolMotorClient):
# DUE TO A BUG IN TAUGROUPBOX, WE NEED THE FULL MODEL NAME
try:
# In case the model is an attribute of a motor, get the device name
- if not DeviceNameValidator().isValid(model):
+ # TODO: When sardana is moved to Taurus 4 replace this line by
+ # taurushelper.isValidName(model, [TaurusElementType.Device])
+ if not TangoDeviceNameValidator().isValid(model):
model = model.rpartition('/')[0]
model = taurus.Factory().getDevice(model).getFullName()
self.setMotor(model)
@@ -836,7 +844,6 @@ class PoolMotorTVLabelWidget(TaurusWidget):
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)
# Handle Power ON/OFF
self.connect(self.btn_poweron, Qt.SIGNAL('clicked()'), self.setPowerOn)
@@ -881,10 +888,10 @@ class PoolMotorTVLabelWidget(TaurusWidget):
event.accept()
def mouseMoveEvent(self, event):
- model = self.lbl_alias.getModelName()
+ model = self.taurusValueBuddy().getModelObj()
mimeData = Qt.QMimeData()
mimeData.setText(self.lbl_alias.text())
- dev_name = model.rpartition('/')[0]
+ dev_name = model.getFullName()
attr_name = dev_name + '/Position'
mimeData.setData(TAURUS_DEV_MIME_TYPE, dev_name)
mimeData.setData(TAURUS_ATTR_MIME_TYPE, attr_name)
@@ -1032,9 +1039,14 @@ class PoolMotorTVReadWidget(TaurusWidget):
# WRITE WIDGET #
##################################################
class PoolMotorTVWriteWidget(TaurusWidget):
-
+
layoutAlignment = Qt.Qt.AlignTop
-
+ try:
+ # TODO: For Taurus 4 compatibility
+ applied = Qt.pyqtSignal()
+ except AttributeError:
+ pass
+
def __init__(self, parent=None, designMode=False):
TaurusWidget.__init__(self, parent, designMode)
self.setLayout(Qt.QGridLayout())
@@ -1141,7 +1153,11 @@ class PoolMotorTVWriteWidget(TaurusWidget):
self.btn_to_pos_press.setVisible(False)
# IN EXPERT VIEW, WE HAVE TO FORWARD THE ''editingFinished()' SIGNAL FROM TaurusValueLineEdit TO Switcher
- self.connect(self.le_write_absolute, Qt.SIGNAL(TaurusBaseWritableWidget.appliedSignalSignature), self.emitEditingFinished)
+ 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)
@@ -1262,7 +1278,11 @@ class PoolMotorTVWriteWidget(TaurusWidget):
TaurusWidget.keyPressEvent(self, key_event)
def emitEditingFinished(self):
- self.emit(Qt.SIGNAL(TaurusBaseWritableWidget.appliedSignalSignature))
+ try:
+ self.emit(Qt.SIGNAL(TaurusBaseWritableWidget.appliedSignalSignature))
+ except AttributeError:
+ # TODO: For Taurus 4 adaptation
+ self.applied.emit()
##################################################
@@ -1296,10 +1316,10 @@ class PoolMotorTV(TaurusValue):
'''
def __init__(self, parent=None, designMode=False):
TaurusValue.__init__(self, parent=parent, designMode=designMode)
- self.setLabelWidgetClass('PoolMotorTVLabelWidget')
- self.setReadWidgetClass('PoolMotorTVReadWidget')
- self.setWriteWidgetClass('PoolMotorTVWriteWidget')
- self.setUnitsWidgetClass('PoolMotorTVUnitsWidget')
+ self.setLabelWidgetClass(PoolMotorTVLabelWidget)
+ self.setReadWidgetClass(PoolMotorTVReadWidget)
+ self.setWriteWidgetClass(PoolMotorTVWriteWidget)
+ self.setUnitsWidgetClass(PoolMotorTVUnitsWidget)
self.setLabelConfig('dev_alias')
@@ -1343,7 +1363,6 @@ class PoolMotorTV(TaurusValue):
if model == '' or model is None:
self.motor_dev = None
return
-
self.motor_dev = taurus.Device(model)
# CONFIGURE A LISTENER IN ORDER TO UPDATE LIMIT SWITCHES STATES
@@ -1524,7 +1543,6 @@ def main():
import taurus.qt.qtgui.application
import taurus.core.util.argparse
from taurus.qt.qtgui.panel import TaurusForm
-
parser = taurus.core.util.argparse.get_taurus_parser()
parser.usage = "%prog [options] [<motor1> [<motor2>] ...]"
@@ -1548,7 +1566,7 @@ def main():
# 1) Test PoolMotorSlim motor widget
form_pms = TaurusForm()
- pms_widget_class = 'taurus.qt.qtgui.extra_pool.PoolMotorSlim'
+ pms_widget_class = 'sardana.taurus.qt.qtgui.extra_pool.PoolMotorSlim'
pms_tgclass_map = {'SimuMotor':(pms_widget_class, (), {}),
'Motor':(pms_widget_class, (), {}),
'PseudoMotor':(pms_widget_class, (), {})}
@@ -1560,7 +1578,7 @@ def main():
# 2) Test PoolMotorTV motor widget
form_tv = TaurusForm()
form_tv.setModifiableByUser(True)
- tv_widget_class = 'taurus.qt.qtgui.extra_pool.PoolMotorTV'
+ tv_widget_class = 'sardana.taurus.qt.qtgui.extra_pool.PoolMotorTV'
tv_tgclass_map = {'SimuMotor':(tv_widget_class, (), {}),
'Motor':(tv_widget_class, (), {}),
'PseudoMotor':(tv_widget_class, (), {})}
diff --git a/src/sardana/taurus/qt/qtgui/extra_pool/ui/PoolMotorSlim.ui b/src/sardana/taurus/qt/qtgui/extra_pool/ui/PoolMotorSlim.ui
index 6c6141b..9233390 100644
--- a/src/sardana/taurus/qt/qtgui/extra_pool/ui/PoolMotorSlim.ui
+++ b/src/sardana/taurus/qt/qtgui/extra_pool/ui/PoolMotorSlim.ui
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PoolMotorSlim</class>
<widget class="TaurusWidget" name="PoolMotorSlim">
@@ -5,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>487</width>
- <height>61</height>
+ <width>549</width>
+ <height>212</height>
</rect>
</property>
<property name="windowTitle">
@@ -22,12 +23,12 @@
<item row="0" column="0">
<widget class="TaurusGroupBox" name="motorGroupBox">
<property name="sizePolicy">
- <sizepolicy vsizetype="Fixed" hsizetype="Preferred">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="showText" stdset="0">
+ <property name="showText">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
@@ -37,13 +38,19 @@
<property name="spacing">
<number>0</number>
</property>
- <item row="0" column="0">
- <widget class="QWidget" native="1" name="taurusValueContainer">
- <property name="sizePolicy">
- <sizepolicy vsizetype="Preferred" hsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="btnStop">
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Stops the motor</string>
+ </property>
+ <property name="text">
+ <string>S</string>
</property>
</widget>
</item>
@@ -55,7 +62,7 @@
<item>
<widget class="QPushButton" name="btnMin">
<property name="sizePolicy">
- <sizepolicy vsizetype="Maximum" hsizetype="Fixed">
+ <sizepolicy hsizetype="Fixed" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -83,7 +90,7 @@
<item>
<widget class="QPushButton" name="btnGoToNeg">
<property name="sizePolicy">
- <sizepolicy vsizetype="Maximum" hsizetype="Fixed">
+ <sizepolicy hsizetype="Fixed" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -111,7 +118,7 @@
<item>
<widget class="QPushButton" name="btnGoToNegPress">
<property name="sizePolicy">
- <sizepolicy vsizetype="Maximum" hsizetype="Fixed">
+ <sizepolicy hsizetype="Fixed" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -126,14 +133,14 @@
<string>Moves the motor towards negative limit while pressed</string>
</property>
<property name="text">
- <string>«</string>
+ <string>«</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnGoToNegInc">
<property name="sizePolicy">
- <sizepolicy vsizetype="Maximum" hsizetype="Fixed">
+ <sizepolicy hsizetype="Fixed" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -171,7 +178,7 @@
<item>
<widget class="QPushButton" name="btnGoToPosInc">
<property name="sizePolicy">
- <sizepolicy vsizetype="Fixed" hsizetype="Fixed">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -193,7 +200,7 @@
<item>
<widget class="QPushButton" name="btnGoToPosPress">
<property name="sizePolicy">
- <sizepolicy vsizetype="Fixed" hsizetype="Fixed">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -208,14 +215,14 @@
<string>Moves the motor towards positive limit while pressed</string>
</property>
<property name="text">
- <string>»</string>
+ <string>»</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnGoToPos">
<property name="sizePolicy">
- <sizepolicy vsizetype="Fixed" hsizetype="Fixed">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -237,7 +244,7 @@
<item>
<widget class="QPushButton" name="btnMax">
<property name="sizePolicy">
- <sizepolicy vsizetype="Fixed" hsizetype="Fixed">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -261,8 +268,18 @@
</item>
</layout>
</item>
- <item row="0" column="2">
- <widget class="QPushButton" name="btnStop">
+ <item row="0" column="0">
+ <widget class="QWidget" name="taurusValueContainer" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="TaurusLauncherButton" name="btnCfg">
<property name="maximumSize">
<size>
<width>30</width>
@@ -270,31 +287,25 @@
</size>
</property>
<property name="toolTip">
- <string>Stops the motor</string>
+ <string>Configures the motor</string>
</property>
<property name="text">
- <string>S</string>
+ <string>Cfg</string>
</property>
</widget>
</item>
- <item row="0" column="3">
- <widget class="QPushButton" name="btnHome">
- <property name="maximumSize">
- <size>
- <width>30</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="toolTip">
- <string>Goes Home</string>
+ <item row="1" column="0" colspan="5">
+ <widget class="TaurusLabel" name="lblStatus">
+ <property name="model">
+ <string>/Status</string>
</property>
- <property name="text">
- <string>H</string>
+ <property name="useParentModel">
+ <bool>true</bool>
</property>
</widget>
</item>
- <item row="0" column="4">
- <widget class="TaurusLauncherButton" name="btnCfg">
+ <item row="0" column="3">
+ <widget class="QPushButton" name="btnHome">
<property name="maximumSize">
<size>
<width>30</width>
@@ -302,47 +313,10 @@
</size>
</property>
<property name="toolTip">
- <string>Configures the motor</string>
+ <string>Goes Home</string>
</property>
<property name="text">
- <string>Cfg</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0" colspan="5">
- <widget class="TaurusValueLabel" name="lblStatus">
- <property name="sizePolicy">
- <sizepolicy vsizetype="Fixed" hsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="font">
- <font>
- <pointsize>7</pointsize>
- </font>
- </property>
- <property name="styleSheet">
- <string notr="true">TauValueLabel {
- border-style: outset;
- border-width: 2px;
- border-color: rgba(255,255,255,128);
- background-color: transparent; color:black; }</string>
- </property>
- <property name="frameShape">
- <enum>QFrame::StyledPanel</enum>
- </property>
- <property name="lineWidth">
- <number>0</number>
- </property>
- <property name="model" stdset="0">
- <string>/Status</string>
- </property>
- <property name="useParentModel" stdset="0">
- <bool>true</bool>
- </property>
- <property name="showQuality" stdset="0">
- <bool>false</bool>
+ <string>H</string>
</property>
</widget>
</item>
@@ -353,28 +327,28 @@
</widget>
<customwidgets>
<customwidget>
- <class>TaurusWidget</class>
- <extends>QWidget</extends>
- <header>taurus.qt.qtgui.container</header>
- </customwidget>
- <customwidget>
<class>TaurusLauncherButton</class>
<extends>QPushButton</extends>
<header>taurus.qt.qtgui.button</header>
</customwidget>
<customwidget>
- <class>TaurusGroupBox</class>
- <extends>QGroupBox</extends>
+ <class>TaurusWidget</class>
+ <extends>QWidget</extends>
<header>taurus.qt.qtgui.container</header>
<container>1</container>
</customwidget>
<customwidget>
- <class>TaurusValueLabel</class>
+ <class>TaurusLabel</class>
<extends>QLabel</extends>
<header>taurus.qt.qtgui.display</header>
</customwidget>
+ <customwidget>
+ <class>TaurusGroupBox</class>
+ <extends>QGroupBox</extends>
+ <header>taurus.qt.qtgui.container</header>
+ <container>1</container>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
-
diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py
index 3e90c8b..1795871 100644
--- a/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py
+++ b/src/sardana/taurus/qt/qtgui/extra_sardana/expdescription.py
@@ -98,7 +98,12 @@ class ExpDescriptionEditor(Qt.QWidget, TaurusBaseWidget):
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.connect(self.ui.preScanList, Qt.SIGNAL('dataChanged'), self.onPreScanSnapshotChanged)
+ preScanList = self.ui.preScanList
+ self.connect(preScanList, Qt.SIGNAL('dataChanged'),
+ self.onPreScanSnapshotChanged)
+ #TODO: For Taurus 4 compatibility
+ if hasattr(preScanList, "dataChangedSignal"):
+ preScanList.dataChangedSignal.connect(self.onPreScanSnapshotChanged)
self.connect(self.ui.choosePathBT, Qt.SIGNAL('clicked ()'), self.onChooseScanDirButtonClicked)
self.__plotManager = None
@@ -210,8 +215,12 @@ class ExpDescriptionEditor(Qt.QWidget, TaurusBaseWidget):
#set the system snapshot list
psl = self._localConfig.get('PreScanSnapshot') #I get it before clearing because clear() changes the _localConfig
+ # TODO: For Taurus 4 compatibility
+ psl_fullname = []
+ for name, display in psl:
+ psl_fullname.append(("tango://%s" % name, display))
self.ui.preScanList.clear()
- self.ui.preScanList.addModels(psl)
+ self.ui.preScanList.addModels(psl_fullname)
#other settings
self.ui.filenameLE.setText(", ".join(self._localConfig['ScanFile']))
@@ -360,9 +369,11 @@ class ExpDescriptionEditor(Qt.QWidget, TaurusBaseWidget):
for e in items:
nfo = ms.getElementInfo(e.src)
if nfo is None:
- preScanList.append((e.src, e.display))
+ full_name = e.src; display = e.display
else:
- preScanList.append((nfo.full_name, nfo.name))
+ full_name = nfo.full_name; display = nfo.name
+ # TODO: For Taurus 4 compatibility
+ preScanList.append((full_name.lstrip("tango://"), display))
self._localConfig['PreScanSnapshot'] = preScanList
self._setDirty(True)
diff --git a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py
index 23fb8df..eca78d8 100644
--- a/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py
+++ b/src/sardana/taurus/qt/qtgui/extra_sardana/measurementgroup.py
@@ -888,9 +888,27 @@ class MntGrpChannelEditor(TaurusBaseTableWidget):
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)
return tableView
def createToolArea(self):
@@ -933,17 +951,48 @@ class MntGrpChannelEditor(TaurusBaseTableWidget):
chnames = [ch.itemData()[0] for ch in channels]
self.getQModel().removeChannels(chnames)
+ def _getSelectedChannel(self):
+ channels = self.selectedItems()
+ if len(channels) != 1:
+ return None
+ return channels[0]
+
+ def moveBottomChannel(self):
+ channel = self._getSelectedChannel()
+ if channel is None:
+ return
+ row = channel.row()
+ parent = channel.parent()
+ if row >= parent.childCount() - 1:
+ return
+ else:
+ # TODO: optimize it if necessary. Instead of moving one by one,
+ # try to remove the item from the list and insert it at the bottom.
+ self.moveDownChannel()
+ return self.moveBottomChannel()
+
+ def moveTopChannel(self):
+ channel = self._getSelectedChannel()
+ if channel is None:
+ return
+ row = channel.row()
+ if row < 1:
+ return
+ else:
+ # TODO: optimize it if necessary. Instead of moving one by one,
+ # try to remove the item from the list and insert it at the top.
+ self.moveUpChannel()
+ return self.moveTopChannel()
+
def moveUpChannel(self, channel=None):
if channel is None:
- channels = self.selectedItems()
- if len(channels) != 1:
+ channel = self._getSelectedChannel()
+ if channel is None:
return
- channel = channels[0]
parent = channel.parent()
row = channel.row()
if row < 1:
return
-
model = self.getQModel()
model.swapChannels(parent, row, row - 1)
idx = model.index(row - 1, 0)
@@ -951,10 +1000,9 @@ class MntGrpChannelEditor(TaurusBaseTableWidget):
def moveDownChannel(self, channel=None):
if channel is None:
- channels = self.selectedItems()
- if len(channels) != 1:
+ channel = self._getSelectedChannel()
+ if channel is None:
return
- channel = channels[0]
parent = channel.parent()
row = channel.row()
if row >= parent.childCount() - 1:
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/sardana.git
More information about the debian-science-commits
mailing list