File: index.rst

package info (click to toggle)
itango 0.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,984 kB
  • sloc: python: 1,476; makefile: 14
file content (716 lines) | stat: -rw-r--r-- 26,305 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
:tocdepth: 3

.. highlight:: python
   :linenothreshold: 4

======
ITango
======

ITango_ is a PyTango CLI based on IPython_. It is designed to be used as an
IPython profile.

It is available since PyTango 7.1.2 and has been moved to a separate
project since PyTango 9.2.0.

You can start ITango_ by typing on the command line:

.. sourcecode:: console

    $ itango

or the equivalent:

.. sourcecode:: console

    $ ipython --profile=tango

and you should get something like this:

.. image:: _images/itango00.png
    :align: center
    :width: 80%

.. _itango-features:

Features
--------

ITango_ works like a normal python console, but it gives you in addition a nice
set of features from IPython_ like:

    - proper (bash-like) command completion
    - automatic expansion of python variables, functions, types
    - command history (with up/down arrow keys, %hist command)
    - help system ( object? syntax, help(object))
    - persistently store your favorite variables
    - color modes

For a complete list checkout the `IPython web page <http://ipython.org/>`_.

Plus an additional set of Tango_ specific features:

    - automatic import of Tango objects to the console namespace (`tango`
      module, :class:`~tango.DeviceProxy` (=Device),
      :class:`~tango.Database`, :class:`~tango.Group`
      and :class:`~tango.AttributeProxy` (=Attribute))
    - device name completion
    - attribute name completion
    - automatic tango object member completion
    - list tango devices, classes, servers
    - customized tango error message
    - tango error introspection
    - switch database
    - refresh database
    - list tango devices, classes
    - store favorite tango objects
    - store favorite tango devices
    - tango color modes

Check the :ref:`itango-highlights` to see how to put these feature to good use
:-)


.. currentmodule:: tango

.. _itango-highlights:

Highlights
----------

Tab completion
~~~~~~~~~~~~~~

ITango_ exports many tango specific objects to the console namespace.
These include:

    - the tango module itself

      .. sourcecode:: itango

            ITango [1]: tango
            Result [1]: <module 'tango' from ...>

    - The :class:`DeviceProxy` (=Device), :class:`AttributeProxy` (=Attribute),
      :class:`Database` and :class:`Group` classes

      .. sourcecode:: itango

            ITango [1]: De<tab>
            DeprecationWarning            Device       DeviceProxy

            ITango [2]: Device
            Result [2]: <class 'tango._tango.DeviceProxy'>

            ITango [3]: Device("sys/tg_test/1")
            Result [3]: DeviceProxy(sys/tg_test/1)

            ITango [4]: Datab<tab>

            ITango [4]: Database

            ITango [4]: Att<tab>
            Attribute       AttributeError  AttributeProxy

    - The Tango :class:`Database` object to which the itango session is
      currently connected

      .. sourcecode:: itango

            ITango [1]: db
            Result [1]: Database(homer, 10000)

Device name completion
~~~~~~~~~~~~~~~~~~~~~~

ITango_ knows the complete list of device names (including alias) for the current
tango database. This means that when you try to create a new Device, by pressing
<tab> you can see a context sensitive list of devices.

