Other changes#

Attribute configuration caching#

When an attribute is read or written with the high-level API, PyTango needs the attribute configuration: for reads, to convert a DevEnum value into a Python IntEnum with labels; for writes, to convert the Python value into the correct C++ data type.

In 10.3.0 each attribute’s configuration is cached on first access by default, and the cached configuration is reused to take the “fast” write path (avoiding an extra synchronous read of the attribute configuration on every write). Each DeviceProxy instance has its own cache.

This is a behaviour change. If the attribute configuration on the server changes while a DeviceProxy is alive (e.g. the server is restarted after a change, or a dynamic attribute is removed and reinstalled), the cached values are not updated automatically, which can lead to unexpected behaviour. To stay safe, PyTango automatically invalidates the cache and re-fetches the configuration if a TypeError is encountered during a write, so in the worst case a genuine type mismatch only costs one extra IO.

Three new DeviceProxy methods let you control the cache:

If you expect attribute configurations to mutate during the lifetime of a DeviceProxy, disable caching. PyTango will then do one additional IO to the server per read/write to fetch the configuration. See attribute configuration caching for more details.

Stricter string-to-boolean device properties#

Boolean device property values are now parsed strictly. The accepted spellings (case-insensitive) are:

  • True: y, yes, t, true, on, 1

  • False: n, no, f, false, off, 0

Anything else now raises an error. Previously, any string other than "true" was silently coerced to False, so typos such as "ture" or "yse" masked configuration errors:

# Before 10.3.0: "ture" silently became False
# From 10.3.0:   "ture" raises an error

This affects DevBoolean and DevVarBooleanArray device properties. Make sure your database property values use one of the accepted spellings.

Errors raised while parsing any device property value are now also more actionable: they report the device name, property name, raw value, and target type, for example:

Failed to convert property 'MyProp' of device 'sys/mydev/1' (value=['1, 2']) to type DevVarLongArray: invalid literal for int() with base 10: '1, 2'

The internal PropUtil.stringArray2values and PropUtil.values2string methods were removed as part of this change. PropUtil is internal API, so this should not affect normal use.

Other additions#

These are additive and require no migration, but may let you simplify your code:

  • PyTangoThread wraps threading.Thread so the task runs inside an EnsureOmniThread context for the whole lifetime of the thread. This removes the need for scattered manual EnsureOmniThread calls:

    import tango
    
    # Instead of wrapping the body of your thread in `with EnsureOmniThread(): ...`
    thread = tango.utils.PyTangoThread(target=my_task)
    thread.start()
    

    Both supplying a target and subclassing/overriding run() are supported. See the multiprocessing how-to.

  • Util now has a cleanup method, and tango_loop calls it on shutdown. This makes it possible to restart a Tango server within the same process, which was not possible before.

  • Equality operators (== / !=) are now exposed for CommandInfo, AttributeInfo, AttributeInfoEx, AttributeEventInfo, and AttributeAlarmInfo, matching the operators already present in cppTango.