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
|