.. sourcecode:: itango

    ITango [1]: test = Device("<tab>
    Display all 3654 possibilities? (y or n) n

    ITango [1]: test = Device("sys<tab>
    sys/access_control/1  sys/database/2        sys/tautest/1         sys/tg_test/1

    ITango [2]: test = Device("sys/tg_test/1")

Attribute name completion
~~~~~~~~~~~~~~~~~~~~~~~~~

ITango_ can inspect the list of attributes in case the device server for the device
where the attribute resides is running.

.. sourcecode:: itango

    ITango [1]: short_scalar = Attribute("sys<tab>
    sys/access_control/1/  sys/database/2/        sys/tautest/1/         sys/tg_test/1/

    ITango [1]: short_scalar = Attribute("sys/tg_test/1/<tab>
    sys/tg_test/1/State                sys/tg_test/1/no_value
    sys/tg_test/1/Status               sys/tg_test/1/short_image
    sys/tg_test/1/ampli                sys/tg_test/1/short_image_ro
    sys/tg_test/1/boolean_image        sys/tg_test/1/short_scalar
    sys/tg_test/1/boolean_image_ro     sys/tg_test/1/short_scalar_ro
    sys/tg_test/1/boolean_scalar       sys/tg_test/1/short_scalar_rww
    sys/tg_test/1/boolean_spectrum     sys/tg_test/1/short_scalar_w
    sys/tg_test/1/boolean_spectrum_ro  sys/tg_test/1/short_spectrum
    sys/tg_test/1/double_image         sys/tg_test/1/short_spectrum_ro
    sys/tg_test/1/double_image_ro      sys/tg_test/1/string_image
    sys/tg_test/1/double_scalar        sys/tg_test/1/string_image_ro
    ...

    ITango [1]: short_scalar = Attribute("sys/tg_test/1/short_scalar")

    ITango [29]: print test.read()
    DeviceAttribute[
    data_format = tango._tango.AttrDataFormat.SCALAR
      dim_x = 1
      dim_y = 0
    has_failed = False
    is_empty = False
       name = 'short_scalar'
    nb_read = 1
    nb_written = 1
    quality = tango._tango.AttrQuality.ATTR_VALID
    r_dimension = AttributeDimension(dim_x = 1, dim_y = 0)
       time = TimeVal(tv_nsec = 0, tv_sec = 1279723723, tv_usec = 905598)
       type = tango._tango.CmdArgType.DevShort
      value = 47
    w_dim_x = 1
    w_dim_y = 0
    w_dimension = AttributeDimension(dim_x = 1, dim_y = 0)
    w_value = 0]

Automatic tango object member completion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When you create a new tango object, (ex.: a device), itango is able to find out
dynamically which are the members of this device (including tango commands
and attributes if the device is currently running)

.. sourcecode:: itango

    ITango [1]: test = Device("sys/tg_test/1")

    ITango [2]: test.<tab>
    Display all 240 possibilities? (y or n)
    ...
    test.DevVoid                            test.get_access_control
    test.Init                               test.get_asynch_replies
    test.State                              test.get_attribute_config
    test.Status                             test.get_attribute_config_ex
    test.SwitchStates                       test.get_attribute_list
    ...

    ITango [2]: test.short_<tab>
    test.short_image        test.short_scalar       test.short_scalar_rww   test.short_spectrum
    test.short_image_ro     test.short_scalar_ro    test.short_scalar_w     test.short_spectrum_ro

    ITango [2]: test.short_scalar        # old style: test.read_attribute("short_scalar").value
    Result [2]: 252

    ITango [3]: test.Dev<tab>
    test.DevBoolean               test.DevUShort                test.DevVarShortArray
    test.DevDouble                test.DevVarCharArray          test.DevVarStringArray
    test.DevFloat                 test.DevVarDoubleArray        test.DevVarULongArray
    test.DevLong                  test.DevVarDoubleStringArray  test.DevVarUShortArray
    test.DevShort                 test.DevVarFloatArray         test.DevVoid
    test.DevString                test.DevVarLongArray
    test.DevULong                 test.DevVarLongStringArray

    ITango [3]: test.DevDouble(56.433)  # old style: test.command_inout("DevDouble").
    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
(say, Libera, for example) you can do:

.. sourcecode:: itango

    ITango [1]: lib01 = Libera("BO01/DI/BPM-01")

One great advantage is that the tango device name completion is sensitive to the
type of device you want to create. This means that if you are in the middle of
writing a device name and you press the <tab> key, only devices of the tango
class 'Libera' will show up as possible completions.

.. sourcecode:: itango

    ITango [1]: bpm1 = Libera("<tab>
    BO01/DI/BPM-01  BO01/DI/BPM-09  BO02/DI/BPM-06  BO03/DI/BPM-03  BO03/DI/BPM-11  BO04/DI/BPM-08
    BO01/DI/BPM-02  BO01/DI/BPM-10  BO02/DI/BPM-07  BO03/DI/BPM-04  BO04/DI/BPM-01  BO04/DI/BPM-09
    BO01/DI/BPM-03  BO01/DI/BPM-11  BO02/DI/BPM-08  BO03/DI/BPM-05  BO04/DI/BPM-02  BO04/DI/BPM-10
    BO01/DI/BPM-04  BO02/DI/BPM-01  BO02/DI/BPM-09  BO03/DI/BPM-06  BO04/DI/BPM-03  BO04/DI/BPM-11
    BO01/DI/BPM-05  BO02/DI/BPM-02  BO02/DI/BPM-10  BO03/DI/BPM-07  BO04/DI/BPM-04
    BO01/DI/BPM-06  BO02/DI/BPM-03  BO02/DI/BPM-11  BO03/DI/BPM-08  BO04/DI/BPM-05
    BO01/DI/BPM-07  BO02/DI/BPM-04  BO03/DI/BPM-01  BO03/DI/BPM-09  BO04/DI/BPM-06
    BO01/DI/BPM-08  BO02/DI/BPM-05  BO03/DI/BPM-02  BO03/DI/BPM-10  BO04/DI/BPM-07

    ITango [1]: bpm1 = Libera("BO01<tab>
    BO01/DI/BPM-01  BO01/DI/BPM-03  BO01/DI/BPM-05  BO01/DI/BPM-07  BO01/DI/BPM-09  BO01/DI/BPM-11
    BO01/DI/BPM-02  BO01/DI/BPM-04  BO01/DI/BPM-06  BO01/DI/BPM-08  BO01/DI/BPM-10

    ITango [1]: bpm1 = Libera("BO01/DI/BPM-01")

Customized device representation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When you use ipython >= 0.11 with a Qt console frontend:

.. sourcecode:: console

    $ itango qtconsole

typing a variable containing a tango device object followend by :kbd:`Enter`
will present you with a customized representation of the object instead of the
usual :func:`repr` :

    .. image:: _images/itango06.png

You can customize the icon that itango displays for a specific device.
The first thing to do is to copy the image file into
`itango.resource` installation directory (if you don't have
permissions to do so, copy the image into a directory of your choosing
and make sure it is accessible from itango).

If you want to use the image for all devices of a certain tango class, just
add a new tango class property called *__icon*. You can do it with jive or, of
course, with itango itself::

    db.put_class_property("Libera", dict(__icon="libera.png"))

    # if you placed your image in a directory different than itango.resource
    # then, instead you have to specify the absolute directory

    db.put_class_property("Libera", dict(__icon="/home/homer/.config/itango/libera.png"))

If you need different images for different devices of the same class, you can
specify an *__icon* property at the device level (which takes precedence over
the class property value, if defined)::

    db.put_device_property("BO01/DI/BPM-01", dict(__icon="libera2.png"))



List tango devices, classes, servers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ITango_ provides a set of magic functions (ipython lingo) that allow you to check
for the list tango devices, classes and servers which are registered in the
current database.

.. sourcecode:: itango

    ITango [1]: lsdev
                                      Device                     Alias                    Server                Class
    ---------------------------------------- ------------------------- ------------------------- --------------------
                  expchan/BL99_Dummy0DCtrl/1                  BL99_0D1                 Pool/BL99      ZeroDExpChannel
                      simulator/bl98/motor08                                      Simulator/BL98            SimuMotor
                  expchan/BL99_Dummy0DCtrl/3                  BL99_0D3                 Pool/BL99      ZeroDExpChannel
                  expchan/BL99_Dummy0DCtrl/2                  BL99_0D2                 Pool/BL99      ZeroDExpChannel
                  expchan/BL99_Dummy0DCtrl/5                  BL99_0D5                 Pool/BL99      ZeroDExpChannel
                  expchan/BL99_Dummy0DCtrl/4                  BL99_0D4                 Pool/BL99      ZeroDExpChannel
                  expchan/BL99_Dummy0DCtrl/7                  BL99_0D7                 Pool/BL99      ZeroDExpChannel
                  expchan/BL99_Dummy0DCtrl/6                  BL99_0D6                 Pool/BL99      ZeroDExpChannel
                      simulator/bl98/motor01                                      Simulator/BL98            SimuMotor
                      simulator/bl98/motor02                                      Simulator/BL98            SimuMotor
                      simulator/bl98/motor03                                      Simulator/BL98            SimuMotor
       mg/BL99/_mg_macserv_26065_-1320158352                                           Pool/BL99           MotorGroup
                      simulator/bl98/motor05                                      Simulator/BL98            SimuMotor
                      simulator/bl98/motor06                                      Simulator/BL98            SimuMotor
                      simulator/bl98/motor07                                      Simulator/BL98            SimuMotor
                    simulator/BL98/motctrl01                                      Simulator/BL98        SimuMotorCtrl
                  expchan/BL99_Simu0DCtrl1/1                  BL99_0D8                 Pool/BL99      ZeroDExpChannel
                 expchan/BL99_UxTimerCtrl1/1                BL99_Timer                 Pool/BL99         CTExpChannel
    ...

    ITango [1]: lsdevclass
    SimuCoTiCtrl                   TangoAccessControl             ZeroDExpChannel
    Door                           Motor                          DataBase
    MotorGroup                     IORegister                     SimuMotorCtrl
    TangoTest                      MacroServer                    TauTest
    SimuMotor                      SimuCounterEx                  MeasurementGroup
    Pool                           CTExpChannel

    ITango [1]: lsserv
    MacroServer/BL99               MacroServer/BL98               Pool/V2
    Pool/BL99                      Pool/BL98                      TangoTest/test
    Pool/tcoutinho                 Simulator/BL98
    TangoAccessControl/1           TauTest/tautest                DataBaseds/2
    MacroServer/tcoutinho          Simulator/BL99

Customized tango error message and introspection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ITango_ intercepts tango exceptions that occur when you do tango operations
(ex.: write an attribute with a value outside the allowed limits) and tries to
display it in a summarized, user friendly way.
If you need more detailed information about the last tango error, you can use
the magic command 'tango_error'.

.. sourcecode:: itango

    ITango [1]: test = Device("sys/tg_test/1")

    ITango [2]: test.no_value
    API_AttrValueNotSet : Read value for attribute no_value has not been updated
    For more detailed information type: tango_error

    ITango [3]: tango_error
    Last tango error:
    DevFailed[
    DevError[
        desc = 'Read value for attribute no_value has not been updated'
      origin = 'Device_3Impl::read_attributes_no_except'
      reason = 'API_AttrValueNotSet'
    severity = tango._tango.ErrSeverity.ERR]
    DevError[
        desc = 'Failed to read_attribute on device sys/tg_test/1, attribute no_value'
      origin = 'DeviceProxy::read_attribute()'
      reason = 'API_AttributeFailed'
    severity = tango._tango.ErrSeverity.ERR]]

Switching database
~~~~~~~~~~~~~~~~~~

You can switch database simply by executing the 'switchdb <host> [<port>]' magic
command.

.. sourcecode:: itango

    ITango [1]: switchdb

    Must give new database name in format <host>[:<port>].
    <port> is optional. If not given it defaults to 10000.

    Examples:
    switchdb homer:10005
    switchdb homer 10005
    switchdb homer

    ITango [2]: db
    Database(homer, 10000)

    ITango [3]: switchdb bart       # by default port is 10000

    ITango [4]: db
    Database(bart, 10000)

    ITango [5]: switchdb lisa 10005  # you can use spaces between host and port

    ITango [6]: db
    Database(lisa, 10005)

    ITango [7]: switchdb marge:10005   # or the traditional ':'

    ITango [8]: db
    Database(marge, 10005)

Refreshing the database
~~~~~~~~~~~~~~~~~~~~~~~

When itango starts up or when the database is switched, a query is made to the
tango Database device server which provides all necessary data. This
data is stored locally in a itango cache which is used to provide all the nice
features.
If the Database server is changed in some way (ex: a new device server is registered),
the local database cache is not consistent anymore with the tango database.
Therefore, itango provides a magic command 'refreshdb' that allows you to reread
all tango information from the database.

.. sourcecode:: itango

    ITango [1]: refreshdb

Storing your favorite tango objects for later usage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. note::
    This feature is not available if you have installed IPython 0.11!

Since version 7.1.2, :class:`DeviceProxy`, :class:`AttributeProxy` and
:class:`Database` became pickable.
This means that they can be used by the IPython_ 'store' magic command (type
'store?' on the itango console to get information on how to use this command).
You can, for example, assign your favorite devices in local python variables and
then store these for the next time you startup IPython_ with itango profile.

.. sourcecode:: itango

    ITango [1]: theta = Motor("BL99_M1")  # notice how we used tango alias

    ITango [2]: store theta
    Stored 'theta' (DeviceProxy)

    ITango [3]: Ctrl+D

    (IPython session is closed and started again...)

    ITango [1]: store -r # in some versions of IPython you may need to do this ...

    ITango [1]: print theta
    DeviceProxy(motor/bl99/1)

Adding itango to your own ipython profile
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Adding itango to the ipython default profile
##################################################

Let's assume that you find itango so useful that each time you start ipython, you want
itango features to be loaded by default.
The way to do this is by editing your default ipython configuration file:

1. On IPython <= 0.10

    $HOME/.ipython/ipy_user_conf.py and add the lines 1 and 7.

    .. note::
        The code shown below is a small part of your $HOME/.ipython/ipy_user_conf.py.
        It is shown here only the relevant part for this example.

    .. sourcecode:: python

        import itango

        def main():

            # uncomment if you want to get ipython -p sh behaviour
            # without having to use command line switches
            # import ipy_profile_sh
            itango.init_ipython(ip, console=False)

2. On IPython > 0.10

    First you have to check which is the configuration directory being used by
    IPython. For this, in an IPython console type:

    .. sourcecode:: itango

        ITango [1]: import IPython.utils.path

        ITango [2]: IPython.utils.path.get_ipython_dir()
        <IPYTHON_DIR>

    now edit <IPYTHON_DIR>/profile_default/ipython_config.py and add the
    following line at the end to add itango configuration::

        load_subconfig('ipython_config.py', profile='tango')

    Alternatively, you could also load itango as an IPython extension::

        config = get_config()
        i_shell_app = config.InteractiveShellApp
        extensions = getattr(i_shell_app, 'extensions', [])
        extensions.append('itango')
        i_shell_app.extensions = extensions

    for more information on how to configure IPython >= 0.11 please check the
    `IPython configuration <http://ipython.org/ipython-doc/dev/config/ipython.html#configuring-the-ipython-command-line-application>`_

And now, every time you start ipython::

    ipython

itango features will also be loaded.

.. sourcecode:: ipython

    In [1]: db
    Out[1]: Database(homer, 10000)


Adding itango to an existing customized profile
####################################################

.. note::
    This chapter has a pending update. The contents only apply to
    IPython <= 0.10.

If you have been working with IPython_ before and have already defined a
customized personal profile, you can extend your profile with itango features
without breaking your existing options. The trick is to initialize itango extension
with a parameter that tells itango to maintain the existing options (like colors,
command line and initial banner).

So, for example, let's say you have created a profile called nuclear, and therefore
you have a file called $HOME/.ipython/ipy_profile_nuclear.py with the following
contents:

.. sourcecode:: python

    import os
    import IPython.ipapi

    def main():
        ip = IPython.ipapi.get()

        o = ip.options
        o.banner = "Springfield nuclear powerplant CLI\n\nWelcome Homer Simpson"
        o.colors = "Linux"
        o.prompt_in1 = "Mr. Burns owns you [\\#]: "

    main()

In order to have itango features available to this profile you simply need to
add two lines of code (lines 3 and 7):

.. sourcecode:: python

    import os
    import IPython.ipapi
    import itango

    def main():
        ip = IPython.ipapi.get()
        itango.init_ipython(ip, console=False)

        o = ip.options
        o.banner = "Springfield nuclear powerplant CLI\n\nMr. Burns owns you!"
        o.colors = "Linux"
        o.prompt_in1 = "The Simpsons [\\#]: "

    main()

This will load the itango features into your profile while preserving your
profile's console options (like colors, command line and initial banner).

Creating a profile that extends itango profile
####################################################

.. note::
    This chapter has a pending update. The contents only apply to
    IPython <= 0.10.

It is also possible to create a profile that includes all itango features and at
the same time adds new ones. Let's suppose that you want to create a customized
profile called 'orbit' that automatically exports devices of class
'Libera' for the booster accelerator (assuming you are working on a synchrotron
like institute ;-).
Here is the code for the $HOME/.ipython/ipy_profile_orbit.py:

.. sourcecode:: python

    import os
    import IPython.ipapi
    import IPython.genutils
    import IPython.ColorANSI
    import itango
    import StringIO

    def magic_liberas(ip, p=''):
        """Lists all known Libera devices."""
        data = itango.get_device_map()
        s = StringIO.StringIO()
        cols = 30, 15, 20
        l = "%{0}s %{1}s %{2}s".format(*cols)
        print >>s, l % ("Device", "Alias", "Server")
        print >>s, l % (cols[0]*"-", cols[1]*"-", cols[2]*"-")
        for d, v in data.items():
            if v[2] != 'Libera': continue
            print >>s, l % (d, v[0], v[1])
        s.seek(0)
        IPython.genutils.page(s.read())

    def main():
        ip = IPython.ipapi.get()

        itango.init_ipython(ip)

        o = ip.options

        Colors = IPython.ColorANSI.TermColors
        c = dict(Colors.__dict__)

        o.banner += "\n{Brown}Welcome to Orbit analysis{Normal}\n".format(**c)

        o.prompt_in1 = "Orbit [\\#]: "
        o.colors = "BlueTango"

        ip.expose_magic("liberas", magic_liberas)

        db = ip.user_ns.get('db')
        dev_class_dict = itango.get_class_map()

        if not dev_class_dict.has_key("Libera"):
            return

        for libera in dev_class_dict['Libera']:
            domain, family, member = libera.split("/")
            var_name = domain + "_" + member
            var_name = var_name.replace("-","_")
            ip.to_user_ns( { var_name : tango.DeviceProxy(libera) } )

    main()

Then start your CLI with:

.. sourcecode:: console

    $ ipython --profile=orbit

and you will have something like this

.. image:: _images/itango02.png

Advanced event monitoring
~~~~~~~~~~~~~~~~~~~~~~~~~

With itango it is possible to monitor change events triggered by any tango
attribute which has events enabled.

To start monitoring the change events of an attribute:

.. sourcecode:: itango

    ITango [1]: mon -a BL99_M1/Position
    'BL99_M1/Position' is now being monitored. Type 'mon' to see all events

To list all events that have been intercepted:

.. sourcecode:: itango

    ITango [2]: mon
      ID           Device    Attribute            Value       Quality             Time
    ---- ---------------- ------------ ---------------- ------------- ----------------
       0     motor/bl99/1        state               ON    ATTR_VALID  17:11:08.026472
       1     motor/bl99/1     position            190.0    ATTR_VALID  17:11:20.691112
       2     motor/bl99/1        state           MOVING    ATTR_VALID  17:12:11.858985
       3     motor/bl99/1     position    188.954072857 ATTR_CHANGING  17:12:11.987817
       4     motor/bl99/1     position    186.045533882 ATTR_CHANGING  17:12:12.124448
       5     motor/bl99/1     position    181.295838155 ATTR_CHANGING  17:12:12.260884
       6     motor/bl99/1     position     174.55354729 ATTR_CHANGING  17:12:12.400036
       7     motor/bl99/1     position     166.08870515 ATTR_CHANGING  17:12:12.536387
       8     motor/bl99/1     position     155.77528943 ATTR_CHANGING  17:12:12.672846
       9     motor/bl99/1     position    143.358230136 ATTR_CHANGING  17:12:12.811878
      10     motor/bl99/1     position    131.476140017 ATTR_CHANGING  17:12:12.950391
      11     motor/bl99/1     position    121.555421781 ATTR_CHANGING  17:12:13.087970
      12     motor/bl99/1     position    113.457930987 ATTR_CHANGING  17:12:13.226531
      13     motor/bl99/1     position    107.319423091 ATTR_CHANGING  17:12:13.363559
      14     motor/bl99/1     position    102.928229946 ATTR_CHANGING  17:12:13.505102
      15     motor/bl99/1     position    100.584726495 ATTR_CHANGING  17:12:13.640794
      16     motor/bl99/1     position            100.0    ATTR_ALARM  17:12:13.738136
      17     motor/bl99/1        state            ALARM    ATTR_VALID  17:12:13.743481

    ITango [3]: mon -l mot.* state
      ID           Device    Attribute            Value       Quality             Time
    ---- ---------------- ------------ ---------------- ------------- ----------------
       0     motor/bl99/1        state               ON    ATTR_VALID  17:11:08.026472
       2     motor/bl99/1        state           MOVING    ATTR_VALID  17:12:11.858985
      17     motor/bl99/1        state            ALARM    ATTR_VALID  17:12:13.743481

To stop monitoring the attribute:

.. sourcecode:: itango

    ITango [1]: mon -d BL99_M1/Position
    Stopped monitoring 'BL99_M1/Position'

.. note::
    Type 'mon?' to see detailed information about this magic command