Skip to content

Commit 0c12705

Browse files
committed
Add type hinting
Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
1 parent 45d4432 commit 0c12705

73 files changed

Lines changed: 185 additions & 167 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/pythonpackage.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ jobs:
1515
run: |
1616
python -m pip install --upgrade pip
1717
pip install .
18+
pip install types-python-dateutil
1819
pip install ruff mypy
1920
- name: Run ruff
2021
run: |

src/holidata/__init__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
from typing import Iterator
1+
from typing import Iterator, Union
22

33
from holidata.emitters import Emitter
44
from holidata.holiday import Country, Holiday
55
from holidata.holidays import *
66

77

88
class Holidata:
9-
def __init__(self, holidays, emitter: Emitter = None):
9+
def __init__(self, holidays: Iterator[Holiday], emitter: Union[Emitter, None] = None) -> None:
1010
self.holidays = holidays
1111
self.emitter = emitter
1212

1313
def __str__(self) -> str:
14+
if not self.emitter:
15+
raise ValueError
1416
return self.emitter.output(self.holidays)
1517

1618
def formatted_as(self, format_id: str) -> 'Holidata':
@@ -20,7 +22,7 @@ def formatted_as(self, format_id: str) -> 'Holidata':
2022

2123

2224
class Locale:
23-
def __init__(self, country: Country, lang: str):
25+
def __init__(self, country: Country, lang: str) -> None:
2426
self.country = country
2527
self.lang = lang
2628

@@ -60,7 +62,7 @@ def get_emitter_for(identifier: str) -> Emitter:
6062
return emitter_class()
6163

6264

63-
def for_locale(country_id: str, lang_id: str = None) -> Locale:
65+
def for_locale(country_id: str, lang_id: Union[str, None] = None) -> Locale:
6466
country = get_country_for(country_id)
6567
lang_id = country.validate_language_or_get_default(lang_id)
6668

src/holidata/emitters.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
import csv
22
import io
33
import json
4-
from typing import Any, Callable, Dict, List
4+
from typing import Any, Callable, Dict, Iterator, List, Union
55

66
from holidata.holiday import Holiday
77
from holidata.plugin import PluginMount
88

99

1010
class Emitter(metaclass=PluginMount):
11-
type: str = None
11+
type: Union[str, None] = None
1212

13-
def __init__(self):
13+
def __init__(self) -> None:
1414
if self.type is None:
1515
raise ValueError(f"Emitter {self.__class__.__name__} does not provide its type!")
1616

1717
@staticmethod
18-
def get(identifier: str) -> Callable[[], 'Emitter']:
18+
def get(identifier: str) -> Union[Callable[[], 'Emitter'], None]:
1919
return Emitter.get_plugin(identifier, "type")
2020

21-
def output(self, holidays: List[Holiday]) -> str:
21+
def output(self, holidays: Iterator[Holiday]) -> str:
2222
raise NotImplementedError
2323

2424

2525
class JsonEmitter(Emitter):
2626
type: str = "json"
2727

28-
def output(self, holidays: List[Holiday]) -> str:
28+
def output(self, holidays: Iterator[Holiday]) -> str:
2929
export_data: List[Dict[str, Any]] = [h.as_dict() for h in holidays]
3030
export_data.sort(key=lambda x: (x["date"], x["description"], x["region"]))
3131
return "\n".join([json.dumps(h, ensure_ascii=False, sort_keys=False, indent=None, separators=(",", ":")) for h in export_data]) + "\n"
@@ -34,12 +34,12 @@ def output(self, holidays: List[Holiday]) -> str:
3434
class CsvEmitter(Emitter):
3535
type: str = "csv"
3636

37-
def output(self, holidays: List[Holiday]) -> str:
37+
def output(self, holidays: Iterator[Holiday]) -> str:
3838
export_data: List[Dict[str, Any]] = [h.as_dict() for h in holidays]
3939
export_data.sort(key=lambda x: (x["date"], x["description"], x["region"]))
4040
result: io.StringIO = io.StringIO()
4141

