Source code for tango.utils._types

# SPDX-FileCopyrightText: All Contributors to the PyTango project
# SPDX-License-Identifier: LGPL-3.0-or-later

"""Tango data-type tables and the predicates that query them."""

import collections.abc
import enum
import inspect
import numbers

import numpy as np

from tango import CmdArgType, DevState, StdStringVector

# Types

__str_klasses = (str,)
__int_klasses = (int, np.integer)
__number_klasses = (numbers.Number, np.number)
__seq_klasses = (collections.abc.Sequence, bytearray, StdStringVector, np.ndarray)

_scalar_int_types = (
    CmdArgType.DevShort,
    CmdArgType.DevUShort,
    CmdArgType.DevLong,
    CmdArgType.DevULong,
    CmdArgType.DevLong64,
    CmdArgType.DevULong64,
)

_scalar_float_types = (
    CmdArgType.DevFloat,
    CmdArgType.DevDouble,
)

_scalar_numerical_types = _scalar_int_types + _scalar_float_types

_scalar_str_types = (
    CmdArgType.DevString,
    CmdArgType.ConstDevString,
)

_scalar_bool_types = (CmdArgType.DevBoolean,)

_scalar_types = (
    _scalar_numerical_types
    + _scalar_str_types
    + _scalar_bool_types
    + (
        CmdArgType.DevEncoded,
        CmdArgType.DevUChar,
    )
)

_array_int_types = (
    CmdArgType.DevVarShortArray,
    CmdArgType.DevVarUShortArray,
    CmdArgType.DevVarLongArray,
    CmdArgType.DevVarULongArray,
    CmdArgType.DevVarLong64Array,
    CmdArgType.DevVarULong64Array,
)

_array_float_types = (CmdArgType.DevVarFloatArray, CmdArgType.DevVarDoubleArray)

_array_numerical_types = _array_int_types + _array_float_types

_array_str_types = (CmdArgType.DevVarStringArray,)

_array_bool_types = (CmdArgType.DevVarBooleanArray,)

_array_types = (
    _array_numerical_types
    + _array_bool_types
    + _array_str_types
    + (
        CmdArgType.DevVarCharArray,
        CmdArgType.DevVarDoubleStringArray,
        CmdArgType.DevVarLongStringArray,
    )
)

_scalar_binary_types = (CmdArgType.DevEncoded,)

_array_binary_types = (CmdArgType.DevVarCharArray,)


FROM_TANGO_TO_NUMPY_TYPE = {
    CmdArgType.DevBoolean: np.bool_,
    CmdArgType.DevUChar: np.ubyte,
    CmdArgType.DevShort: np.short,
    CmdArgType.DevUShort: np.ushort,
    CmdArgType.DevLong: np.int32,
    CmdArgType.DevULong: np.uint32,
    CmdArgType.DevLong64: np.int64,
    CmdArgType.DevULong64: np.uint64,
    CmdArgType.DevString: str,
    CmdArgType.DevDouble: np.float64,
    CmdArgType.DevFloat: np.float32,
}


def __build_to_tango_type():
    ret = {
        int: CmdArgType.DevLong64,
        str: CmdArgType.DevString,
        bool: CmdArgType.DevBoolean,
        bytearray: CmdArgType.DevEncoded,
        float: CmdArgType.DevDouble,
        chr: CmdArgType.DevUChar,
        None: CmdArgType.DevVoid,
        "int": CmdArgType.DevLong64,
        "int16": CmdArgType.DevShort,
        "int32": CmdArgType.DevLong,
        "int64": CmdArgType.DevLong64,
        "uint": CmdArgType.DevULong64,
        "uint16": CmdArgType.DevUShort,
        "uint32": CmdArgType.DevULong,
        "uint64": CmdArgType.DevULong64,
        "str": CmdArgType.DevString,
        "string": CmdArgType.DevString,
        "text": CmdArgType.DevString,
        "bool": CmdArgType.DevBoolean,
        "boolean": CmdArgType.DevBoolean,
        "bytes": CmdArgType.DevEncoded,
        "bytearray": CmdArgType.DevEncoded,
        "float": CmdArgType.DevDouble,
        "float32": CmdArgType.DevFloat,
        "float64": CmdArgType.DevDouble,
        "double": CmdArgType.DevDouble,
        "byte": CmdArgType.DevUChar,
        "chr": CmdArgType.DevUChar,
        "char": CmdArgType.DevUChar,
        "None": CmdArgType.DevVoid,
        "state": CmdArgType.DevState,
        "enum": CmdArgType.DevEnum,
    }

    for key in dir(CmdArgType):
        if key.startswith("Dev"):
            value = getattr(CmdArgType, key)
            ret[key] = ret[value] = value

    for tango_type, numpy_type in FROM_TANGO_TO_NUMPY_TYPE.items():
        ret[numpy_type] = tango_type

    return ret


