Skip to content

Commit a7af216

Browse files
author
Mauko Quiroga
committed
[SPLIT]
1 parent af3636b commit a7af216

File tree

15 files changed

+1301
-462
lines changed

15 files changed

+1301
-462
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ check-style: \
5252
check-style-doc-commons \
5353
check-style-doc-entities \
5454
check-style-doc-indexed_enums \
55+
check-style-doc-periods \
5556
check-style-doc-types
5657
@$(call pass,$@:)
5758

@@ -72,6 +73,7 @@ check-types: \
7273
check-types-strict-commons \
7374
check-types-strict-entities \
7475
check-types-strict-indexed_enums \
76+
check-types-strict-periods \
7577
check-types-strict-types
7678
@$(call pass,$@:)
7779

openfisca_core/periods/__init__.py

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,50 @@
2121
#
2222
# See: https://www.python.org/dev/peps/pep-0008/#imports
2323

24-
from .config import ( # noqa: F401
25-
DAY,
26-
MONTH,
27-
YEAR,
28-
ETERNITY,
29-
INSTANT_PATTERN,
30-
date_by_instant_cache,
31-
str_by_instant_cache,
32-
year_or_month_or_day_re,
33-
)
24+
from typing import Any, Dict
25+
26+
from .config import INSTANT_PATTERN, YEAR_OR_MONTH_OR_DAY_RE, DATE, LAST # noqa: F401
27+
from .instant_ import Instant # noqa: F401
28+
from .period_ import Period # noqa: F401
29+
from .date_unit import DateUnit # noqa: F401
3430

3531
from .helpers import ( # noqa: F401
3632
N_,
3733
instant,
3834
instant_date,
39-
period,
4035
key_period_size,
41-
unit_weights,
42-
unit_weight,
36+
period,
4337
)
4438

45-
from .instant_ import Instant # noqa: F401
46-
from .period_ import Period # noqa: F401
39+
# For backwards compatibility
40+
41+
from .helpers import unit_weight, unit_weights # noqa: F401
42+
43+
for item in DateUnit:
44+
globals()[item.name.upper()] = item.value
45+
46+
str_by_instant_cache: Dict[Any, Any] = {}
47+
"""Cache to store :obj:`str` reprentations of :obj:`.Instant`.
48+
49+
.. deprecated:: 35.9.0
50+
This cache has been deprecated and will be removed in the future. The
51+
functionality is now provided by :func:`functools.lru_cache`.
52+
53+
"""
54+
55+
date_by_instant_cache: Dict[Any, Any] = {}
56+
"""Cache to store :obj:`datetime.date` reprentations of :obj:`.Instant`.
57+
58+
.. deprecated:: 35.9.0
59+
This cache has been deprecated and will be removed in the future. The
60+
functionality is now provided by :func:`functools.lru_cache`.
61+
62+
"""
63+
64+
year_or_month_or_day_re = YEAR_OR_MONTH_OR_DAY_RE
65+
"""???
66+
67+
.. deprecated:: 35.9.0
68+
??? has been deprecated and it will be removed in 36.0.0.
69+
70+
"""

openfisca_core/periods/config.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
1+
import calendar
2+
import datetime
3+
import functools
14
import re
2-
import typing
5+
from typing import Pattern
36

