File: registry.py

package info (click to toggle)
python-calendra 7.11.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,600 kB
  • sloc: python: 16,840; makefile: 6
file content (136 lines) | stat: -rw-r--r-- 4,417 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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
from importlib import import_module

from .core import Calendar
from .exceptions import ISORegistryError


class IsoRegistry:
    """
    Registry for all calendars retrievable
    by ISO 3166-2 codes associated with countries
    where they are used as official calendars.

    Two letter codes are favored for any subdivisions.
    """

    STANDARD_MODULES = (
        # Europe Countries
        'europe',
        # United States of America
        'usa',
        # American continent outside of USA
        'america',
        # African continent
        'africa',
        # Asia
        'asia',
        # Oceania
        'oceania',
    )

    def __init__(self, load_standard_modules=False):
        self.region_registry = dict()
        if load_standard_modules:
            for module_name in self.STANDARD_MODULES:
                module = f'calendra.{module_name}'
                all_classes = getattr(import_module(module), '__all__')
                self.load_module_from_items(module, all_classes)

    def register(self, iso_code, cls):
        """
        Store the ``cls`` in the region_registry.
        """
        if not issubclass(cls, Calendar):
            raise ISORegistryError(
                f"Class `{cls}` is not a Calendar class"
            )
        self.region_registry[iso_code] = cls

    def load_module_from_items(self, module_name, items):
        """
        Load all registered classes in the registry
        """
        for item in items:
            cls = getattr(import_module(module_name), item)
            iso_stuff = getattr(cls, '__iso_code', None)
            if iso_stuff:
                iso_code, class_name = iso_stuff
                if iso_code and cls.__name__ == class_name:
                    self.register(iso_code, cls)

    def get(self, iso_code):
        """
        Retrieve calendar class associated with given ``iso_code``.

        If calendar of subdivision is not registered
        (for subdivision like ISO codes, e.g. GB-ENG)
        returns calendar of containing region
        (e.g. United Kingdom for ISO code GB) if it's available.

        :rtype: Calendar
        """
        return self.region_registry.get(iso_code)

    def get_subregions(self, iso_code):
        """
        Returns subregion calendar classes for given region iso_code.

        >>> registry = IsoRegistry()
        >>> # assuming calendars registered are: DE, DE-HH, DE-BE
        >>> registry.get_subregions('DE')  # doctest: +SKIP
        {'DE-HH': <class 'calendra.europe.germany.Hamburg'>,
        'DE-BE': <class 'calendra.europe.germany.Berlin'>}
        :rtype dict
        :return dict where keys are ISO codes strings
        and values are calendar classes
        """
        items = dict()
        for key, value in self.region_registry.items():
            if key.startswith(f"{iso_code}-"):
                items[key] = value
        return items

    def get_calendars(self, region_codes=None, include_subregions=False):
        """
        Returns calendar classes for regions

        :param region_codes list of ISO codes for selected regions. If empty,
                            the function will return all items from the
                            registry.
        :param include_subregions boolean if subregions
        of selected regions should be included in result
        :rtype dict
        :return dict where keys are ISO codes strings
        and values are calendar classes
        """
        if not region_codes:
            # Here it contains all subregions
            if include_subregions:
                return self.region_registry.copy()
            items = {k: v for k, v in self.region_registry.items()
                     if '-' not in k}
            return items

        items = dict()
        for code in region_codes:
            try:
                items[code] = self.region_registry[code]
            except KeyError:
                continue
            if include_subregions:
                items.update(self.get_subregions(code))
        return items


registry = IsoRegistry()

# Europe Countries
from calendra.europe import *  # noqa
# United States of America
from calendra.usa import *  # noqa
# American continent outside of USA
from calendra.america import *  # noqa
# African continent
from calendra.africa import *  # noqa
from calendra.asia import *  # noqa
from calendra.oceania import *  # noqa