42-
writer: csv.DictWriter = csv.DictWriter(
42+
writer: csv.DictWriter[str] = csv.DictWriter(
4343
result,
4444
["locale", "region", "date", "description", "type", "notes"],
4545
quoting=csv.QUOTE_ALL,
@@ -66,7 +66,7 @@ def _format_yaml(holiday: Dict[str, Any]) -> str:
6666

6767
return output
6868

69-
def output(self, holidays: List[Holiday]) -> str:
69+
def output(self, holidays: Iterator[Holiday]) -> str:
7070
export_data: List[Dict[str, Any]] = [h.as_dict() for h in holidays]
7171
export_data.sort(key=lambda x: (x["date"], x["description"], x["region"]))
7272

@@ -94,7 +94,7 @@ def _format_xml(holiday: Dict[str, Any]) -> str:
9494
output += " </holiday>\n"
9595
return output
9696

97-
def output(self, holidays: List[Holiday]) -> str:
97+
def output(self, holidays: Iterator[Holiday]) -> str:
9898
export_data: List[Dict[str, Any]] = [h.as_dict() for h in holidays]
9999
export_data.sort(key=lambda x: (x["date"], x["description"], x["region"]))
100100

src/holidata/holiday.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from dataclasses import dataclass
2-
from typing import Callable, Dict, Iterator, List, Union
2+
from typing import Callable, Dict, Iterator, List, Literal, Union
33

44
import dateutil
55
from arrow import Arrow
@@ -19,7 +19,7 @@ class Holiday:
1919
flags: str = ""
2020
notes: str = ""
2121

22-
def as_dict(self) -> dict:
22+
def as_dict(self) -> Dict[str, str]:
2323
return {
2424
"locale": self.locale,
2525
"region": self.region,
@@ -31,26 +31,30 @@ def as_dict(self) -> dict:
3131

3232

3333
class HolidayGenerator:
34-
def __init__(self, country_id: str, default_lang: str):
34+
def __init__(self, country_id: str, default_lang: Union[str, None]) -> None:
3535
self.name_dict: Dict[str, str] = {}
3636
self.notes: str = ""
3737
self.regions: List[str] = [""]
3838
self.flags: str = ""
3939
self.date: Callable[[int], Union[Arrow, None]] = lambda year: None
4040
self.country_id: str = country_id
41-
self.default_lang: str = default_lang
41+
self.default_lang: Union[str, None] = default_lang
4242
self.filters: List[Callable[[int], bool]] = []
4343

44-
def with_name(self, name: str, lang: str = None) -> 'HolidayGenerator':
44+
def with_name(self, name: str, lang: Union[str, None] = None) -> 'HolidayGenerator':
4545
lang = self.default_lang if lang is None else lang
46+
47+
if lang is None:
48+
raise ValueError("No language specified and no default language was provided!")
49+
4650
self.name_dict[lang] = name
4751
return self
4852

4953
def with_names(self, name_dict: Dict[str, str]) -> 'HolidayGenerator':
5054
self.name_dict = name_dict
5155
return self
5256

53-
def on(self, date_func: Callable[[int], Arrow] = None) -> 'HolidayGenerator':
57+
def on(self, date_func: Callable[[int], Union[Arrow, None]]) -> 'HolidayGenerator':
5458
self.date = date_func
5559
return self
5660

@@ -128,27 +132,28 @@ class Country(metaclass=PluginMount):
128132
id: str
129133
languages: List[str]
130134
default_lang: Union[str, None] = None
131-
easter_type: int
132-
holiday_generators: list
133-
regions: list
135+
easter_type: Literal[1, 2, 3]
136+
holiday_generators: List[HolidayGenerator]
137+
regions: List['Region']
134138

135-
def __init__(self):
139+
def __init__(self) -> None:
136140
if not self.id:
137141
raise ValueError(f"Country '{self.__class__.__name__}' does not provide an id!")
138142
if not self.languages:
139143
raise ValueError(f"Country '{self.__class__.__name__}' does not list any languages!")
140144
if self.default_lang is not None and self.default_lang not in self.languages:
141145
raise ValueError(f"Country '{self.__class__.__name__}' does not list language '{self.default_lang}'!")
142146

143-
self.default_lang = self.languages[0] if self.default_lang is None and len(self.languages) == 1 else self.default_lang
147+
self.default_lang = self.languages[0] if self.default_lang is None and len(
148+
self.languages) == 1 else self.default_lang
144149
self.holiday_generators = []
145150
self.regions = []
146151

147152
@staticmethod
148-
def get(identifier):
153+
def get(identifier: str) -> Union[Callable[[], 'Country'], None]:
149154
return Country.get_plugin(identifier, "id")
150155

151-
def validate_language_or_get_default(self, lang_id: str) -> str:
156+
def validate_language_or_get_default(self, lang_id: Union[str, None]) -> str:
152157
if lang_id and lang_id.lower() not in self.languages:
153158
raise ValueError(
154159
f"Language '{lang_id}' is not defined for country '{self.id}'! Choose one of [{', '.join(self.languages)}].")
@@ -182,7 +187,7 @@ def wrapper(year: int) -> Arrow:
182187

183188

184189
class Region:
185-
def __init__(self, id: str, country: Country):
190+
def __init__(self, id: str, country: Country) -> None:
186191
self.id: str = id
187192
self.country: Country = country
188193
self.holiday_generators: List[HolidayGenerator] = []

src/holidata/holidays/AT/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class AT(Country):
1313
languages = ["de"]
1414
easter_type = EASTER_WESTERN
1515

16-
def __init__(self):
16+
def __init__(self) -> None:
1717
super().__init__()
1818

1919
self.define_holiday() \

src/holidata/holidays/BE/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class BE(Country):
1313
languages = ["de", "fr", "nl"]
1414
easter_type = EASTER_WESTERN
1515

16-
def __init__(self):
16+
def __init__(self) -> None:
1717
super().__init__()
1818

1919
self.define_holiday() \

src/holidata/holidays/BR/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class BR(Country):
4949
languages = ["pt"]
5050
easter_type = EASTER_WESTERN
5151

52-
def __init__(self):
52+
def __init__(self) -> None:
5353
super().__init__()
5454

5555
self.define_holiday() \

src/holidata/holidays/CA/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class CA(Country):
3737
languages = ["en", "fr"]
3838
easter_type = EASTER_WESTERN
3939

40-
def __init__(self):
40+
def __init__(self) -> None:
4141
super().__init__()
4242

4343
self.define_holiday() \

src/holidata/holidays/CH/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class CH(Country):
1313
languages = ["de"]
1414
easter_type = EASTER_WESTERN
1515

16-
def __init__(self):
16+
def __init__(self) -> None:
1717
super().__init__()
1818

1919
self.define_holiday() \

src/holidata/holidays/CO/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class CO(Country):
1313
languages = ["es"]
1414
easter_type = EASTER_WESTERN
1515

16-
def __init__(self):
16+
def __init__(self) -> None:
1717
super().__init__()
1818

1919
self.define_holiday() \

0 commit comments

Comments
 (0)