4-
DAY = 'day'
5-
MONTH = 'month'
6-
YEAR = 'year'
7-
ETERNITY = 'eternity'
7+
INSTANT_PATTERN: Pattern = re.compile(r"^\d{4}(-(0[1-9]|1[012]))?(-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))?$")
8+
"""Pattern to validate a valid :obj:`.Instant`.
89
9-
# Matches "2015", "2015-01", "2015-01-01"
10-
# Does not match "2015-13", "2015-12-32"
11-
INSTANT_PATTERN = re.compile(r"^\d{4}(-(0[1-9]|1[012]))?(-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))?$")
10+
Matches: "2015", "2015-01", "2015-01-01"…
11+
Does not match: "2015-13", "2015-12-32"…
1212
13-
date_by_instant_cache: typing.Dict = {}
14-
str_by_instant_cache: typing.Dict = {}
15-
year_or_month_or_day_re = re.compile(r'(18|19|20)\d{2}(-(0?[1-9]|1[0-2])(-([0-2]?\d|3[0-1]))?)?$')
13+
"""
14+
15+
YEAR_OR_MONTH_OR_DAY_RE: Pattern = re.compile(r"(18|19|20)\d{2}(-(0?[1-9]|1[0-2])(-([0-2]?\d|3[0-1]))?)?$")
16+
"""???
17+
18+
.. deprecated:: 35.9.0
19+
??? has been deprecated and it will be removed in 36.0.0.
20+
21+
"""
22+
23+
DATE = functools.lru_cache(maxsize = None)(datetime.date)
24+
"""A memoized date constructor."""
25+
26+
LAST = functools.lru_cache(maxsize = None)(calendar.monthrange)
27+
"""A memoized date range constructor, useful for last-of month offsets."""
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
from __future__ import annotations
2+
3+
import enum
4+
from typing import Any, Tuple, TypeVar
5+
6+
from openfisca_core.indexed_enums import Enum
7+
8+
T = TypeVar("T", bound = "DateUnit")
9+
10+
11+
class DateUnitMeta(enum.EnumMeta):
12+
13+
def __contains__(self, item: Any) -> bool:
14+
if isinstance(item, str):
15+
return super().__contains__(self[item.upper()])
16+
17+
return super().__contains__(item)
18+
19+
def __getitem__(self, key: object) -> T:
20+
if not isinstance(key, (int, slice, str, DateUnit)):
21+
return NotImplemented
22+
23+
if isinstance(key, (int, slice)):
24+
return self[self.__dict__["_member_names_"][key]]
25+
26+
if isinstance(key, str):
27+
return super().__getitem__(key.upper())
28+
29+
return super().__getitem__(key.value.upper())
30+
31+
@property
32+
def ethereal(self) -> Tuple[DateUnit, ...]:
33+
"""Creates a :obj:`tuple` of ``key`` with ethereal items.
34+
35+
Returns:
36+
tuple(str): A :obj:`tuple` containing the ``keys``.
37+
38+
Examples:
39+
>>> DateUnit.ethereal
40+
(<DateUnit.DAY(day)>, <DateUnit.MONTH(month)>, <DateUnit.YEAR(year)>)
41+
42+
>>> DateUnit.DAY in DateUnit.ethereal
43+
True
44+
45+
>>> "DAY" in DateUnit.ethereal
46+
True
47+
48+
>>> "day" in DateUnit.ethereal
49+
True
50+
51+
>>> "eternity" in DateUnit.ethereal
52+
False
53+
54+
"""
55+
56+
return DateUnit.DAY, DateUnit.MONTH, DateUnit.YEAR
57+
58+
@property
59+
def eternal(self) -> Tuple[DateUnit, ...]:
60+
"""Creates a :obj:`tuple` of ``key`` with eternal items.
61+
62+
Returns:
63+
tuple(str): A :obj:`tuple` containing the ``keys``.
64+
65+
Examples:
66+
>>> DateUnit.eternal
67+
(<DateUnit.ETERNITY(eternity)>,)
68+
69+
>>> DateUnit.ETERNITY in DateUnit.eternal
70+
True
71+
72+
>>> "ETERNITY" in DateUnit.eternal
73+
True
74+
75+
>>> "eternity" in DateUnit.eternal
76+
True
77+
78+
>>> "day" in DateUnit.eternal
79+
False
80+
81+
"""
82+
83+
return (DateUnit.ETERNITY,)
84+
85+
86+
class DateUnit(Enum, metaclass = DateUnitMeta):
87+
"""The date units of a rule system.
88+
89+
Attributes:
90+
index (:obj:`int`): The ``index`` of each item.
91+
name (:obj:`str`): The ``name`` of each item.
92+
value (tuple(str, int)): The ``value`` of each item.
93+
94+
Examples:
95+
>>> repr(DateUnit)
96+
"<enum 'DateUnit'>"
97+
98+
>>> repr(DateUnit.DAY)
99+
'<DateUnit.DAY(day)>'
100+
101+
>>> str(DateUnit.DAY)
102+
'DateUnit.DAY'
103+
104+
>>> dict([(DateUnit.DAY, DateUnit.DAY.value)])
105+
{<DateUnit.DAY(day)>: 'day'}
106+
107+
>>> tuple(DateUnit)
108+
(<DateUnit.WEEK_DAY(week_day)>, <DateUnit.WEEK(week)>, <DateUnit.DA...)
109+
110+
>>> len(DateUnit)
111+
6
112+
113+
>>> DateUnit["DAY"]
114+
<DateUnit.DAY(day)>
115+
116+
>>> DateUnit["day"]
117+
<DateUnit.DAY(day)>
118+
119+
>>> DateUnit[2]
120+
<DateUnit.DAY(day)>
121+
122+
>>> DateUnit[-4]
123+
<DateUnit.DAY(day)>
124+
125+
>>> DateUnit[DateUnit.DAY]
126+
<DateUnit.DAY(day)>
127+
128+
>>> DateUnit("day")
129+
<DateUnit.DAY(day)>
130+
131+
>>> DateUnit.DAY in DateUnit
132+
True
133+
134+
>>> "DAY" in DateUnit
135+
True
136+
137+
>>> "day" in DateUnit
138+
True
139+
140+
>>> DateUnit.DAY == DateUnit.DAY
141+
True
142+
143+
>>> "DAY" == DateUnit.DAY
144+
True
145+
146+
>>> "day" == DateUnit.DAY
147+
True
148+
149+
>>> DateUnit.DAY < DateUnit.DAY
150+
False
151+
152+
>>> DateUnit.DAY > DateUnit.DAY
153+
False
154+
155+
>>> DateUnit.DAY <= DateUnit.DAY
156+
True
157+
158+
>>> DateUnit.DAY >= DateUnit.DAY
159+
True
160+
161+
>>> "DAY" < DateUnit.DAY
162+
False
163+
164+
>>> "DAY" > DateUnit.DAY
165+
False
166+
167+
>>> "DAY" <= DateUnit.DAY
168+
True
169+
170+
>>> "DAY" >= DateUnit.DAY
171+
True
172+
173+
>>> "day" < DateUnit.DAY
174+
False
175+
176+
>>> "day" > DateUnit.DAY
177+
False
178+
179+
>>> "day" <= DateUnit.DAY
180+
True
181+
182+
>>> "day" >= DateUnit.DAY
183+
True
184+
185+
>>> DateUnit.DAY.index
186+
2
187+
188+
>>> DateUnit.DAY.name
189+
'DAY'
190+
191+
>>> DateUnit.DAY.value
192+
'day'
193+
194+
.. versionadded:: 35.9.0
195+
196+
"""
197+
198+
# Attributes
199+
200+
index: int
201+
name: str
202+
value: str
203+
204+
# Members
205+
206+
WEEK_DAY = "week_day"
207+
WEEK = "week"
208+
DAY = "day"
209+
MONTH = "month"
210+
YEAR = "year"
211+
ETERNITY = "eternity"
212+
213+
__hash__ = object.__hash__
214+
215+
def __eq__(self, other):
216+
if isinstance(other, str):
217+
return self.value == other.lower()
218+
219+
return NotImplemented
220+
221+
def __lt__(self, other: Any) -> bool:
222+
if isinstance(other, str):
223+
return self.index < DateUnit[other.upper()].index
224+
225+
return self.index < other
226+
227+
def __le__(self, other: Any) -> bool:
228+
if isinstance(other, str):
229+
return self.index <= DateUnit[other.upper()].index
230+
231+
return self.index <= other
232+
233+
def __gt__(self, other: Any) -> bool:
234+
if isinstance(other, str):
235+
return self.index > DateUnit[other.upper()].index
236+
237+
return self.index > other
238+
239+
def __ge__(self, other: Any) -> bool:
240+
if isinstance(other, str):
241+
return self.index >= DateUnit[other.upper()].index
242+
243+
return self.index >= other
244+
245+
def upper(self) -> str:
246+
"""Uppercases the :class:`.Unit`.
247+
248+
Returns:
249+
:obj:`str`: The uppercased :class:`.Unit`.
250+
251+
Examples:
252+
>>> DateUnit.DAY.upper()
253+
'DAY'
254+
255+
"""
256+
257+
return self.value.upper()
258+
259+
def lower(self) -> str:
260+
"""Lowecases the :class:`.Unit`.
261+
262+
Returns:
263+
:obj:`str`: The lowercased :class:`.Unit`.
264+
265+
Examples:
266+
>>> DateUnit.DAY.lower()
267+
'day'
268+
269+
"""
270+
271+
return self.value.lower()

0 commit comments

Comments
 (0)