TO_TANGO_TYPE = __build_to_tango_type()

_scalar_to_array_type = {
    CmdArgType.DevBoolean: CmdArgType.DevVarBooleanArray,
    CmdArgType.DevUChar: CmdArgType.DevVarCharArray,
    CmdArgType.DevShort: CmdArgType.DevVarShortArray,
    CmdArgType.DevUShort: CmdArgType.DevVarUShortArray,
    CmdArgType.DevLong: CmdArgType.DevVarLongArray,
    CmdArgType.DevULong: CmdArgType.DevVarULongArray,
    CmdArgType.DevLong64: CmdArgType.DevVarLong64Array,
    CmdArgType.DevULong64: CmdArgType.DevVarULong64Array,
    CmdArgType.DevFloat: CmdArgType.DevVarFloatArray,
    CmdArgType.DevDouble: CmdArgType.DevVarDoubleArray,
    CmdArgType.DevString: CmdArgType.DevVarStringArray,
    CmdArgType.ConstDevString: CmdArgType.DevVarStringArray,
}


def __add_derived_scalar_types(scalar_to_array_map):
    """Let every spelling accepted by TO_TANGO_TYPE index the array map too."""
    for alias, tango_type in TO_TANGO_TYPE.items():
        if tango_type in scalar_to_array_map:
            scalar_to_array_map[alias] = scalar_to_array_map[tango_type]


__add_derived_scalar_types(_scalar_to_array_type)


