Passed
Push — master ( dc8133...73195b )
by Ramon
01:02 queued 11s
created

_LiteralMeta.__getattribute__()   C

Complexity

Conditions 9

Size

Total Lines 23
Code Lines 15

Duplication

Lines 23
Ratio 100 %

Importance

Changes 0
Metric Value
cc 9
eloc 15
nop 2
dl 23
loc 23
rs 6.6666
c 0
b 0
f 0
1
import typing
2
3
from typish.classes._subscriptable_type import SubscriptableType
4
5
6
def is_literal_type(cls: typing.Any) -> bool:
7
    """
8
    Return whether cls is a Literal type.
9
    :param cls: the type that is to be checked.
10
    :return: True if cls is a Literal type.
11
    """
12
    from typish.functions._get_simple_name import get_simple_name
13
14
    return get_simple_name(cls) == 'Literal'
15
16
17 View Code Duplication
class _LiteralMeta(SubscriptableType):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
18
    """
19
    A Metaclass that exists to serve Literal and alter the __args__ attribute.
20
    """
21
    def __getattribute__(cls, item):
22
        """
23
        This method makes sure that __args__ is a tuple, like with
24
        typing.Literal.
25
        :param item: the name of the attribute that is obtained.
26
        :return: the attribute.
27
        """
28
        if item == '__args__':
29
            try:
30
                result = SubscriptableType.__getattribute__(cls, item)
31
                if (result and isinstance(result, tuple)
32
                        and isinstance(result[0], tuple)):
33
                    result = result[0]  # result was a tuple in a tuple.
34
                if result and not isinstance(result, tuple):
35
                    result = (result,)
36
            except AttributeError:  # pragma: no cover
37
                # In case of Python 3.5
38
                result = tuple()
39
        elif item in ('__origin__', '__name__', '_name'):
40
            result = 'Literal'
41
        else:
42
            result = SubscriptableType.__getattribute__(cls, item)
43
        return result
44
45
    def __instancecheck__(self, instance):
46
        return self.__args__ and instance in self.__args__
47
48
    def __str__(self):
49
        args = ', '.join(str(arg) for arg in self.__args__)
50
        return '{}[{}]'.format(self.__name__, args)
51
52
    def __subclasscheck__(self, subclass: typing.Any) -> bool:
53
        return is_literal_type(subclass)
54
55
56
class LiteralAlias(type, metaclass=_LiteralMeta):
57
    """
58
    This is a backwards compatible variant of typing.Literal (Python 3.8+).
59
    """
60
    @staticmethod
61
    def from_literal(literal: typing.Any) -> typing.Type['LiteralAlias']:
62
        """
63
        Create a LiteralAlias from the given typing.Literal.
64
        :param literal: the typing.Literal type.
65
        :return: a LiteralAlias type.
66
        """
67
        from typish.functions._get_args import get_args
68
69
        args = get_args(literal)
70
        return LiteralAlias[args] if args else LiteralAlias
71
72
73
# If Literal is available (Python 3.8+), then return that type instead.
74
Literal = getattr(typing, 'Literal', LiteralAlias)
75