Passed
Pull Request — master (#23)
by Ramon
55s
created

jsons._common_impl.StateHolder._warn()   A

Complexity

Conditions 2

Size

Total Lines 6
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nop 4
1
"""
2
PRIVATE MODULE: do not import (from) it directly.
3
4
This module contains implementations of common functionality that can be used
5
throughout `jsons`.
6
"""
7
import warnings
8
from typing import Callable, Optional
9
10
11
META_ATTR = '-meta'  # The name of the attribute holding meta info.
12
13
14
class StateHolder:
15
    """
16
    This class holds the registered serializers and deserializers.
17
    """
18
    _classes_serializers = list()
19
    _classes_deserializers = list()
20
    _serializers = dict()
21
    _deserializers = dict()
22
    _announced_classes = dict()
23
    _suppress_warnings = False
24
25
    @classmethod
26
    def _warn(cls, msg, *args, **kwargs):
27
        if not cls._suppress_warnings:
28
            msg_ = ('{} You can suppress warnings like this using '
29
                    'jsons.suppress_warnings().'.format(msg))
30
            warnings.warn(msg_, *args, **kwargs)
31
32
33
def get_class_name(cls: type,
34
                   transformer: Optional[Callable[[str], str]] = None,
35
                   fully_qualified: bool = False,
36
                   fork_inst: Optional[type] = StateHolder) -> Optional[str]:
37
    """
38
    Return the name of a class.
39
    :param cls: the class of which the name if to be returned.
40
    :param transformer: any string transformer, e.g. ``str.lower``.
41
    :param fully_qualified: if ``True`` return the fully qualified name (i.e.
42
    complete with module name).
43
    :param fork_inst if given, it uses this fork of ``JsonSerializable`` for
44
    finding the class name.
45
    :return: the name of ``cls``, transformed if a transformer is given.
46
    """
47
    if cls in fork_inst._announced_classes:
48
        return fork_inst._announced_classes[cls]
49
    cls_name = _get_simple_name(cls)
50
    module = _get_module(cls)
51
    transformer = transformer or (lambda x: x)
52
    if not cls_name and hasattr(cls, '__origin__'):
53
        origin = cls.__origin__
54
        cls_name = get_class_name(origin, transformer,
55
                                  fully_qualified, fork_inst)
56
    if not cls_name:
57
        cls_name = str(cls)
58
    if fully_qualified and module:
59
        cls_name = '{}.{}'.format(module, cls_name)
60
    cls_name = transformer(cls_name)
61
    return cls_name
62
63
64
def _get_simple_name(cls: type) -> str:
65
    cls_name = getattr(cls, '__name__', None)
66
    if not cls_name:
67
        cls_name = getattr(cls, '_name', None)
68
    if not cls_name:
69
        cls_name = repr(cls)
70
        cls_name = cls_name.split('[')[0]  # Remove generic types.
71
        cls_name = cls_name.split('.')[-1]  # Remove any . caused by repr.
72
    return cls_name
73
74
75
def _get_module(cls: type) -> Optional[str]:
76
    builtin_module = str.__class__.__module__
77
    module = cls.__module__
78
    if module and module != builtin_module:
79
        return module
80
81
82
def get_parents(cls: type, lizers: list) -> list:
83
    """
84
    Return a list of serializers or deserializers that can handle a parent
85
    of ``cls``.
86
    :param cls: the type that
87
    :param lizers: a list of serializers or deserializers.
88
    :return: a list of serializers or deserializers.
89
    """
90
    parents = []
91
    for cls_ in lizers:
92
        try:
93
            if issubclass(cls, cls_):
94
                parents.append(cls_)
95
        except TypeError:
96
            pass  # Some types do not support `issubclass` (e.g. Union).
97
    return parents
98