aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python/enum_util.py
blob: 41dfd8a459855e7e70089f3634f692e7e493b2a0 (plain)
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
# Copyright (c) 2024 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Utility functions for handling VPP API enum values from Robot."""


from enum import Enum, IntEnum
from typing import Type, Union


# The return type is enum_class, but it is hard to explain that to pylint.
def get_enum_instance(
    enum_class: Type[Enum], value: Union[Enum, str, int, None]
) -> Enum:
    """Return an enum instance matching the string name.

    In Robot, it is not convenient to construct Enum instances,
    most values defined in Robot are strings.

    This helper function can be used in Python L1 keywords
    to convert string into the corresponding Enum instance.
    Aliases are also recognized.

    As an added benefit, support various Robot-like niceties,
    like lower case, or dash or space instead of underscore.

    As a common shortcut, value is returned it it already is an instance.

    Another convenience: None or empty string is processed as "NONE".

    If the class is a subclass of IntEnum, int values
    and (string) values convertable to int are also accepted as input.

    :param enum_class: Class object instance of which should be returned.
    :param value: String or any other recognized form of an enum instance.
    :type enum_class: Type[Enum]
    :type value: Union[enum_class, str, int, None]
    :returns: The matching instance, if found.
    :rtype: enum_class
    :raises: ValueError if no matching instance is found.
    """
    if issubclass(enum_class, IntEnum):
        try:
            int_value = int(value)
            return enum_class(int_value)
        except (TypeError, ValueError):
            pass
    if isinstance(value, enum_class):
        return value
    if not value:
        value = "NONE"
    normalized_name = str(value).upper().replace("-", "_").replace(" ", "_")
    members = enum_class.__members__  # Includes aliases, useful for NONE.
    if normalized_name not in members:
        msg = f"Enum class {enum_class} does not have value {normalized_name!r}"
        raise ValueError(msg)
    return members[normalized_name]