[docs] def is_pure_str(obj): """ Tells if the given object is a python string. This means any subclass of str. :param obj: the object to be inspected :type obj: :py:obj:`object` :return: True is the given obj is a string or False otherwise :rtype: :py:obj:`bool` """ return isinstance(obj, __str_klasses)
[docs] def is_seq(obj): """ Tells if the given object is a python sequence. It will return True for any collections.Sequence (list, tuple, str, bytes, unicode), bytearray and (if numpy is enabled) numpy.ndarray :param obj: the object to be inspected :type obj: :py:obj:`object` :return: True is the given obj is a sequence or False otherwise :rtype: :py:obj:`bool` """ return isinstance(obj, __seq_klasses)
[docs] def is_non_str_seq(obj): """ Tells if the given object is a python sequence (excluding string sequences). It will return True for any collections.Sequence (list, tuple (and bytes in python3)), bytearray and (if numpy is enabled) numpy.ndarray :param obj: the object to be inspected :type obj: :py:obj:`object` :return: True is the given obj is a sequence or False otherwise :rtype: :py:obj:`bool` """ return is_seq(obj) and not is_pure_str(obj)
def is_devstate(obj): return inspect.isclass(obj) and issubclass(obj, DevState) def is_devstate_seq(obj): if is_non_str_seq(obj): while is_non_str_seq(obj) and len(obj): obj = obj[0] return is_devstate(obj) return False def is_enum(obj): return inspect.isclass(obj) and issubclass(obj, enum.Enum) def is_enum_seq(obj): if is_non_str_seq(obj): while is_non_str_seq(obj) and len(obj): obj = obj[0] return is_enum(obj) return False
[docs] def is_integer(obj): """ Tells if the given object is a python integer. It will return True for any int, long (in python 2) and (if numpy is enabled) numpy.integer :param obj: the object to be inspected :type obj: :py:obj:`object` :return: True is the given obj is a python integer or False otherwise :rtype: :py:obj:`bool` """ return isinstance(obj, __int_klasses) and not isinstance(obj, bool)
[docs] def is_number(obj): """ Tells if the given object is a python number. It will return True for any numbers.Number and (if numpy is enabled) numpy.number :param obj: the object to be inspected :type obj: :py:obj:`object` :return: True is the given obj is a python number or False otherwise :rtype: :py:obj:`bool` """ return isinstance(obj, __number_klasses)
def is_scalar(tg_type): """Tells if the given tango type is a scalar :param tg_type: tango type :type tg_type: :class:`tango.CmdArgType` :return: True if the given tango type is a scalar or False otherwise :rtype: :py:obj:`bool` """ return tg_type in _scalar_types is_scalar_type = is_scalar def is_array(tg_type): """Tells if the given tango type is an array type :param tg_type: tango type :type tg_type: :class:`tango.CmdArgType` :return: True if the given tango type is an array type or False otherwise :rtype: :py:obj:`bool` """ return tg_type in _array_types is_array_type = is_array def __is_type(tg_type, inc_array, scalar_types, array_types): """Shared body of the type predicates: array types count only on request.""" if tg_type in scalar_types: return True if not inc_array: return False return tg_type in array_types def is_numerical(tg_type, inc_array=False): """Tells if the given tango type is numerical :param tg_type: tango type :type tg_type: :class:`tango.CmdArgType` :param inc_array: (optional, default is False) determines if include array in the list of checked types :type inc_array: :py:obj:`bool` :return: True if the given tango type is a numerical or False otherwise :rtype: :py:obj:`bool` """ return __is_type(tg_type, inc_array, _scalar_numerical_types, _array_numerical_types) is_numerical_type = is_numerical def is_int(tg_type, inc_array=False): """Tells if the given tango type is integer :param tg_type: tango type :type tg_type: :class:`tango.CmdArgType` :param inc_array: (optional, default is False) determines if include array in the list of checked types :type inc_array: :py:obj:`bool` :return: True if the given tango type is integer or False otherwise :rtype: :py:obj:`bool` """ return __is_type(tg_type, inc_array, _scalar_int_types, _array_int_types) is_int_type = is_int def is_float(tg_type, inc_array=False): """Tells if the given tango type is float :param tg_type: tango type :type tg_type: :class:`tango.CmdArgType` :param inc_array: (optional, default is False) determines if include array in the list of checked types :type inc_array: :py:obj:`bool` :return: True if the given tango type is float or False otherwise :rtype: :py:obj:`bool` """ return __is_type(tg_type, inc_array, _scalar_float_types, _array_float_types) is_float_type = is_float
[docs] def is_bool(tg_type, inc_array=False): """Tells if the given tango type is boolean :param tg_type: tango type :type tg_type: :class:`tango.CmdArgType` :param inc_array: (optional, default is False) determines if include array in the list of checked types :type inc_array: :py:obj:`bool` :return: True if the given tango type is boolean or False otherwise :rtype: :py:obj:`bool` """ return __is_type(tg_type, inc_array, _scalar_bool_types, _array_bool_types)
is_bool_type = is_bool def is_str(tg_type, inc_array=False): """Tells if the given tango type is string :param tg_type: tango type :type tg_type: :class:`tango.CmdArgType` :param inc_array: (optional, default is False) determines if include array in the list of checked types :type inc_array: :py:obj:`bool` :return: True if the given tango type is string or False otherwise :rtype: :py:obj:`bool` """ return __is_type(tg_type, inc_array, _scalar_str_types, _array_str_types) is_str_type = is_str def is_binary(tg_type, inc_array=False): """Tells if the given tango type is binary :param tg_type: tango type :type tg_type: :class:`tango.CmdArgType` :param inc_array: (optional, default is False) determines if include array in the list of checked types :type inc_array: :py:obj:`bool` :return: True if the given tango type is binary or False otherwise :rtype: :py:obj:`bool` """ return __is_type(tg_type, inc_array, _scalar_binary_types, _array_binary_types) is_binary_type = is_binary
[docs] def scalar_to_array_type(tg_type): """ Gives the array tango type corresponding to the given tango scalar type. Example: giving DevLong will return DevVarLongArray. :param tg_type: tango type :type tg_type: :class:`tango.CmdArgType` :return: the array tango type for the given scalar tango type :rtype: :class:`tango.CmdArgType` :raises ValueError: in case the given dtype is not a tango scalar type """ try: return _scalar_to_array_type[tg_type] except KeyError: raise ValueError(f"Invalid tango scalar type: {tg_type}") from None