[pytango] 379/483: Update documentation
Sandor Bodo-Merle
sbodomerle-guest at moszumanska.debian.org
Thu Sep 28 19:15:02 UTC 2017
This is an automated email from the git hooks/post-receive script.
sbodomerle-guest pushed a commit to annotated tag bliss_8.10
in repository pytango.
commit d6ad17441f9d51f5f149192eaea6098107a1d8fe
Author: tiagocoutinho <tiagocoutinho at 4e9c00fd-8f2e-0410-aa12-93ce3db5e235>
Date: Tue May 13 15:32:27 2014 +0000
Update documentation
git-svn-id: http://svn.code.sf.net/p/tango-cs/code/bindings/PyTango/trunk@25584 4e9c00fd-8f2e-0410-aa12-93ce3db5e235
---
doc/_static/PowerSupplyDS.py | 80 +++
doc/_static/arrow03.png | Bin 0 -> 5669 bytes
doc/_static/jive_powersupply.png | Bin 0 -> 14023 bytes
doc/_static/jquery-1.9.1.min.js | 20 +
doc/_static/jssor.css | 23 +
doc/_static/jssor.slider.mini.js | 2 +
doc/_templates/index.html | 122 +++-
doc/api.rst | 8 +-
doc/{client => client_api}/attribute_proxy.rst | 0
doc/{client => client_api}/device_proxy.rst | 0
doc/client_api/green.rst | 21 +
doc/{client => client_api}/group.rst | 0
doc/{client => client_api}/index.rst | 1 +
doc/client_api/miscellaneous.rst | 144 +++++
doc/{client => client_api}/other.rst | 0
doc/conf.py | 4 +
doc/contents.rst | 8 +-
doc/exception.rst | 26 +-
doc/faq.rst | 132 +----
doc/{client/miscellaneous.rst => green.rst} | 172 +-----
doc/{server/index.rst => howto.rst} | 734 ++++++++++++++-----------
doc/itango/highlights.rst | 4 +-
doc/quicktour.rst | 627 +++++++--------------
doc/revision.rst | 14 +-
doc/{server => server_api}/attribute.rst | 0
doc/{server => server_api}/device.rst | 0
doc/{server => server_api}/device_class.rst | 0
doc/server_api/index.rst | 67 +++
doc/{server => server_api}/logging.rst | 0
doc/{server => server_api}/server.rst | 6 +-
doc/{server => server_api}/util.rst | 0
doc/start.rst | 25 +-
32 files changed, 1142 insertions(+), 1098 deletions(-)
diff --git a/doc/_static/PowerSupplyDS.py b/doc/_static/PowerSupplyDS.py
new file mode 100644
index 0000000..e5b8e0d
--- /dev/null
+++ b/doc/_static/PowerSupplyDS.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""Demo power supply tango device server"""
+
+import time
+import numpy
+
+from PyTango import AttrQuality, AttrWriteType, DispLevel, DevState, DebugIt
+from PyTango.server import Device, DeviceMeta, attribute, command, run
+from PyTango.server import device_property
+
+
+class PowerSupply(Device):
+ __metaclass__ = DeviceMeta
+
+ voltage = attribute(label="Voltage", dtype=float,
+ display_level=DispLevel.OPERATOR,
+ access=AttrWriteType.READ,
+ unit="V",format="8.4f",
+ doc="the power supply voltage")
+
+ current = attribute(label="Current", dtype=float,
+ display_level=DispLevel.EXPERT,
+ access=AttrWriteType.READ_WRITE,
+ unit="A",format="8.4f",
+ min_value=0.0, max_value=8.5,
+ min_alarm=0.1, max_alarm=8.4,
+ min_warning=0.5, max_warning=8.0,
+ fget="get_current",
+ fset="set_current",
+ doc="the power supply current")
+
+ noise = attribute(label="Noise",
+ dtype=((int,),),
+ max_dim_x=1024, max_dim_y=1024)
+
+ host = device_property(dtype=str)
+ port = device_property(dtype=int, default_value=9788)
+
+ def init_device(self):
+ Device.init_device(self)
+ self.__current = 0.0
+ self.set_state(DevState.STANDBY)
+
+ def read_voltage(self):
+ self.info_stream("read_voltage(%s, %d)", self.host, self.port)
+ return 9.99, time.time(), AttrQuality.ATTR_WARNING
+
+ def get_current(self):
+ return self.__current
+
+ def set_current(self, current):
+ # should set the power supply current
+ self.__current = current
+
+ @DebugIt()
+ def read_noise(self):
+ return numpy.random.random_integers(1000, size=(100, 100))
+
+ @command
+ def TurnOn(self):
+ # turn on the actual power supply here
+ self.set_state(DevState.ON)
+
+ @command
+ def TurnOff(self):
+ # turn off the actual power supply here
+ self.set_state(DevState.OFF)
+
+ @command(dtype_in=float, doc_in="Ramp target current",
+ dtype_out=bool, doc_out="True if ramping went well, False otherwise")
+ def Ramp(self, target_current):
+ # should do the ramping
+ return True
+
+
+if __name__ == "__main__":
+ run([PowerSupply])
+
diff --git a/doc/_static/arrow03.png b/doc/_static/arrow03.png
new file mode 100644
index 0000000..1855c0b
Binary files /dev/null and b/doc/_static/arrow03.png differ
diff --git a/doc/_static/jive_powersupply.png b/doc/_static/jive_powersupply.png
new file mode 100644
index 0000000..f3cdc79
Binary files /dev/null and b/doc/_static/jive_powersupply.png differ
diff --git a/doc/_static/jquery-1.9.1.min.js b/doc/_static/jquery-1.9.1.min.js
new file mode 100644
index 0000000..bc1e707
--- /dev/null
+++ b/doc/_static/jquery-1.9.1.min.js
@@ -0,0 +1,20 @@
+
+/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
+//@ sourceMappingURL=jquery.min.map
+*/
+(function (e, t) {
+ var n, r, i = typeof t, o = e.document, a = e.location, s = e.jQuery, u = e.$, l = {}, c = [], p = "1.9.1", f = c.concat, d = c.push, h = c.slice, g = c.indexOf, m = l.toString, y = l.hasOwnProperty, v = p.trim, b = function (e, t) { return new b.fn.init(e, t, r) }, x = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, w = /\S+/g, T = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, N = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, C = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, k = /^[\],:{}\s]*$/, E = /(?:^|:|,)(?:\s*\[ [...]
+ b.event.special[e] = { delegateType: t, bindType: t, handle: function (e) {
+ var n, r = this, i = e.relatedTarget, o = e.handleObj;
+ return (!i || i !== r && !b.contains(r, i)) && (e.type = o.origType, n = o.handler.apply(this, arguments), e.type = t), n
+ }
+ }
+ }), b.support.submitBubbles || (b.event.special.submit = { setup: function () { return b.nodeName(this, "form") ? !1 : (b.event.add(this, "click._submit keypress._submit", function (e) { var n = e.target, r = b.nodeName(n, "input") || b.nodeName(n, "button") ? n.form : t; r && !b._data(r, "submitBubbles") && (b.event.add(r, "submit._submit", function (e) { e._submit_bubble = !0 }), b._data(r, "submitBubbles", !0)) }), t) }, postDispatch: function (e) { e._submit_bubble && (delete e._ [...]
+ var i, o, a, s, u, l, c, p = e.length, f = dt(t), d = [], h = 0; for (; p > h; h++) if (o = e[h], o || 0 === o) if ("object" === b.type(o)) b.merge(d, o.nodeType ? [o] : o); else if (wt.test(o)) {
+ s = s || f.appendChild(t.createElement("div")), u = (bt.exec(o) || ["", ""])[1].toLowerCase(), c = At[u] || At._default, s.innerHTML = c[1] + o.replace(vt, "<$1></$2>") + c[2], i = c[0]; while (i--) s = s.lastChild; if (!b.support.leadingWhitespace && yt.test(o) && d.push(t.createTextNode(yt.exec(o)[0])), !b.support.tbody) {
+ o = "table" !== u || xt.test(o) ? "<table>" !== c[1] || xt.test(o) ? 0 : s : s.firstChild, i = o && o.childNodes.length; while (i--) b.nodeName(l = o.childNodes[i], "tbody") && !l.childNodes.length && o.removeChild(l)
+ } b.merge(d, s.childNodes), s.textContent = ""; while (s.firstChild) s.removeChild(s.firstChild); s = f.lastChild
+ } else d.push(t.createTextNode(o)); s && f.removeChild(s), b.support.appendChecked || b.grep(Ot(d, "input"), Bt), h = 0; while (o = d[h++]) if ((!r || -1 === b.inArray(o, r)) && (a = b.contains(o.ownerDocument, o), s = Ot(f.appendChild(o), "script"), a && Mt(s), n)) { i = 0; while (o = s[i++]) kt.test(o.type || "") && n.push(o) } return s = null, f
+ }, cleanData: function (e, t) { var n, r, o, a, s = 0, u = b.expando, l = b.cache, p = b.support.deleteExpando, f = b.event.special; for (; null != (n = e[s]); s++) if ((t || b.acceptData(n)) && (o = n[u], a = o && l[o])) { if (a.events) for (r in a.events) f[r] ? b.event.remove(n, r) : b.removeEvent(n, r, a.handle); l[o] && (delete l[o], p ? delete n[u] : typeof n.removeAttribute !== i ? n.removeAttribute(u) : n[u] = null, c.push(o)) } }
+ }); var Pt, Rt, Wt, $t = /alpha\([^)]*\)/i, It = /opacity\s*=\s*([^)]*)/, zt = /^(top|right|bottom|left)$/, Xt = /^(none|table(?!-c[ea]).+)/, Ut = /^margin/, Vt = RegExp("^(" + x + ")(.*)$", "i"), Yt = RegExp("^(" + x + ")(?!px)[a-z%]+$", "i"), Jt = RegExp("^([+-])=(" + x + ")", "i"), Gt = { BODY: "block" }, Qt = { position: "absolute", visibility: "hidden", display: "block" }, Kt = { letterSpacing: 0, fontWeight: 400 }, Zt = ["Top", "Right", "Bottom", "Left"], en = ["Webkit", "O", " [...]
+})(window);
\ No newline at end of file
diff --git a/doc/_static/jssor.css b/doc/_static/jssor.css
new file mode 100644
index 0000000..908ed85
--- /dev/null
+++ b/doc/_static/jssor.css
@@ -0,0 +1,23 @@
+ /* jssor slider arrow navigator skin 03 css */
+/*
+.jssora03l (normal)
+.jssora03r (normal)
+.jssora03l:hover (normal mouseover)
+.jssora03r:hover (normal mouseover)
+.jssora03ldn (mousedown)
+.jssora03rdn (mousedown)
+*/
+.jssora03l, .jssora03r, .jssora03ldn, .jssora03rdn
+{
+ position: absolute;
+ cursor: pointer;
+ display: block;
+ background: url(../img/a03.png) no-repeat;
+ overflow:hidden;
+}
+.jssora03l { background-position: -3px -33px; }
+.jssora03r { background-position: -63px -33px; }
+.jssora03l:hover { background-position: -123px -33px; }
+.jssora03r:hover { background-position: -183px -33px; }
+.jssora03ldn { background-position: -243px -33px; }
+.jssora03rdn { background-position: -303px -33px; }
\ No newline at end of file
diff --git a/doc/_static/jssor.slider.mini.js b/doc/_static/jssor.slider.mini.js
new file mode 100644
index 0000000..b69c55a
--- /dev/null
+++ b/doc/_static/jssor.slider.mini.js
@@ -0,0 +1,2 @@
+(function(g,f,b,d,c,e,z){/*! Jssor */
+$Jssor$=g.$Jssor$=g.$Jssor$||{};new(function(){});var m=function(){var b=this,a={};b.$On=b.addEventListener=function(b,c){if(typeof c!="function")return;if(!a[b])a[b]=[];a[b].push(c)};b.$Off=b.removeEventListener=function(e,d){var b=a[e];if(typeof d!="function")return;else if(!b)return;for(var c=0;c<b.length;c++)if(d==b[c]){b.splice(c,1);return}};b.g=function(e){var c=a[e],d=[];if(!c)return;for(var b=1;b<arguments.length;b++)d.push(arguments[b]);for(var b=0;b<c.length;b++)try{c[b].apply( [...]
\ No newline at end of file
diff --git a/doc/_templates/index.html b/doc/_templates/index.html
index 478dfae..92a970d 100644
--- a/doc/_templates/index.html
+++ b/doc/_templates/index.html
@@ -1,10 +1,52 @@
{% extends "layout.html" %}
{% set title = 'PyTango documentation' %}
-{% set script_files = script_files + ["_static/slideshow.js"] %}
+{% set script_files = script_files + ["_static/jquery-1.9.1.min.js", "_static/jssor.slider.mini.js"] %}
{% block body %}
+<script>
+ jQuery(document).ready(function ($) {
+
+ var _SlideshowTransitions = [
+ //Fade
+ { $Duration: 1200, $Opacity: 2 }
+ ];
+
+ var options = {
+ $AutoPlay: true,
+ $AutoPlaySteps: 1,
+ $AutoPlayInterval: 3000,
+ $PauseOnHover: 1,
+ $ArrowKeyNavigation: true,
+ $SlideDuration: 500,
+ $MinDragOffsetToSlide: 20,
+ $SlideSpacing: 0,
+ $DisplayPieces: 1,
+ $ParkingPosition: 0,
+ $UISearchMode: 1,
+ $PlayOrientation: 1,
+ $DragOrientation: 3,
+
+ $SlideshowOptions: {
+ $Class: $JssorSlideshowRunner$,
+ $Transitions: _SlideshowTransitions,
+ $TransitionsOrder: 1,
+ $ShowLink: false
+ },
+
+ $ArrowNavigatorOptions: {
+ $Class: $JssorArrowNavigator$,
+ $ChanceToShow: 1,
+ $AutoCenter: 0,
+ $Steps: 1
+ }
+ };
+
+ var jssor_gallery = new $JssorSlider$("gallery", options);
+ });
+</script>
+
<h1>Welcome to PyTango documentation!</h1>
<p>
@@ -15,30 +57,33 @@
of this in pure python.
</p>
-<div id="gallery" style="width:610px; height:415px; margin:auto;">
-
- <img src="_static/banner1.png" />
+<div id="gallery" style="position:relative; top:0px; left:0px; width:610px; height:415px; margin:auto;">
- <iframe src="_static/ipython_tango.html" style="width:600px; height:411px;border: 0; "></iframe>
+ <div u="slides" style="cursor: move; position:absolute; top:0px; left:0px; width: 610px; height: 415px; overflow: hidden;">
- <iframe src="_static/ipython_db.html" style="width:600px; height:411px;border: 0; "></iframe>
+ <div style="background:white;"><img src="_static/banner1.png"/></div>
- <iframe src="_static/ipython_motor.html" style="width:600px; height:411px;border: 0; "></iframe>
+ <div style="background:white;"><iframe src="_static/ipython_tango.html" style="width:600px; height:411px;border: 0;"></iframe></div>
- <iframe src="_static/ipython_serial.html" style="width:600px; height:411px;border: 0; "></iframe>
+ <div style="background:white;"><iframe src="_static/ipython_db.html" style="width:600px; height:411px;border:0;"></iframe></div>
- <table style="width:100%;"><tr>
- <td>
+ <div style="background:white;"><iframe src="_static/ipython_motor.html" style="width:600px; height:411px;border:0;"></iframe></div>
+ <div style="background:white;"><iframe src="_static/ipython_serial.html" style="width:600px; height:411px;border:0;"></iframe></div>
+ <!-- 6th item -->
+ <div style="background: white;">
+ <table style="width:100%;"><tr><td>
<div class="highlight-python"><div class="highlight"><pre style="font-size: 10px;">
<span class="c"># ----------------- server ------------------</span>
+
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">from</span> <span class="nn">PyTango.server</span> <span class="kn">import</span> <span class="n">server_run</span>
<span class="kn">from</span> <span class="nn">PyTango.server</span> <span class="kn">import</span> <span class="n">Device</span><span class="p">,</span> <span class="n">DeviceMeta</span>
<span class="kn">from</span> <span class="nn">PyTango.server</span> <span class="kn">import</span> <span class="n">attribute</span><span class="p">,</span> <span class="n">command</span>
+
<span class="k">class</span> <span class="nc">Clock</span><span class="p">(</span><span class="n">Device</span><span class="p">):</span>
<span class="n">__metaclass__</span> <span class="o">=</span> <span class="n">DeviceMeta</span>
@@ -53,6 +98,7 @@
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
<span class="n">server_run</span><span class="p">((</span><span class="n">Clock</span><span class="p">,))</span>
+
</pre></div>
</div>
@@ -74,20 +120,24 @@
<span class="gp">>>> </span><span class="n">clock</span><span class="o">.</span><span class="n">read_attribute</span><span class="p">(</span><span class="s">"time"</span><span class="p">)</span><span class="o">.</span><span class="n">value</span>
<span class="go">1384447252.037578</span>
+<span class="gp">>>> </span><span class="n">clock</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">"%H:%M:%S"</span><span class="p">)</span>
+<span class="go">'17:41:50'</span>
+
<span class="gp">>>> </span><span class="n">clock</span><span class="o">.</span><span class="n">command_inout</span><span class="p">(</span><span class="s">"strftime"</span><span class="p">,</span>
<span class="gp">... </span> <span class="s">"%H:%M:%S"</span><span class="p">)</span>
-<span class="go">'17:41:50'</span>
+<span class="go">'17:43:12'</span>
<span class="gp">>>> </span><span class="n">clock</span><span class="o">.</span><span class="n">status</span><span class="p">()</span>
-<span class="go">The device is in UNKNOWN state.</span>
+<span class="go">'The device is in UNKNOWN state.'</span>
-</pre></div>
-</div>
+</pre></div></div>
+ </td></tr></table>
+ </div>
- </td>
- </tr></table>
+ <!-- 7th item -->
+ <div>
- <table style="width:100%;"><tr>
+ <table style="width:100%; background: white;"><tr>
<td>
<div class="highlight-python"><div class="highlight"><pre style="font-size: 10px;">
@@ -164,6 +214,44 @@
</td>
</tr></table>
+ </div>
+
+ </div> <!-- end of slide items -->
+
+ <!-- Arrow Navigator Skin Begin -->
+ <style>
+ /* jssor slider arrow navigator skin 03 css */
+ /*
+ .jssora03l (normal)
+ .jssora03r (normal)
+ .jssora03l:hover (normal mouseover)
+ .jssora03r:hover (normal mouseover)
+ .jssora03ldn (mousedown)
+ .jssora03rdn (mousedown)
+ */
+ .jssora03l, .jssora03r, .jssora03ldn, .jssora03rdn
+ {
+ position: absolute;
+ cursor: pointer;
+ display: block;
+ background: url(_static/arrow03.png) no-repeat;
+ overflow:hidden;
+ }
+ .jssora03l { background-position: -3px -33px; }
+ .jssora03r { background-position: -63px -33px; }
+ .jssora03l:hover { background-position: -123px -33px; }
+ .jssora03r:hover { background-position: -183px -33px; }
+ .jssora03ldn { background-position: -243px -33px; }
+ .jssora03rdn { background-position: -303px -33px; }
+
+ </style>
+ <!-- Arrow Left -->
+ <span u="arrowleft" class="jssora03l" style="width: 55px; height: 55px; top: 123px; left: 8px;">
+ </span>
+ <!-- Arrow Right -->
+ <span u="arrowright" class="jssora03r" style="width: 55px; height: 55px; top: 123px; right: 8px">
+ </span>
+
</div>
<p>
diff --git a/doc/api.rst b/doc/api.rst
index 745ab10..122da04 100644
--- a/doc/api.rst
+++ b/doc/api.rst
@@ -1,7 +1,7 @@
.. currentmodule:: PyTango
-.. _api:
+.. _pytango-api:
===========
PyTango API
@@ -10,12 +10,12 @@ PyTango API
.. automodule:: PyTango
.. toctree::
- :maxdepth: 2
+ :maxdepth: 1
data_types
- client/index
+ client_api/index
+ server_api/index
database
- server/index
encoded
utilities
exception
diff --git a/doc/client/attribute_proxy.rst b/doc/client_api/attribute_proxy.rst
similarity index 100%
rename from doc/client/attribute_proxy.rst
rename to doc/client_api/attribute_proxy.rst
diff --git a/doc/client/device_proxy.rst b/doc/client_api/device_proxy.rst
similarity index 100%
rename from doc/client/device_proxy.rst
rename to doc/client_api/device_proxy.rst
diff --git a/doc/client_api/green.rst b/doc/client_api/green.rst
new file mode 100644
index 0000000..9048861
--- /dev/null
+++ b/doc/client_api/green.rst
@@ -0,0 +1,21 @@
+
+.. pytango-client-green-api:
+
+=========
+Green API
+=========
+
+Summary:
+ * :func:`PyTango.get_green_mode`
+ * :func:`PyTango.set_green_mode`
+ * :func:`PyTango.futures.DeviceProxy`
+ * :func:`PyTango.gevent.DeviceProxy`
+
+.. autofunction:: PyTango.get_green_mode
+
+.. autofunction:: PyTango.set_green_mode
+
+.. autofunction:: PyTango.futures.DeviceProxy
+
+.. autofunction:: PyTango.gevent.DeviceProxy
+
diff --git a/doc/client/group.rst b/doc/client_api/group.rst
similarity index 100%
rename from doc/client/group.rst
rename to doc/client_api/group.rst
diff --git a/doc/client/index.rst b/doc/client_api/index.rst
similarity index 92%
rename from doc/client/index.rst
rename to doc/client_api/index.rst
index 317614a..b5ee594 100644
--- a/doc/client/index.rst
+++ b/doc/client_api/index.rst
@@ -7,5 +7,6 @@ Client API
device_proxy
attribute_proxy
group
+ green
miscellaneous
other
diff --git a/doc/client_api/miscellaneous.rst b/doc/client_api/miscellaneous.rst
new file mode 100644
index 0000000..27905d5
--- /dev/null
+++ b/doc/client_api/miscellaneous.rst
@@ -0,0 +1,144 @@
+.. currentmodule:: PyTango
+
+API util
+--------
+
+.. autoclass:: ApiUtil
+ :members:
+
+Information classes
+-------------------
+
+See also `Event configuration information`_
+
+Attribute
+~~~~~~~~~
+
+.. autoclass:: AttributeAlarmInfo
+ :members:
+
+.. autoclass:: AttributeDimension
+ :members:
+
+.. autoclass:: AttributeInfo
+ :members:
+
+.. autoclass:: AttributeInfoEx
+ :members:
+
+see also :class:`AttributeInfo`
+
+.. autoclass:: DeviceAttributeConfig
+ :members:
+
+Command
+~~~~~~~
+
+.. autoclass:: DevCommandInfo
+ :members:
+
+.. autoclass:: CommandInfo
+ :members:
+
+Other
+~~~~~
+
+.. autoclass:: DeviceInfo
+ :members:
+
+.. autoclass:: LockerInfo
+ :members:
+
+.. autoclass:: PollDevice
+ :members:
+
+
+Storage classes
+---------------
+
+Attribute: DeviceAttribute
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: DeviceAttribute
+ :members:
+
+
+Command: DeviceData
+~~~~~~~~~~~~~~~~~~~
+
+Device data is the type used internally by Tango to deal with command parameters
+and return values. You don't usually need to deal with it, as command_inout
+will automatically convert the parameters from any other type and the result
+value to another type.
+
+You can still use them, using command_inout_raw to get the result in a DeviceData.
+
+You also may deal with it when reading command history.
+
+.. autoclass:: DeviceData
+ :members:
+
+
+Callback related classes
+------------------------
+
+If you subscribe a callback in a DeviceProxy, it will be run with a parameter.
+This parameter depends will be of one of the following classes depending on
+the callback type.
+
+.. autoclass:: AttrReadEvent
+ :members:
+
+.. autoclass:: AttrWrittenEvent
+ :members:
+
+.. autoclass:: CmdDoneEvent
+ :members:
+
+
+Event related classes
+---------------------
+
+Event configuration information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: AttributeEventInfo
+ :members:
+
+.. autoclass:: ArchiveEventInfo
+ :members:
+
+.. autoclass:: ChangeEventInfo
+ :members:
+
+.. autoclass:: PeriodicEventInfo
+ :members:
+
+Event arrived structures
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: EventData
+ :members:
+
+.. autoclass:: AttrConfEventData
+ :members:
+
+.. autoclass:: DataReadyEventData
+ :members:
+
+
+History classes
+---------------
+
+.. autoclass:: DeviceAttributeHistory
+ :show-inheritance:
+ :members:
+
+See :class:`DeviceAttribute`.
+
+.. autoclass:: DeviceDataHistory
+ :show-inheritance:
+ :members:
+
+See :class:`DeviceData`.
+
diff --git a/doc/client/other.rst b/doc/client_api/other.rst
similarity index 100%
rename from doc/client/other.rst
rename to doc/client_api/other.rst
diff --git a/doc/conf.py b/doc/conf.py
index 302e1b5..fcd04e0 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -29,6 +29,7 @@ extensions = ['sphinx.ext.pngmath',
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
+ 'sphinx.ext.todo',
'ipython_console_highlighting',
'tango_console_highlighting']
@@ -253,6 +254,9 @@ intersphinx_mapping = {
'http://docs.sqlalchemy.org/en/rel_0_7/' : None,
}
+todo_include_todos = True
+
+
def copy_spaces(origin):
r = ''
for x in xrange(len(origin)):
diff --git a/doc/contents.rst b/doc/contents.rst
index dacf3b2..a2e34d8 100644
--- a/doc/contents.rst
+++ b/doc/contents.rst
@@ -13,14 +13,12 @@ Contents
start
quicktour
itango/index
+ green
API <api>
+ How to <howto>
+ FAQ <faq>
TEP <tep>
- faq
History of changes <revision>
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
**Last update:** |today|
diff --git a/doc/exception.rst b/doc/exception.rst
index e31e74d..6f8c2c4 100644
--- a/doc/exception.rst
+++ b/doc/exception.rst
@@ -3,8 +3,8 @@
.. highlight:: python
:linenothreshold: 4
-Exception Handling
-==================
+Exception API
+=============
Exception definition
--------------------
@@ -42,21 +42,15 @@ all of which containing the following kind of key-value pairs:
::
- # Protect the script from Exceptions raised by the Tango or python itself
+ import PyTango
+
+ # How to protect the script from exceptions raised by the Tango
try:
- # Get proxy on the tangotest1 device
- print "Getting DeviceProxy "
- tangotest = DeviceProxy("tango/tangotest/1")
-
- #Catch Tango and Systems Exceptions
- except DevFailed:
- exctype , value = sys.exc_info()[:2]
- print "Failed with exception ! " , exctype
- for err in value:
- print " reason" , err.reason
- print " description" , err.desc
- print " origin" , err.origin
- print " severity" , err.severity
+ # Get proxy on a non existing device should throw an exception
+ device = DeviceProxy("non/existing/device")
+ except DevFailed as df:
+ print("Failed to create proxy to non/existing/device:\n%s" % df)
+
Throwing exception in a device server
-------------------------------------
diff --git a/doc/faq.rst b/doc/faq.rst
index d3b4908..c559ec7 100644
--- a/doc/faq.rst
+++ b/doc/faq.rst
@@ -1,5 +1,7 @@
.. currentmodule:: PyTango
+.. _pytango-faq:
+
FAQ
===
@@ -7,8 +9,7 @@ Answers to general Tango questions can be found at http://www.tango-controls.org
Please also check http://www.tango-controls.org/howtos for a list of Tango howtos
-Where are the usual bjam files?
--------------------------------
+**Where are the usual bjam files?**
Starting from PyTango 7.0.0 the prefered way to build PyTango is using the standard
python distutils package. This means that:
@@ -19,8 +20,7 @@ python distutils package. This means that:
Please check the compilation chapter for details on how to build PyTango.
-I got a libbost_python error when I try to import PyTango module
-----------------------------------------------------------------
+**I got a libbost_python error when I try to import PyTango module**
doing:
>>> import PyTango
@@ -48,8 +48,7 @@ To see which boost python file PyTango needs type::
/lib64/ld-linux-x86-64.so.2 (0x00007f3940a4c000)
-My python code uses PyTango 3.0.4 API. How do I change to 7.0.0 API?
---------------------------------------------------------------------
+**My python code uses PyTango 3.0.4 API. How do I change to 7.0.0 API?**
To ease migration effort, PyTango 7 provides an alternative module called
PyTango3.
@@ -69,8 +68,7 @@ since the PyTango team cannot assure the maintainability of the PyTango3 module.
Please find below a basic set of rules to migrate from PyTango 3.0.x to 7:
-General rule of thumb for data types
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+*General rule of thumb for data types*
The first important thing to be aware of when migrating from PyTango <= 3.0.4 to
PyTango >= 7 is that the data type mapping from tango to python and vice versa is
@@ -162,8 +160,8 @@ reference, the proper code would be::
if not da.data_format is PyTango.AttrDataFormat.SCALAR:
print "array_attr is NOT a scalar attribute"
-Server
-~~~~~~
+*Server*
+
#. replace `PyTango.PyUtil` with :class:`Util`
@@ -176,8 +174,7 @@ Server
in PyTango 7 the methods have been renamed to **dev_state()** and **dev_status()** in
order to match the C++ API.
-General
-~~~~~~~
+*General*
#. AttributeValue does **NOT** exist anymore.
- the result of a read_attribute call on a :class:`DeviceProxy` / :class:`Group`
@@ -224,118 +221,15 @@ General
print e.args[0].reason
-Optional
-~~~~~~~~
+*Optional*
The following is a list of API improvements. Some where added for performance
reasons, others to allow for a more pythonic interface, others still to reflect
more adequately the C++ interface. They are not mandatory since the original
interface will still be available.
-Server side V3 to V4 upgrade
-############################
-
-If you want your server to support the V4 interface provided by Tango 7
-instead of the V3 provided by Tango 6:
-
-- replace the inheritance of your device class from :class:`Device_3Impl` to :class:`Device_4Impl`
-- in the `init_device` method replace the call::
-
- Device_3Impl.init_device(self)
-
- with::
-
- Device_4Impl.init_device(self)
-
- or better yet, if your device class only inherits from :class:`Device_4Impl`::
-
- super(<your class>, self).init_device()
-
-Improved server side image attribute read API
-#############################################
-
-In PyTango <= 3.0.4, to set the value of an image attribute you needed it
-as a flat list. Consider you want to set as value the following image::
-
- # Image:
- # | 1 2 |
- # | 3 4 |
-
-In order to tell tango the dimensions of the image you had to specify them as::
-
- image = [ 1, 2, 3, 4]
- dim_x = 2
- dim_y = 2
- attr.set_value(image, dim_x, dim_y)
-
-In PyTango 8 it is still supported, but the preferred way is to use a
-sequence of sequences (instead of a flat sequence), so the dimensions
-are inherent and not needed anymore::
-
- image = [ [1, 2], [3, 4]]
- attr.set_value(image)
-
-If you use a numpy array as the sequence of sequences you can get better
-performance::
-
- image = numpy.array([ [1, 2], [3, 4]], dtype=numpy.int32)
- attr.set_value(image)
-
-Likewise, calls to::
-
- PyTango.set_attribute_value_date_quality(attr, value, date, quality, dim_x, dim_y)
-
-can be replaced with::
+**Why is there a "-Wstrict-prototypes" warning when I compile PyTango?**
- attr.set_value_date_quality(value, date, quality)
-
-Improved server side attribute write API
-########################################
-
-Imagine the following value is written to our IMAGE attribute::
-
- # Image:
- # | 1 2 |
- # | 3 4 |
-
-This is what you would do with PyTango <= 3.0.4::
-
- flatList = []
- attr.get_write_value(flatList)
- print "flatList =", flatList
- # flatList = [ 1, 2, 3, 4 ]
-
-You can still do it with PyTango 8. However I recommend::
-
- image = attr.get_write_value()
- print "image =", image
- # image = numpy.array([[1, 2], [3, 4]])
-
-If PyTango 8 is compiled without numpy support, you will get a sequence
-of sequences, which makes more sense than a flat list.
-
-If PyTango 8 is compiled with numpy support it does not only makes more sense
-but it is also considerably **faster and memory friendlier**.
-
-If PyTango is compiled with numpy support but you prefer a list of lists for
-some attribute, you can do::
-
- image = attr.get_write_value(PyTango.ExtractAs.List)
- print "image =", image
- # image = [[1, 2], [3, 4]]
-
-Also the SCALAR attribute case is much **cleaner** now. Instead of::
-
- data = []
- attr.get_write_value(data)
- actualData = data[0]
-
-You can just write::
-
- actualData = attr.get_write_value()
-
-Why is there a "-Wstrict-prototypes" warning when I compile PyTango?
---------------------------------------------------------------------
The PyTango prefered build system (distutils) uses the same flags used to compile
Python to compile PyTango. It happens that Python is compiled as a pure C library
@@ -349,8 +243,8 @@ For reference here is the complete error message you may have:
Do not worry about this warning since the compiler is ignoring the presence of this flag
in the compilation.
-Why are there so many warnings when generating the documentation?
------------------------------------------------------------------
+**Why are there so many warnings when generating the documentation?**
+
PyTango uses boost python for the binding between C++ and Python and sphinx for
document generation.
When sphinx generates the PyTango API documentation it uses introspection to search
diff --git a/doc/client/miscellaneous.rst b/doc/green.rst
similarity index 76%
rename from doc/client/miscellaneous.rst
rename to doc/green.rst
index 0eaba34..eee9a4e 100644
--- a/doc/client/miscellaneous.rst
+++ b/doc/green.rst
@@ -1,7 +1,7 @@
.. currentmodule:: PyTango
-Green objects
--------------
+Green
+-----
PyTango supports cooperative green Tango objects. Since version 8.1 two *green*
modes have been added: :obj:`~PyTango.GreenMode.Futures` and
@@ -264,171 +264,3 @@ Here is another example using :meth:`~DeviceProxy.read_attribute`::
This is, in fact, one of the major bonus of working with :mod:`gevent` when
compared with :mod:`concurrent.futures`
-
-Green API
-~~~~~~~~~
-
-Summary:
- * :func:`PyTango.get_green_mode`
- * :func:`PyTango.set_green_mode`
- * :func:`PyTango.futures.DeviceProxy`
- * :func:`PyTango.gevent.DeviceProxy`
-
-.. autofunction:: PyTango.get_green_mode
-
-.. autofunction:: PyTango.set_green_mode
-
-.. autofunction:: PyTango.futures.DeviceProxy
-
-.. autofunction:: PyTango.gevent.DeviceProxy
-
-
-Low level API
-#############
-
-.. autofunction:: get_device_proxy
-
-.. autofunction:: get_attribute_proxy
-
-API util
---------
-
-.. autoclass:: PyTango.ApiUtil
- :members:
-
-Information classes
--------------------
-
-See also `Event configuration information`_
-
-Attribute
-~~~~~~~~~
-
-.. autoclass:: PyTango.AttributeAlarmInfo
- :members:
-
-.. autoclass:: PyTango.AttributeDimension
- :members:
-
-.. autoclass:: PyTango.AttributeInfo
- :members:
-
-.. autoclass:: PyTango.AttributeInfoEx
- :members:
-
-see also :class:`PyTango.AttributeInfo`
-
-.. autoclass:: PyTango.DeviceAttributeConfig
- :members:
-
-Command
-~~~~~~~
-
-.. autoclass:: PyTango.DevCommandInfo
- :members:
-
-.. autoclass:: PyTango.CommandInfo
- :members:
-
-Other
-~~~~~
-
-.. autoclass:: PyTango.DeviceInfo
- :members:
-
-.. autoclass:: PyTango.LockerInfo
- :members:
-
-.. autoclass:: PyTango.PollDevice
- :members:
-
-
-Storage classes
----------------
-
-Attribute: DeviceAttribute
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. autoclass:: DeviceAttribute
- :members:
-
-
-Command: DeviceData
-~~~~~~~~~~~~~~~~~~~
-
-Device data is the type used internally by Tango to deal with command parameters
-and return values. You don't usually need to deal with it, as command_inout
-will automatically convert the parameters from any other type and the result
-value to another type.
-
-You can still use them, using command_inout_raw to get the result in a DeviceData.
-
-You also may deal with it when reading command history.
-
-.. autoclass:: DeviceData
- :members:
-
-
-Callback related classes
-------------------------
-
-If you subscribe a callback in a DeviceProxy, it will be run with a parameter.
-This parameter depends will be of one of the following classes depending on
-the callback type.
-
-.. autoclass:: PyTango.AttrReadEvent
- :members:
-
-.. autoclass:: PyTango.AttrWrittenEvent
- :members:
-
-.. autoclass:: PyTango.CmdDoneEvent
- :members:
-
-
-Event related classes
----------------------
-
-Event configuration information
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. autoclass:: PyTango.AttributeEventInfo
- :members:
-
-.. autoclass:: PyTango.ArchiveEventInfo
- :members:
-
-.. autoclass:: PyTango.ChangeEventInfo
- :members:
-
-.. autoclass:: PyTango.PeriodicEventInfo
- :members:
-
-Event arrived structures
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. autoclass:: PyTango.EventData
- :members:
-
-.. autoclass:: PyTango.AttrConfEventData
- :members:
-
-.. autoclass:: PyTango.DataReadyEventData
- :members:
-
-
-History classes
----------------
-
-.. autoclass:: PyTango.DeviceAttributeHistory
- :show-inheritance:
- :members:
-
-See :class:`DeviceAttribute`.
-
-.. autoclass:: PyTango.DeviceDataHistory
- :show-inheritance:
- :members:
-
-See :class:`DeviceData`.
-
diff --git a/doc/server/index.rst b/doc/howto.rst
similarity index 78%
rename from doc/server/index.rst
rename to doc/howto.rst
index d437c04..ef511a3 100644
--- a/doc/server/index.rst
+++ b/doc/howto.rst
@@ -2,38 +2,440 @@
.. highlight:: python
:linenothreshold: 3
-
-.. _server:
-
-Server API
-==========
+======
+How to
+======
+
+Check the default TANGO host
+----------------------------
+
+.. todo::
+ write this how to
+
+
+Work with Groups
+----------------
+
+.. todo::
+ write this how to
+
+Handle errors
+-------------
+
+.. todo::
+ write this how to
+
+Check TANGO version
+-------------------
+
+.. todo::
+ write this how to
+
+Report a bug
+------------
+
+.. todo::
+ write this how to
+
+Write a server
+--------------
+
+Before reading this chapter you should be aware of the TANGO basic concepts.
This chapter does not explain what a Tango device or a device server is.
-This is explained in details in "The Tango control system manual" available at
-http://www.tango-controls.org/TangoKernel.
-The device server described in the following example is a Tango device server
-with one Tango class called *PyDsExp*. This class has two commands called
-*IOLong* and *IOStringArray* and two attributes called *Long_attr* and
-*Short_attr_rw*.
+This is explained in details in the
+`Tango control system manual <http://www.tango-controls.org/TangoKernel>`_
+
+Since version 8.1, PyTango provides a helper module which simplifies the
+development of a Tango device server. This helper is provided through the
+:mod:`PyTango.server` module.
-Importing python modules
-------------------------
+Here is a simple example on how to write a *Clock* device server using the
+high level API::
+
+ import time
+ from PyTango.server import run
+ from PyTango.server import Device, DeviceMeta
+ from PyTango.server import attribute, command
-To write a Python script which is a Tango device server, you need to import
-two modules which are:
-1. The :mod:`PyTango` module which is the Python to C++ interface
-2. The Python classical :mod:`sys` module
+ class Clock(Device):
+ __metaclass__ = DeviceMeta
-This could be done with code like (supposing the PYTHONPATH environment variable
-is correctly set)::
+ time = attribute()
- import PyTango
- import sys
+ def read_time(self):
+ return time.time()
-The main part of a Python device server
+ @command(din_type=str, dout_type=str)
+ def strftime(self, format):
+ return time.strftime(format)
+
+
+ if __name__ == "__main__":
+ run((Clock,))
+
+
+Here is a more complete example on how to write a *PowerSupply* device server
+using the high level API. The example contains:
+
+#. a read-only double scalar attribute called *voltage*
+#. a read/write double scalar expert attribute *current*
+#. a read-only double image attribute called *noise*
+#. a *ramp* command
+#. a *host* device property
+#. a *port* class property
+
+.. code-block:: python
+ :linenos:
+
+ from time import time
+ from numpy.random import random_sample
+
+ from PyTango import AttrQuality, AttrWriteType, DispLevel, server_run
+ from PyTango.server import Device, DeviceMeta, attribute, command
+ from PyTango.server import class_property, device_property
+
+ class PowerSupply(Device):
+ __metaclass__ = DeviceMeta
+
+ voltage = attribute()
+
+ current = attribute(label="Current", dtype=float,
+ display_level=DispLevel.EXPERT,
+ access=AttrWriteType.READ_WRITE,
+ unit="A", format="8.4f",
+ min_value=0.0, max_value=8.5,
+ min_alarm=0.1, max_alarm=8.4,
+ min_warning=0.5, max_warning=8.0,
+ fget="get_current", fset="set_current",
+ doc="the power supply current")
+
+ noise = attribute(label="Noise", dtype=((float,),),
+ max_dim_x=1024, max_dim_y=1024,
+ fget="get_noise")
+
+ host = device_property(dtype=str)
+ port = class_property(dtype=int, default_value=9788)
+
+ def read_voltage(self):
+ self.info_stream("get voltage(%s, %d)" % (self.host, self.port))
+ return 10.0
+
+ def get_current(self):
+ return 2.3456, time(), AttrQuality.ATTR_WARNING
+
+ def set_current(self, current):
+ print("Current set to %f" % current)
+
+ def get_noise(self):
+ return random_sample((1024, 1024))
+
+ @command(dtype_in=float)
+ def ramp(self, value):
+ print("Ramping up...")
+
+ if __name__ == "__main__":
+ server_run((PowerSupply,))
+
+*Pretty cool, uh?*
+
+.. note::
+ the ``__metaclass__`` statement is mandatory due to a limitation in the
+ *boost-python* library used by PyTango.
+
+ If you are using python 3 you can write instead::
+
+ class PowerSupply(Device, metaclass=DeviceMeta)
+ pass
+
+.. _logging:
+
+Server logging
+--------------
+
+This chapter instructs you on how to use the tango logging API (log4tango) to
+create tango log messages on your device server.
+
+The logging system explained here is the Tango Logging Service (TLS). For
+detailed information on how this logging system works please check:
+
+ * `3.5 The tango logging service <http://www.esrf.eu/computing/cs/tango/tango_doc/kernel_doc/ds_prog/node4.html#sec:The-Tango-Logging>`_
+ * `9.3 The tango logging service <http://www.esrf.eu/computing/cs/tango/tango_doc/kernel_doc/ds_prog/node9.html#SECTION00930000000000000000>`_
+
+The easiest way to start seeing log messages on your device server console is
+by starting it with the verbose option. Example::
+
+ python PyDsExp.py PyDs1 -v4
+
+This activates the console tango logging target and filters messages with
+importance level DEBUG or more.
+The links above provided detailed information on how to configure log levels
+and log targets. In this document we will focus on how to write log messages on
+your device server.
+
+Basic logging
+~~~~~~~~~~~~~
+
+The most basic way to write a log message on your device is to use the
+:class:`~PyTango.server.Device` logging related methods:
+
+ * :meth:`~PyTango.server.Device.debug_stream`
+ * :meth:`~PyTango.server.Device.info_stream`
+ * :meth:`~PyTango.server.Device.warn_stream`
+ * :meth:`~PyTango.server.Device.error_stream`
+ * :meth:`~PyTango.server.Device.fatal_stream`
+
+Example::
+
+ def read_voltage(self):
+ self.info_stream("read voltage attribute")
+ # ...
+ return voltage_value
+
+This will print a message like::
+
+ 1282206864 [-1215867200] INFO test/power_supply/1 read voltage attribute
+
+every time a client asks to read the *voltage* attribute value.
+
+The logging methods support argument list feature (since PyTango 8.1). Example::
+
+ def read_voltage(self):
+ self.info_stream("read_voltage(%s, %d)", self.host, self.port)
+ # ...
+ return voltage_value
+
+
+Logging with print statement
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+*This feature is only possible since PyTango 7.1.3*
+
+It is possible to use the print statement to log messages into the tango logging
+system. This is achieved by using the python's print extend form sometimes
+refered to as *print chevron*.
+
+Same example as above, but now using *print chevron*::
+
+ def read_voltage(self, the_att):
+ print >>self.log_info, "read voltage attribute"
+ # ...
+ return voltage_value
+
+Or using the python 3k print function::
+
+ def read_Long_attr(self, the_att):
+ print("read voltage attribute", file=self.log_info)
+ # ...
+ return voltage_value
+
+
+Logging with decorators
+~~~~~~~~~~~~~~~~~~~~~~~
+
+*This feature is only possible since PyTango 7.1.3*
+
+PyTango provides a set of decorators that place automatic log messages when
+you enter and when you leave a python method. For example::
+
+ @PyTango.DebugIt()
+ def read_Long_attr(self, the_att):
+ the_att.set_value(self.attr_long)
+
+will generate a pair of log messages each time a client asks for the 'Long_attr'
+value. Your output would look something like::
+
+ 1282208997 [-1215965504] DEBUG test/pydsexp/1 -> read_Long_attr()
+ 1282208997 [-1215965504] DEBUG test/pydsexp/1 <- read_Long_attr()
+
+Decorators exist for all tango log levels:
+ * :class:`PyTango.DebugIt`
+ * :class:`PyTango.InfoIt`
+ * :class:`PyTango.WarnIt`
+ * :class:`PyTango.ErrorIt`
+ * :class:`PyTango.FatalIt`
+
+The decorators receive three optional arguments:
+ * show_args - shows method arguments in log message (defaults to False)
+ * show_kwargs shows keyword method arguments in log message (defaults to False)
+ * show_ret - shows return value in log message (defaults to False)
+
+Example::
+
+ @PyTango.DebugIt(show_args=True, show_ret=True)
+ def IOLong(self, in_data):
+ return in_data * 2
+
+will output something like::
+
+ 1282221947 [-1261438096] DEBUG test/pydsexp/1 -> IOLong(23)
+ 1282221947 [-1261438096] DEBUG test/pydsexp/1 46 <- IOLong()
+
+
+Mix multiple device classes in a server
---------------------------------------
+.. todo::
+ write this how to
+
+
+Create attributes dynamically
+-----------------------------
+
+It is also possible to create dynamic attributes within a Python device server.
+There are several ways to create dynamic attributes. One of the way, is to
+create all the devices within a loop, then to create the dynamic attributes and
+finally to make all the devices available for the external world. In C++ device
+server, this is typically done within the <Device>Class::device_factory() method.
+In Python device server, this method is generic and the user does not have one.
+Nevertheless, this generic device_factory method calls a method named dyn_attr()
+allowing the user to create his dynamic attributes. It is simply necessary to
+re-define this method within your <Device>Class and to create the dynamic
+attribute within this method:
+
+ ``dyn_attr(self, dev_list)``
+
+ where dev_list is a list containing all the devices created by the
+ generic device_factory() method.
+
+There is another point to be noted regarding dynamic attribute within Python
+device server. The Tango Python device server core checks that for each
+attribute it exists methods named <attribute_name>_read and/or
+<attribute_name>_write and/or is_<attribute_name>_allowed. Using dynamic
+attribute, it is not possible to define these methods because attributes name
+and number are known only at run-time.
+To address this issue, the Device_3Impl::add_attribute() method has a diferent
+signature for Python device server which is:
+
+ ``add_attribute(self, attr, r_meth = None, w_meth = None, is_allo_meth = None)``
+
+attr is an instance of the Attr class, r_meth is the method which has to be
+executed with the attribute is read, w_meth is the method to be executed
+when the attribute is written and is_allo_meth is the method to be executed
+to implement the attribute state machine. The method passed here as argument
+as to be class method and not object method. Which argument you have to use
+depends on the type of the attribute (A WRITE attribute does not need a
+read method). Note, that depending on the number of argument you pass to this
+method, you may have to use Python keyword argument. The necessary methods
+required by the Tango Python device server core will be created automatically
+as a forward to the methods given as arguments.
+
+Here is an example of a device which has a TANGO command called
+*createFloatAttribute*. When called, this command creates a new scalar floating
+point attribute with the specified name::
+
+
+ from PyTango import Util, Attr
+ from PyTango.server import DeviceMeta, Device, command
+
+ class MyDevice(Device):
+ __metaclass__ = DeviceMeta
+
+ @command(dtype_in=str)
+ def CreateFloatAttribute(self, attr_name):
+ attr = Attr(attr_name, PyTango.DevDouble)
+ self.add_attribute(attr, self.read_General, self.write_General)
+
+ def read_General(self, attr):
+ self.info_stream("Reading attribute %s", attr.get_name())
+ attr.set_value(99.99)
+
+ def write_General(self, attr):
+ self.info_stream("Writting attribute %s", attr.get_name())
+
+
+Create/Delete devices dynamically
+---------------------------------
+
+*This feature is only possible since PyTango 7.1.2*
+
+Starting from PyTango 7.1.2 it is possible to create devices in a device server
+"en caliente". This means that you can create a command in your "management device"
+of a device server that creates devices of (possibly) several other tango classes.
+There are two ways to create a new device which are described below.
+
+Dynamic device from a known tango class name
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you know the tango class name but you don't have access to the :class:`PyTango.DeviceClass`
+(or you are too lazy to search how to get it ;-) the way to do it is call
+:meth:`~PyTango.Util.create_device` / :meth:`~PyTango.Util.delete_device`.
+Here is an example of implementing a tango command on one of your devices that
+creates a device of some arbitrary class (the example assumes the tango commands
+'CreateDevice' and 'DeleteDevice' receive a parameter of type DevVarStringArray
+with two strings. No error processing was done on the code for simplicity sake)::
+
+ from PyTango import Util
+ from PyTango.server import DeviceMeta, Device, command
+
+ class MyDevice(Device):
+ __metaclass__ = DeviceMeta
+
+ @command(dtype_in=[str])
+ def CreateDevice(self, pars):
+ klass_name, dev_name = pars
+ util = Util.instance()
+ util.create_device(klass_name, dev_name, alias=None, cb=None)
+
+ @command(dtype_in=[str])
+ def DeleteDevice(self, pars):
+ klass_name, dev_name = pars
+ util = Util.instance()
+ util.delete_device(klass_name, dev_name)
+
+An optional callback can be registered that will be executed after the device is
+registed in the tango database but before the actual device object is created
+and its init_device method is called. It can be used, for example, to initialize
+some device properties.
+
+Dynamic device from a known tango class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you already have access to the :class:`~PyTango.DeviceClass` object that
+corresponds to the tango class of the device to be created you can call directly
+the :meth:`~PyTango.DeviceClass.create_device` / :meth:`~PyTango.DeviceClass.delete_device`.
+For example, if you wish to create a clone of your device, you can create a
+tango command called *Clone*::
+
+ class MyDevice(PyTango.Device_4Impl):
+
+ def fill_new_device_properties(self, dev_name):
+ prop_names = db.get_device_property_list(self.get_name(), "*")
+ prop_values = db.get_device_property(self.get_name(), prop_names.value_string)
+ db.put_device_property(dev_name, prop_values)
+
+ # do the same for attributes...
+ ...
+
+ def Clone(self, dev_name):
+ klass = self.get_device_class()
+ klass.create_device(dev_name, alias=None, cb=self.fill_new_device_properties)
+
+ def DeleteSibling(self, dev_name):
+ klass = self.get_device_class()
+ klass.delete_device(dev_name)
+
+Note that the cb parameter is optional. In the example it is given for
+demonstration purposes only.
+
+.. _server:
+
+Write a server (original API)
+-----------------------------
+
+This chapter describes how to develop a PyTango device server using the
+original PyTango server API. This API mimics the C++ API and is considered
+low level.
+You should write a server using this API if you are using code generated by
+`Pogo tool <http://www.esrf.eu/computing/cs/tango/tango_doc/tools_doc/pogo_doc/index.html>`_
+or if for some reason the high level API helper doesn't provide a feature
+you need (in that case think of writing a mail to tango mailing list explaining
+what you cannot do).
+
+The main part of a Python device server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
The rule of this part of a Tango device server is to:
- Create the :class:`Util` object passing it the Python interpreter command
@@ -68,7 +470,7 @@ The following is a typical code for this main function::
Run the device server loop
The PyDsExpClass class in Python
---------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The rule of this class is to :
@@ -122,7 +524,7 @@ constructor. An example of such a contructor is ::
The device type is set at line 3.
Defining commands
------------------
+~~~~~~~~~~~~~~~~~
As shown in the previous example, commands have to be defined in a :class:`dict`
called *cmd_list* as a data member of the xxxClass class of the Tango class.
@@ -152,7 +554,7 @@ this :class:`dict` are summarized in the following array:
+-------------------+----------------------+------------------------------------------+
Defining attributes
--------------------
+~~~~~~~~~~~~~~~~~~~
As shown in the previous example, attributes have to be defined in a :class:`dict`
called **attr_list** as a data
@@ -217,7 +619,7 @@ array:
+-------------------+-----------------------------------+------------------------------------------+
The PyDsExp class in Python
----------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
The rule of this class is to implement methods executed by commands and attributes.
In our example, the code of this class looks like::
@@ -480,284 +882,4 @@ write the Short_attr_rw attribute::
store the value written in the device object. Our attribute is a scalar
short attribute so the return value is an int
-.. _logging:
-
-Logging
-#######
-
-This chapter instructs you on how to use the tango logging API (log4tango) to
-create tango log messages on your device server.
-
-The logging system explained here is the Tango Logging Service (TLS). For
-detailed information on how this logging system works please check:
-
- * `3.5 The tango logging service <http://www.esrf.eu/computing/cs/tango/tango_doc/kernel_doc/ds_prog/node4.html#sec:The-Tango-Logging>`_
- * `9.3 The tango logging service <http://www.esrf.eu/computing/cs/tango/tango_doc/kernel_doc/ds_prog/node9.html#SECTION00930000000000000000>`_
-
-The easiest way to start seeing log messages on your device server console is
-by starting it with the verbose option. Example::
-
- python PyDsExp.py PyDs1 -v4
-
-This activates the console tango logging target and filters messages with
-importance level DEBUG or more.
-The links above provided detailed information on how to configure log levels
-and log targets. In this document we will focus on how to write log messages on
-your device server.
-
-Basic logging
-~~~~~~~~~~~~~
-
-The most basic way to write a log message on your device is to use the
-:class:`PyTango.DeviceImpl` logging related methods:
-
- * :meth:`PyTango.DeviceImpl.debug_stream`
- * :meth:`PyTango.DeviceImpl.info_stream`
- * :meth:`PyTango.DeviceImpl.warn_stream`
- * :meth:`PyTango.DeviceImpl.error_stream`
- * :meth:`PyTango.DeviceImpl.fatal_stream`
-
-Example::
-
- def read_Long_attr(self, the_att):
- self.info_stream("read attribute name Long_attr")
- the_att.set_value(self.attr_long)
-
-This will print a message like::
-
- 1282206864 [-1215867200] INFO test/pydsexp/1 read attribute name Long_attr
-
-every time a client asks to read the 'Long_attr' attribute value.
-
-Logging with print statement
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-*This feature is only possible since PyTango 7.1.3*
-
-It is possible to use the print statement to log messages into the tango logging
-system. This is achieved by using the python's print extend form sometimes
-refered to as *print chevron*.
-
-Same example as above, but now using *print chevron*::
-
- def read_Long_attr(self, the_att):
- print >>self.log_info, "read attribute name Long_attr"
- the_att.set_value(self.attr_long)
-
-Or using the python 3k print function::
-
- def read_Long_attr(self, the_att):
- print("read attribute name Long_attr", file=self.log_info)
- the_att.set_value(self.attr_long)
-
-Logging with decorators
-~~~~~~~~~~~~~~~~~~~~~~~
-
-*This feature is only possible since PyTango 7.1.3*
-
-PyTango provides a set of decorators that place automatic log messages when
-you enter and when you leave a python method. For example::
-
- @PyTango.DebugIt()
- def read_Long_attr(self, the_att):
- the_att.set_value(self.attr_long)
-
-will generate a pair of log messages each time a client asks for the 'Long_attr'
-value. Your output would look something like::
-
- 1282208997 [-1215965504] DEBUG test/pydsexp/1 -> read_Long_attr()
- 1282208997 [-1215965504] DEBUG test/pydsexp/1 <- read_Long_attr()
-
-Decorators exist for all tango log levels:
- * :class:`PyTango.DebugIt`
- * :class:`PyTango.InfoIt`
- * :class:`PyTango.WarnIt`
- * :class:`PyTango.ErrorIt`
- * :class:`PyTango.FatalIt`
-
-The decorators receive three optional arguments:
- * show_args - shows method arguments in log message (defaults to False)
- * show_kwargs shows keyword method arguments in log message (defaults to False)
- * show_ret - shows return value in log message (defaults to False)
-
-Example::
-
- @PyTango.DebugIt(show_args=True, show_ret=True)
- def IOLong(self, in_data):
- return in_data * 2
-
-will output something like::
-
- 1282221947 [-1261438096] DEBUG test/pydsexp/1 -> IOLong(23)
- 1282221947 [-1261438096] DEBUG test/pydsexp/1 46 <- IOLong()
-
-Dynamic devices
-###############
-
-*This feature is only possible since PyTango 7.1.2*
-
-Starting from PyTango 7.1.2 it is possible to create devices in a device server
-"en caliente". This means that you can create a command in your "management device"
-of a device server that creates devices of (possibly) several other tango classes.
-There are two ways to create a new device which are described below.
-
-Dynamic device from a known tango class name
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you know the tango class name but you don't have access to the :class:`PyTango.DeviceClass`
-(or you are too lazy to search how to get it ;-) the way to do it is call
-:meth:`PyTango.Util.create_device` / :meth:`PyTango.Util.delete_device`.
-Here is an example of implementing a tango command on one of your devices that
-creates a device of some arbitrary class (the example assumes the tango commands
-'CreateDevice' and 'DeleteDevice' receive a parameter of type DevVarStringArray
-with two strings. No error processing was done on the code for simplicity sake)::
-
- class MyDevice(PyTango.Device_4Impl):
-
- def CreateDevice(self, pars):
- klass_name, dev_name = pars
- util = PyTango.Util.instance()
- util.create_device(klass_name, dev_name, alias=None, cb=None)
-
- def DeleteDevice(self, pars):
- klass_name, dev_name = pars
- util = PyTango.Util.instance()
- util.delete_device(klass_name, dev_name)
-
-An optional callback can be registered that will be executed after the device is
-registed in the tango database but before the actual device object is created and its
-init_device method is called. You can, for example, initialize some device properties
-here.
-Dynamic device from a known tango class
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you already have access to the :class:`PyTango.DeviceClass` object that
-corresponds to the tango class of the device to be created you can call directly
-the :meth:`PyTango.DeviceClass.create_device` / :meth:`PyTango.DeviceClass.delete_device`.
-For example, if you wish to create a clone of your device, you can create a
-tango command called Clone::
-
- class MyDevice(PyTango.Device_4Impl):
-
- def fill_new_device_properties(self, dev_name):
- prop_names = db.get_device_property_list(self.get_name(), "*")
- prop_values = db.get_device_property(self.get_name(), prop_names.value_string)
- db.put_device_property(dev_name, prop_values)
-
- # do the same for attributes...
- ...
-
- def Clone(self, dev_name):
- klass = self.get_device_class()
- klass.create_device(dev_name, alias=None, cb=self.fill_new_device_properties)
-
- def DeleteSibling(self, dev_name):
- klass = self.get_device_class()
- klass.delete_device(dev_name)
-
-Note that the cb parameter is optional. In the example it is given for
-demonstration purposes only.
-
-Dynamic attributes
-##################
-
-It is also possible to create dynamic attributes within a Python device server.
-There are several ways to create dynamic attributes. One of the way, is to
-create all the devices within a loop, then to create the dynamic attributes and
-finally to make all the devices available for the external world. In C++ device
-server, this is typically done within the <Device>Class::device_factory() method.
-In Python device server, this method is generic and the user does not have one.
-Nevertheless, this generic device_factory method calls a method named dyn_attr()
-allowing the user to create his dynamic attributes. It is simply necessary to
-re-define this method within your <Device>Class and to create the dynamic
-attribute within this method:
-
- ``dyn_attr(self, dev_list)``
-
- where dev_list is a list containing all the devices created by the
- generic device_factory() method.
-
-There is another point to be noted regarding dynamic attribute within Python
-device server. The Tango Python device server core checks that for each
-attribute it exists methods named <attribute_name>_read and/or
-<attribute_name>_write and/or is_<attribute_name>_allowed. Using dynamic
-attribute, it is not possible to define these methods because attributes name
-and number are known only at run-time.
-To address this issue, the Device_3Impl::add_attribute() method has a diferent
-signature for Python device server which is:
-
- ``add_attribute(self, attr, r_meth = None, w_meth = None, is_allo_meth = None)``
-
- attr is an instance of the Attr class, r_meth is the method which has to be
- executed with the attribute is read, w_meth is the method to be executed
- when the attribute is written and is_allo_meth is the method to be executed
- to implement the attribute state machine. The method passed here as argument
- as to be class method and not object method. Which argument you have to use
- depends on the type of the attribute (A WRITE attribute does not need a
- read method). Note, that depending on the number of argument you pass to this
- method, you may have to use Python keyword argument. The necessary methods
- required by the Tango Python device server core will be created automatically
- as a forward to the methods given as arguments.
-
-Mixing Tango classes (Python and C++) in a Python Tango device server
----------------------------------------------------------------------
-
-Within the same python interpreter, it is possible to mix several Tango classes.
-Here is an example of the main function of a device server with two Tango classes
-called IRMiror and PLC::
-
- import PyTango
- import sys
-
- if __name__ == '__main__':
- util = PyTango.Util(sys.argv)
- util.add_class(PLCClass, PLC, 'PLC')
- util.add_class(IRMirrorClass, IRMirror, 'IRMirror')
-
- U = PyTango.Util.instance()
- U.server_init()
- U.server_run()
-
-:Line 6: The Tango class PLC is registered in the device server
-:Line 7: The Tango class IRMirror is registered in the device server
-
-It is also possible to add C++ Tango class in a Python device server as soon as:
- 1. The Tango class is in a shared library
- 2. It exist a C function to create the Tango class
-
-For a Tango class called MyTgClass, the shared library has to be called
-MyTgClass.so and has to be in a directory listed in the LD_LIBRARY_PATH
-environment variable. The C function creating the Tango class has to be called
-_create_MyTgClass_class() and has to take one parameter of type "char \*" which
-is the Tango class name. Here is an example of the main function of the same
-device server than before but with one C++ Tango class called SerialLine::
-
- import PyTango
- import sys
-
- if __name__ == '__main__':
- py = PyTango.Util(sys.argv)
- util.add_class('SerialLine', 'SerialLine', language="c++")
- util.add_class(PLCClass, PLC, 'PLC')
- util.add_class(IRMirrorClass, IRMirror, 'IRMirror')
-
- U = PyTango.Util.instance()
- U.server_init()
- U.server_run()
-
-:Line 6: The C++ class is registered in the device server
-:Line 7 and 8: The two Python classes are registered in the device server
-
-Server API
-----------
-
-.. toctree::
- :maxdepth: 2
-
- server
- device
- device_class
- logging
- attribute
- util
diff --git a/doc/itango/highlights.rst b/doc/itango/highlights.rst
index 02575e8..cfdd257 100644
--- a/doc/itango/highlights.rst
+++ b/doc/itango/highlights.rst
@@ -40,7 +40,7 @@ These include:
ITango [4]: Att<tab>
Attribute AttributeError AttributeProxy
- - The tango :class:`PyTango.Database` object to which the itango session is
+ - The Tango :class:`Database` object to which the itango session is
currently connected
.. sourcecode:: itango
@@ -153,7 +153,7 @@ and attributes if the device is currently running)
Result [3]: 56.433
Tango classes as :class:`DeviceProxy`
----------------------------------------------
+------------------------------------------------
ITango exports all known tango classes as python alias to :class:`DeviceProxy`.
This way, if you want to create a device of class which you already know
diff --git a/doc/quicktour.rst b/doc/quicktour.rst
index 1ed0cbc..fe31e19 100644
--- a/doc/quicktour.rst
+++ b/doc/quicktour.rst
@@ -1,502 +1,249 @@
-.. _quick-tour:
+.. _pytango-quick-tour:
Quick tour
-============
+==========
This quick tour will guide you through the first steps on using PyTango.
-This is the new quick tour guide based on the :ref:`itango` console.
-You can still find the old version of this tour based on a simple python
-console :ref:`here <quick-tour-old>`.
-Quick tour on the client side
------------------------------
+Fundamental TANGO concepts
+--------------------------
-Check PyTango version
-~~~~~~~~~~~~~~~~~~~~~
+Before you begin there are some fundamental TANGO concepts you should be aware of.
-Start an IPython_ tango console with::
+Tango consists basically of a set of **devices** running somewhere on the network.
- $ itango
+A device is identified by a unique case insensitive name in the format
+*<domain>/<family>/<member>*. Examples: `LAB-01/PowerSupply/01`,
+`ID21/OpticsHutch/energy`.
-and type:
+Each device has a series of *attributes*, *properties* and *commands*.
- .. sourcecode:: itango
+An attribute is identified by a name in a device. It has a value that can
+be read. Some attributes can also be changed (read-write attributes).
- ITango [1]: PyTango.__version__
- Result [1]: '8.0.0'
+A property is identified by a name in a device. Usually, devices properties are
+used to provide a way to configure a device.
- ITango [2]: PyTango.__version_long__
- Result [2]: '8.0.0dev0'
+A command is also identified by a name. A command may or not receive a parameter
+and may or not return a value when it is executed.
- ITango [3]: PyTango.__version_number__
- Result [3]: 800
+Any device has **at least** a *State* and *Status* attributes and *State*,
+*Status* and *Init* commands. Reading the *State* or *Status* attributes has
+the same effect as executing the *State* or *Status* commands.
- ITango [4]: PyTango.__version_description__
- Result [4]: 'This version implements the C++ Tango 8.0 API.'
+Each device as an associated *TANGO Class*. Most of the times the TANGO class
+has the same name as the object oriented programming class which implements it
+but that is not mandatory.
-or alternatively:
+TANGO devices *live* inside a operating system process called *TANGO Device Server*.
+This server acts as a container of devices. A device server can host multiple
+devices of multiple TANGO classes. Devices are, therefore, only accessible when
+the corresponding TANGO Device Server is running.
- .. sourcecode:: itango
+A special TANGO device server called the *TANGO Database Server* will act as
+a naming service between TANGO servers and clients. This server has a known
+address where it can be reached. The machines that run TANGO Device Servers
+and/or TANGO clients, should export an environment variable called
+:envvar:`TANGO_HOST` that points to the TANGO Database server address. Example:
+``TANGO_HOST=homer.lab.eu:10000``
- ITango [1]: PyTango.Release.version
- Result [1]: '8.0.0'
+Minimum setup
+-------------
- ITango [2]: PyTango.Release.version_long
- Result [2]: '8.0.0dev0'
+This chapter assumes you have already installed PyTango.
- ITango [3]: PyTango.Release.version_number
- Result [3]: 800
+To explore PyTango you should have a running Tango system. If you are working in
+a facility/institute that uses Tango, this has probably already been prepared
+for you. You need to ask your facility/institute tango contact for the
+:envvar:`TANGO_HOST` variable where Tango system is running.
- ITango [4]: PyTango.Release.version_description
- Result [4]: 'This version implements the C++ Tango 8.0 API.'
+If you are working in an isolate machine you first need to make sure the Tango
+system is installed and running (`Tango howtos <http://www.tango-controls.org/howtos>`_).
-.. tip::
+Most examples here connect to a device called *sys/tg_test/1* that runs in a
+TANGO server called *TangoTest* with the instance name *test*.
+This server comes with the TANGO installation. The TANGO installation
+also registers the *test* instance. All you have to do is start the TangoTest
+server on a console::
- When typing, try pressing <tab>. Since ITango has autocomplete embedded you
- should get a list of possible completions. Example::
-
- PyTango.Release.<tab>
-
- Should get a list of all members of :class:`PyTango.Release` class.
+ $ TangoTest test
+ Ready to accept request
-Check Tango C++ version
-~~~~~~~~~~~~~~~~~~~~~~~
+.. note::
+ if you receive a message saying that the server is already running,
+ it just means that somebody has already started the test server so you don't
+ need to do anything.
+
+Client
+------
+
+Finally you can get your hands dirty. The first thing to do is start a python
+console and import the :mod:`PyTango` module. The following example shows
+how to create a proxy to an existing TANGO device, how to read and write
+attributes and execute commands from a python console::
+
+ >>> import PyTango
+
+ >>> # create a device object
+ >>> test_device = PyTango.DeviceProxy("sys/tg_test/1")
+
+ >>> # every device has a state and status which can be checked with:
+ >>> print(test_device.state())
+ RUNNING
+
+ >>> print(test_device.status())
+ The device is in RUNNING state.
+
+ >>> # this device has an attribute called "long_scalar". Let's see which value it has...
+ >>> data = test_device.read_attribute("long_scalar")
+
+ >>> # ...PyTango provides a shortcut to do the same:
+ >>> data = test_device["long_scalar"]
+
+ >>> # the result of reading an attribute is a DeviceAttribute python object.
+ >>> # It has a member called "value" which contains the value of the attribute
+ >>> data.value
+ 136
-From a client (This is only possible since PyTango 7.0.0)
+ >>> # Check the complete DeviceAttribute members:
+ >>> print(data)
+ DeviceAttribute[
+ data_format = SCALAR
+ dim_x = 1
+ dim_y = 0
+ has_failed = False
+ is_empty = False
+ name = 'long_scalar'
+ nb_read = 1
+ nb_written = 1
+ quality = ATTR_VALID
+ r_dimension = AttributeDimension(dim_x = 1, dim_y = 0)
+ time = TimeVal(tv_nsec = 0, tv_sec = 1399450183, tv_usec = 323990)
+ type = DevLong
+ value = 136
+ w_dim_x = 1
+ w_dim_y = 0
+ w_dimension = AttributeDimension(dim_x = 1, dim_y = 0)
+ w_value = 0]
- .. sourcecode:: itango
+ >>> # PyTango provides a handy pythonic shortcut to read the attribute value:
+ >>> test_device.long_scalar
+ 136
- ITango [1]: import PyTango.constants
+ >>> # Setting an attribute value is equally easy:
+ >>> test_device.write_attribute("long_scalar", 8776)
- ITango [2]: PyTango.constants.TgLibVers
- Result [2]: '8.0.0'
+ >>> # ... and a handy shortcut to do the same exists as well:
+ >>> test_device.long_scalar = 8776
-From a server you can alternatively do::
-
- u = PyTango.Util.instance()
- tg_cpp_lib_ver = u.get_tango_lib_release()
-
+ >>> # TangoTest has a command called "DevDouble" which receives a number
+ >>> # as parameter and returns the same number as a result. Let's
+ >>> # execute this command:
+ >>> test_device.command_inout("DevDouble", 45.67)
+ 45.67
-Test the connection to the Device and get it's current state
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ >>> # PyTango provides a handy shortcut: it exports commands as device methods:
+ >>> test_device.DevDouble(45.67)
+ 45.67
-One of the most basic examples is to get a reference to a device and
-determine if it is running or not.
+ >>> # Introspection: check the list of attributes:
+ >>> test_device.get_attribute_list()
+ ['ampli', 'boolean_scalar', 'double_scalar', '...', 'State', 'Status']
+
+ >>>
- .. sourcecode:: itango
-
- ITango [1]: # What is a DeviceProxy, really?
- ITango [1]: DeviceProxy?
- DeviceProxy is the high level Tango object which provides the client with
- an easy-to-use interface to TANGO devices. DeviceProxy provides interfaces
- to all TANGO Device interfaces.The DeviceProxy manages timeouts, stateless
- connections and reconnection if the device server is restarted. To create
- a DeviceProxy, a Tango Device name must be set in the object constructor.
+This is just the tip of the iceberg. Check the :class:`~PyTango.DeviceProxy` for
+the complete API.
- Example :
- dev = PyTango.DeviceProxy("sys/tg_test/1")
-
- ITango [2]: tangotest = DeviceProxy("sys/tg_test/1")
+PyTango comes with an integrated IPython_ based console called :ref:`itango`.
+It provides helpers to simplify console usage. You can use this console instead
+of the traditional python console. Be aware, though, that many of the *tricks*
+you can do in an :ref:`itango` console cannot be done in a python program.
- ITango [3]: # ping it
- ITango [4]: tangotest.ping()
- Result [4]: 110
+Server
+------
- ITango [5]: # Lets test the state
- ITango [6]: tangotest.state()
- Result [6]: PyTango._PyTango.DevState.RUNNING
+Since PyTango 8.1 it has become much easier to program a Tango device server.
+PyTango provides some helpers that allow developers to simplify the programming
+of a Tango device server.
- ITango [7]: # And now the status
- ITango [8]: tangotest.status()
- Result [8]: 'The device is in RUNNING state.'
+Before creating a server you need to decide:
-.. note::
+1. The name of the device server (example: `PowerSupplyDS`). This will be
+ the mandatory name of your python file.
+2. The Tango Class name of your device (example: `PowerSupply`). In our
+ example we will use the same name as the python class name.
+3. the list of attributes of the device, their data type, access (read-only vs
+ read-write), data_format (scalar, 1D, 2D)
+4. the list of commands, their parameters and their result
- Did you notice that you didn't write `PyTango.DeviceProxy` but instead just
- `DeviceProxy` ? This is because :ref:`itango` automatically exports the
- :class:`~PyTango.DeviceProxy`, :class:`~PyTango.AttributeProxy`,
- :class:`~PyTango.Database` and :class:`~PyTango.Group` classes to the
- namespace. If you are writting code outside :ref:`itango` you **MUST**
- use the `PyTango` module prefix.
+In our example we will write a fake power supply device server. The server
+will be called `PowerSupplyDS`. There will be a class called `PowerSupply`
+which will have attributes:
-.. tip::
+* *voltage* (scalar, read-only, numeric)
+* *current* (scalar, read_write, numeric, expert mode)
+* *noise* (2D, read-only, numeric)
- When typing the device name in the :class:`~PyTango.DeviceProxy` creation
- line, try pressing the <tab> key. You should get a list of devices::
-
- tangotest = DeviceProxy("sys<tab>
-
- Better yet (and since the Tango Class of 'sys/tg_test/1' is 'TangoTest'),
- try doing::
-
- tangotest = TangoTest("<tab>
+commands:
- Now the list of devices should be reduced to the ones that belong to the
- 'TangoTest' class. Note that TangoTest only works in ITango. If you are
- writting code outside :ref:`itango` you **MUST** use
- :class:`PyTango.DeviceProxy` instead.
-
-Execute commands with scalar arguments on a Device
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-As you can see in the following example, when scalar types are used, PyTango
-automatically manages the data types, and writing scripts is quite easy.
+* *TurnOn* (argument: None, result: None)
+* *TurnOff* (argument: None, result: None)
+* *Ramp* (param: scalar, numeric; result: bool)
- .. sourcecode:: itango
-
- ITango [1]: tangotest = TangoTest("sys/tg_test/1")
+properties:
- ITango [2]: # classical way
- ITango [2]: r = tangotest.command_inout("DevString", "Hello, world!")
+* *host* (string representing the host name of the actual power supply)
+* *port* (port number in the host with default value = 9788)
- ITango [3]: print "Result of execution of DevString command =", r
- Result of execution of DevString command = Hello, world!
+Here is the code for the :file:`PowerSupplyDS.py`
- ITango [4]: # 'pythonic' way
- ITango [5]: tangotest.DevString("Hello, world!")
- Result [5]: 'Hello, world!'
-
- ITango [6]: # type is automatically managed by PyTango
- ITango [7]: tangotest.DevULong(12456)
- Result [7]: 12456
+.. literalinclude:: _static/PowerSupplyDS.py
+ :linenos:
-Execute commands with more complex types
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The server API :ref:`pytango-hlapi`.
-In this case you have to use put your arguments data in the correct python
-structures.
+Before running this brand new server we need to register it in the Tango system.
+You can do it with Jive (`Jive->Edit->Create server`):
- .. sourcecode:: itango
-
- ITango [1]: tangotest = TangoTest("sys/tg_test/1")
-
- ITango [2]: argin = [1, 2, 3], ["Hello", "World"]
-
- ITango [3]: tango_test.DevVarLongArray(argin)
- Result [3]: [array([1, 2, 3]), ['Hello', 'World']]
-
-.. note::
- notice that the command returns a list of two elements. The first element is
- a :class:`numpy.ndarray` (assuming PyTango is compiled with numpy_ support).
- This is because PyTango does a best effort to convert all numeric array types
- to numpy_ arrays.
-
-Reading and writing attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. image:: _static/jive_powersupply.png
-Basic read/write attribute operations.
+... or in a python script::
- .. sourcecode:: itango
-
- ITango [1]: # Read a scalar attribute
- ITango [2]: print tangotest.read_attribute("long_scalar")
- DeviceAttribute[
- data_format = PyTango._PyTango.AttrDataFormat.SCALAR
- dim_x = 1
- dim_y = 0
- has_failed = False
- is_empty = False
- name = 'long_scalar'
- nb_read = 1
- nb_written = 1
- quality = PyTango._PyTango.AttrQuality.ATTR_VALID
- r_dimension = AttributeDimension(dim_x = 1, dim_y = 0)
- time = TimeVal(tv_nsec = 0, tv_sec = 1281084943, tv_usec = 461730)
- type = PyTango._PyTango.CmdArgType.DevLong
- value = 239
- w_dim_x = 1
- w_dim_y = 0
- w_dimension = AttributeDimension(dim_x = 1, dim_y = 0)
- w_value = 0]
-
- ITango [3]: # Read a spectrum attribute
- ITango [4]: print tangotest.read_attribute("double_spectrum")
- DeviceAttribute[
- data_format = PyTango._PyTango.AttrDataFormat.SPECTRUM
- dim_x = 20
- dim_y = 0
- has_failed = False
- is_empty = False
- name = 'double_spectrum'
- nb_read = 20
- nb_written = 20
- quality = PyTango._PyTango.AttrQuality.ATTR_VALID
- r_dimension = AttributeDimension(dim_x = 20, dim_y = 0)
- time = TimeVal(tv_nsec = 0, tv_sec = 1281085195, tv_usec = 244760)
- type = PyTango._PyTango.CmdArgType.DevDouble
- value = array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.,
- 11., 12., 13., 14., 15., 16., 17., 18., 19.])
- w_dim_x = 20
- w_dim_y = 0
- w_dimension = AttributeDimension(dim_x = 20, dim_y = 0)
- w_value = array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.,
- 11., 12., 13., 14., 15., 16., 17., 18., 19.])]
-
- ITango [5]: # Write a scalar attribute
- ITango [6]: scalar_value = 18
- ITango [7]: tangotest.write_attribute("long_scalar", scalar_value)
-
- ITango [8]: # Write a spectrum attribute
- ITango [9]: spectrum_value = numpy.random.rand(100)*10
- ITango [10]: tangotest.write_attribute("double_spectrum", spectrum_value)
-
-
- ITango [11]: # Write an image attribute
- ITango [12]: image_value = numpy.random.randint(0,10,size=(10,10))
- ITango [13]: tangotest.write_attribute("long_image", image_value)
-
-.. tip::
-
- If you are only interested in the attribute's read value you can do insted:
-
- .. sourcecode:: itango
-
- ITango [1]: tangotest.long_scalar
- Result [1]: 239
+ >>> import PyTango
- The same is valid for writting a new value to an attribute:
+ >>> dev_info = PyTango.DbDevInfo()
+ >>> dev_info.server = "PowerSupplyDS/test"
+ >>> dev_info._class = "PowerSupply"
+ >>> dev_info.name = "test/power_supply/1"
- .. sourcecode:: itango
-
- ITango [1]: tangotest.long_scalar = 18
-
-.. note::
+ >>> db = PyTango.Database()
+ >>> db.add_device(dev_info)
- If PyTango is compiled with numpy support the values got when reading
- a spectrum or an image will be numpy arrays. This results in a faster and
- more memory efficient PyTango. You can also use numpy to specify the values when
- writing attributes, especially if you know the exact attribute type.::
+After, you can run the server on a console with::
- # Creating an unitialized double spectrum of 1000 elements
- spectrum_value = PyTango.numpy_spectrum(PyTango.DevDouble, 1000)
+ $ python PowerSupplyDS.py test
+ Ready to accept request
- # Creating an spectrum with a range
- # Note that I do NOT use PyTango.DevLong here, BUT PyTango.NumpyType.DevLong
- # numpy functions do not understand normal python types, so there's a
- # translation available in PyTango.NumpyType
- spectrum_value = numpy.arange(5, 1000, 2, PyTango.NumpyType.DevLong)
+Now you can access it from a python console::
- # Creating a 2x2 long image from an existing one
- image_value = PyTango.numpy_image(PyTango.DevLong, [[1,2],[3,4]])
+ >>> import PyTango
-Registering devices
-~~~~~~~~~~~~~~~~~~~
+ >>> power_supply = PyTango.DeviceProxy("test/power/supply/1")
+ >>> power_supply.state()
+ STANDBY
-Defining devices in the Tango DataBase:
-
- .. sourcecode:: itango
-
- ITango [1]: # The 3 devices name we want to create
- ITango [2]: # Note: these 3 devices will be served by the same DServer
- ITango [3]: new_device_name1="px1/tdl/mouse1"
- ITango [4]: new_device_name2="px1/tdl/mouse2"
- ITango [5]: new_device_name3="px1/tdl/mouse3"
-
- ITango [6]: # Define the Tango Class served by this DServer
- ITango [7]: new_device_info_mouse = PyTango.DbDevInfo()
- ITango [8]: new_device_info_mouse._class = "Mouse"
- ITango [9]: new_device_info_mouse.server = "ds_Mouse/server_mouse"
-
- ITango [10]: # add the first device
- ITango [11]: new_device_info_mouse.name = new_device_name1
- ITango [12]: db.add_device(new_device_info_mouse)
-
- ITango [13]: # add the next device
- ITango [14]: new_device_info_mouse.name = new_device_name2
- ITango [15]: db.add_device(new_device_info_mouse)
-
- ITango [16]: # add the third device
- ITango [17]: new_device_info_mouse.name = new_device_name3
- ITango [18]: db.add_device(new_device_info_mouse)
-
-Setting up Device properties
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A more complex example using python subtilities.
-The following python script example (containing some functions and instructions
-manipulating a Galil motor axis device server) gives an idea of how the Tango
-API should be accessed from Python.
-
- .. sourcecode:: itango
+ >>> power_supply.current = 2.3
- ITango [1]: # connecting to the motor axis device
- ITango [2]: axis1 = DeviceProxy ("microxas/motorisation/galilbox")
-
- ITango [3]: # Getting Device Properties
- ITango [4]: property_names = ["AxisBoxAttachement",
- ....: "AxisEncoderType",
- ....: "AxisNumber",
- ....: "CurrentAcceleration",
- ....: "CurrentAccuracy",
- ....: "CurrentBacklash",
- ....: "CurrentDeceleration",
- ....: "CurrentDirection",
- ....: "CurrentMotionAccuracy",
- ....: "CurrentOvershoot",
- ....: "CurrentRetry",
- ....: "CurrentScale",
- ....: "CurrentSpeed",
- ....: "CurrentVelocity",
- ....: "EncoderMotorRatio",
- ....: "logging_level",
- ....: "logging_target",
- ....: "UserEncoderRatio",
- ....: "UserOffset"]
-
- ITango [5]: axis_properties = axis1.get_property(property_names)
- ITango [6]: for prop in axis_properties.keys():
- ....: print "%s: %s" % (prop, axis_properties[prop][0])
-
- ITango [7]: # Changing Properties
- ITango [8]: axis_properties["AxisBoxAttachement"] = ["microxas/motorisation/galilbox"]
- ITango [9]: axis_properties["AxisEncoderType"] = ["1"]
- ITango [10]: axis_properties["AxisNumber"] = ["6"]
- ITango [11]: axis1.put_property(axis_properties)
-
- ITango [12]: # Reading attributes
- ITango [13]: att_list = axis.get_attribute_list()
- ITango [14]: for att in att_list:
- ....: att_val = axis.read_attribute(att)
- ....: print "%s: %s" % (att.name, att_val.value)
-
- ITango [15]: # Changing some attribute values
- ITango [16]: axis1.write_attribute("AxisBackslash", 0.5)
- ITango [17]: axis1.write_attribute("AxisDirection", 1.0)
- ITango [18]: axis1.write_attribute("AxisVelocity", 1000.0)
- ITango [19]: axis1.write_attribute("AxisOvershoot", 500.0)
-
- ITango [20]: # Testing some device commands
- ITango [21]: pos1=axis1.read_attribute("AxisCurrentPosition")
- ITango [22]: axis1.command_inout("AxisBackward")
- ITango [23]: while pos1.value > 1000.0:
- ....: pos1 = axis1.read_attribute("AxisCurrentPosition")
- ....: print "position axis 1 = ", pos1.value
-
- ITango [24]: axis1.command_inout("AxisStop")
-
-Quick tour on the server side
------------------------------
-
-To write a tango device server in python, you must first import the
-:mod:`PyTango` module in your code.
-
-Below is the python code for a Tango device server with two commands and two
-attributes. The commands are:
-
-1. IOLOng which receives a Tango Long and return it multiply by 2. This command
- is allowed only if the device is in the ON state.
-
-2. IOStringArray which receives an array of Tango strings and which returns it
- but in the reverse order. This command is only allowed if the device is in
- the ON state.
-
-The attributes are:
-
-1. Long_attr wich is a Tango long attribute, Scalar and Read only with a
- minimum alarm set to 1000 and a maximum alarm set to 1500
-
-2. Short_attr_rw which is a Tango short attribute, Scalar and Read/Write
-
-The following code is the complete device server code::
-
- import PyTango
-
- class PyDsExp(PyTango.Device_4Impl):
-
- def __init__(self,cl,name):
- PyTango.Device_4Impl.__init__(self,cl,name)
- self.debug_stream('In PyDsExp __init__')
- PyDsExp.init_device(self)
-
- def init_device(self):
- self.debug_stream('In Python init_device method')
- self.set_state(PyTango.DevState.ON)
- self.attr_short_rw = 66
- self.attr_long = 1246
-
- def delete_device(self):
- self.debug_stream('[delete_device] for device %s ' % self.get_name())
-
- #------------------------------------------------------------------
- # COMMANDS
- #------------------------------------------------------------------
-
- def is_IOLong_allowed(self):
- return self.get_state() == PyTango.DevState.ON
-
- def IOLong(self, in_data):
- self.debug_stream('[IOLong::execute] received number %s' % str(in_data))
- in_data = in_data * 2;
- self.debug_stream('[IOLong::execute] return number %s' % str(in_data))
- return in_data;
-
- def is_IOStringArray_allowed(self):
- return self.get_state() == PyTango.DevState.ON
-
- def IOStringArray(self, in_data):
- l = range(len(in_data)-1, -1, -1);
- out_index=0
- out_data=[]
- for i in l:
- self.debug_stream('[IOStringArray::execute] received String' % in_data[out_index])
- out_data.append(in_data[i])
- self.debug_stream('[IOStringArray::execute] return String %s' %out_data[out_index])
- out_index += 1
- self.y = out_data
- return out_data
-
- #------------------------------------------------------------------
- # ATTRIBUTES
- #------------------------------------------------------------------
-
- def read_attr_hardware(self, data):
- self.debug_stream('In read_attr_hardware')
+ >>> power_supply.current
+ 2.3
- def read_Long_attr(self, the_att):
- self.debug_stream('[PyDsExp::read_attr] attribute name Long_attr')
- the_att.set_value(self.attr_long)
-
- def read_Short_attr_rw(self, the_att):
- self.debug_stream('[PyDsExp::read_attr] attribute name Short_attr_rw')
- the_att.set_value(self.attr_short_rw)
-
- def write_Short_attr_rw(self, the_att):
- self.debug_stream('In write_Short_attr_rw for attribute %s' % the_att.get_name())
- data = the_att.get_write_value()
- self.attr_short_rw = data[0]
-
-
- class PyDsExpClass(PyTango.DeviceClass):
-
- def __init__(self, name):
- PyTango.DeviceClass.__init__(self, name)
- self.set_type("PyDsExp")
-
- cmd_list = { 'IOLong' : [ [ PyTango.ArgType.DevLong, "Number" ],
- [ PyTango.ArgType.DevLong, "Number * 2" ] ],
- 'IOStringArray' : [ [ PyTango.ArgType.DevVarStringArray, "Array of string" ],
- [ PyTango.ArgType.DevVarStringArray, "This reversed array"] ],
- }
-
- attr_list = { 'Long_attr' : [ [ PyTango.ArgType.DevLong ,
- PyTango.AttrDataFormat.SCALAR ,
- PyTango.AttrWriteType.READ],
- { 'min alarm' : 1000, 'max alarm' : 1500 } ],
-
- 'Short_attr_rw' : [ [ PyTango.ArgType.DevShort,
- PyTango.AttrDataFormat.SCALAR,
- PyTango.AttrWriteType.READ_WRITE ] ]
- }
+ >>> power_supply.PowerOn()
+ >>> power_supply.Ramp(2.1)
+ True
-
- def main():
- PyTango.server_run({"PyDsExp" : (PyDsExpClass, PyDsExp)})
-
- if __name__ == '__main__':
- main()
-
-.. toctree::
- :hidden:
+ >>> power_supply.state()
+ ON
- Quick tour (original) <quicktour_old>
+Next steps: Check out the :ref:`pytango-api`.
diff --git a/doc/revision.rst b/doc/revision.rst
index d20f47c..f01de14 100644
--- a/doc/revision.rst
+++ b/doc/revision.rst
@@ -1,15 +1,17 @@
-.. _revision:
+.. _pytango-history-changes:
-Revision
---------
+==================
+History of changes
+==================
:Contributers: T\. Coutinho
:Last Update: |today|
-.. _history-modifications:
+.. _pytango-revisions:
-History of modifications:
+Document revisions
+-------------------
+----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
| Date | Revision | Description | Author |
@@ -78,7 +80,7 @@ History of modifications:
| __/02/14 | `8.19 <http://www.tango-controls.org/static/PyTango/v812/doc/html/index.html>`_ | Update to PyTango 8.1.2 | T\. Coutinho |
+----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
-.. _version-history:
+.. _pytango-version-history:
Version history
---------------
diff --git a/doc/server/attribute.rst b/doc/server_api/attribute.rst
similarity index 100%
rename from doc/server/attribute.rst
rename to doc/server_api/attribute.rst
diff --git a/doc/server/device.rst b/doc/server_api/device.rst
similarity index 100%
rename from doc/server/device.rst
rename to doc/server_api/device.rst
diff --git a/doc/server/device_class.rst b/doc/server_api/device_class.rst
similarity index 100%
rename from doc/server/device_class.rst
rename to doc/server_api/device_class.rst
diff --git a/doc/server_api/index.rst b/doc/server_api/index.rst
new file mode 100644
index 0000000..6bd2ec5
--- /dev/null
+++ b/doc/server_api/index.rst
@@ -0,0 +1,67 @@
+.. currentmodule:: PyTango
+
+.. highlight:: python
+ :linenothreshold: 3
+
+
+Mixing Tango classes (Python and C++) in a Python Tango device server
+---------------------------------------------------------------------
+
+Within the same python interpreter, it is possible to mix several Tango classes.
+Here is an example of the main function of a device server with two Tango classes
+called IRMiror and PLC::
+
+ import PyTango
+ import sys
+
+ if __name__ == '__main__':
+ util = PyTango.Util(sys.argv)
+ util.add_class(PLCClass, PLC, 'PLC')
+ util.add_class(IRMirrorClass, IRMirror, 'IRMirror')
+
+ U = PyTango.Util.instance()
+ U.server_init()
+ U.server_run()
+
+:Line 6: The Tango class PLC is registered in the device server
+:Line 7: The Tango class IRMirror is registered in the device server
+
+It is also possible to add C++ Tango class in a Python device server as soon as:
+ 1. The Tango class is in a shared library
+ 2. It exist a C function to create the Tango class
+
+For a Tango class called MyTgClass, the shared library has to be called
+MyTgClass.so and has to be in a directory listed in the LD_LIBRARY_PATH
+environment variable. The C function creating the Tango class has to be called
+_create_MyTgClass_class() and has to take one parameter of type "char \*" which
+is the Tango class name. Here is an example of the main function of the same
+device server than before but with one C++ Tango class called SerialLine::
+
+ import PyTango
+ import sys
+
+ if __name__ == '__main__':
+ py = PyTango.Util(sys.argv)
+ util.add_class('SerialLine', 'SerialLine', language="c++")
+ util.add_class(PLCClass, PLC, 'PLC')
+ util.add_class(IRMirrorClass, IRMirror, 'IRMirror')
+
+ U = PyTango.Util.instance()
+ U.server_init()
+ U.server_run()
+
+:Line 6: The C++ class is registered in the device server
+:Line 7 and 8: The two Python classes are registered in the device server
+
+Server API
+----------
+
+.. toctree::
+ :maxdepth: 2
+
+ server
+ device
+ device_class
+ logging
+ attribute
+ util
diff --git a/doc/server/logging.rst b/doc/server_api/logging.rst
similarity index 100%
rename from doc/server/logging.rst
rename to doc/server_api/logging.rst
diff --git a/doc/server/server.rst b/doc/server_api/server.rst
similarity index 98%
rename from doc/server/server.rst
rename to doc/server_api/server.rst
index 86cfd81..530ec06 100644
--- a/doc/server/server.rst
+++ b/doc/server_api/server.rst
@@ -14,10 +14,11 @@ Here is a simple example on how to write a *Clock* device server using the
high level API::
import time
- from PyTango.server import server_run
+ from PyTango.server import run
from PyTango.server import Device, DeviceMeta
from PyTango.server import attribute, command
+
class Clock(Device):
__metaclass__ = DeviceMeta
@@ -32,7 +33,8 @@ high level API::
if __name__ == "__main__":
- server_run((Clock,))
+ run((Clock,))
+
Here is a more complete example on how to write a *PowerSupply* device server
using the high level API. The example contains:
diff --git a/doc/server/util.rst b/doc/server_api/util.rst
similarity index 100%
rename from doc/server/util.rst
rename to doc/server_api/util.rst
diff --git a/doc/start.rst b/doc/start.rst
index 4408937..48d6df9 100644
--- a/doc/start.rst
+++ b/doc/start.rst
@@ -6,8 +6,11 @@
Getting started
===============
-Quick installation: Linux
--------------------------
+Installing
+----------
+
+Linux
+~~~~~
PyTango is available on linux as an official debian/ubuntu package::
@@ -23,8 +26,8 @@ RPM packages are also available for RHEL & CentOS:
* `RHEL 6/CentOS 6 32bits <ftp://ftp.maxlab.lu.se/pub/maxlab/packages/el6/i386/repoview/index.html>`_
* `RHEL 6/CentOS 6 64bits <ftp://ftp.maxlab.lu.se/pub/maxlab/packages/el6/x86_64/repoview/index.html>`_
-From PyPi
-~~~~~~~~~
+PyPi
+~~~~
You can also install the latest version from `PyPi`_.
@@ -43,8 +46,8 @@ or easy_install::
$ easy_install -U PyTango
-Quick installation: Windows
----------------------------
+Windows
+~~~~~~~
First, make sure `Python`_ and `numpy`_ are installed.
@@ -55,9 +58,8 @@ Windows XP/Vista/7/8. The complete list of binaries can be downloaded from
Select the proper windows package, download it and finally execute the
installion wizard.
-
-Compiling & installing
-----------------------
+Compiling
+---------
Linux
~~~~~
@@ -95,8 +97,8 @@ Since it is rarely needed and the instructions are so complicated, I have
choosen to place the how-to in a separate text file. You can find it in the
source package under :file:`doc/windows_notes.txt`.
-Testing your installation
--------------------------
+Testing
+-------
If you have IPython_ installed, the best way to test your PyTango installation
is by starting the new PyTango CLI called :ref:`itango` by typing on the command
@@ -121,3 +123,4 @@ python console and type:
>>> PyTango.Release.version
'8.0.2'
+Next steps: Check out the :ref:`pytango-quick-tour`.
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/pytango.git
More information about the debian-science-commits
mailing list