File: _cls_dict.py

package info (click to toggle)
python-typish 1.9.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 324 kB
  • sloc: python: 1,632; makefile: 2
file content (49 lines) | stat: -rw-r--r-- 1,888 bytes parent folder | download
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
from collections import OrderedDict
from typing import Optional, Any


class ClsDict(OrderedDict):
    """
    ClsDict is a dict that accepts (only) types as keys and will return its
    values depending on instance checks rather than equality checks.
    """
    def __new__(cls, *args, **kwargs):
        """
        Construct a new instance of ``ClsDict``.
        :param args: a dict.
        :param kwargs: any kwargs that ``dict`` accepts.
        :return: a ``ClsDict``.
        """
        from typish.functions._is_type_annotation import is_type_annotation

        if len(args) > 1:
            raise TypeError('TypeDict accepts only one positional argument, '
                            'which must be a dict.')
        if args and not isinstance(args[0], dict):
            raise TypeError('TypeDict accepts only a dict as positional '
                            'argument.')
        if not all([is_type_annotation(key) for key in args[0]]):
            raise TypeError('The given dict must only hold types as keys.')
        return super().__new__(cls, args[0], **kwargs)

    def __getitem__(self, item: Any) -> Any:
        """
        Return the value of the first encounter of a key for which
        ``is_instance(item, key)`` holds ``True``.
        :param item: any item.
        :return: the value of which the type corresponds with item.
        """
        from typish.functions._get_type import get_type
        from typish.functions._subclass_of import subclass_of

        item_type = get_type(item, use_union=True)
        for key, value in self.items():
            if subclass_of(item_type, key):
                return value
        raise KeyError('No match for {}'.format(item))

    def get(self, item: Any, default: Any = None) -> Optional[Any]:
        try:
            return self.__getitem__(item)
        except KeyError:
            return default