Skip to content

Commit

Permalink
[SPLIT]
Browse files Browse the repository at this point in the history
  • Loading branch information
Mauko Quiroga committed Sep 21, 2021
1 parent 1e88559 commit 6f4a04f
Show file tree
Hide file tree
Showing 15 changed files with 1,301 additions and 462 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ check-style: \
check-style-doc-commons \
check-style-doc-entities \
check-style-doc-indexed_enums \
check-style-doc-periods \
check-style-doc-types
@$(call pass,$@:)

Expand All @@ -72,6 +73,7 @@ check-types: \
check-types-strict-commons \
check-types-strict-entities \
check-types-strict-indexed_enums \
check-types-strict-periods \
check-types-strict-types
@$(call pass,$@:)

Expand Down
54 changes: 39 additions & 15 deletions openfisca_core/periods/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,50 @@
#
# See: https://www.python.org/dev/peps/pep-0008/#imports

from .config import ( # noqa: F401
DAY,
MONTH,
YEAR,
ETERNITY,
INSTANT_PATTERN,
date_by_instant_cache,
str_by_instant_cache,
year_or_month_or_day_re,
)
from typing import Any, Dict

from .config import INSTANT_PATTERN, YEAR_OR_MONTH_OR_DAY_RE, DATE, LAST # noqa: F401
from .instant_ import Instant # noqa: F401
from .period_ import Period # noqa: F401
from .date_unit import DateUnit # noqa: F401

from .helpers import ( # noqa: F401
N_,
instant,
instant_date,
period,
key_period_size,
unit_weights,
unit_weight,
period,
)

from .instant_ import Instant # noqa: F401
from .period_ import Period # noqa: F401
# For backwards compatibility

from .helpers import unit_weight, unit_weights # noqa: F401

for item in DateUnit:
globals()[item.name.upper()] = item.value

str_by_instant_cache: Dict[Any, Any] = {}
"""Cache to store :obj:`str` reprentations of :obj:`.Instant`.
.. deprecated:: 35.9.0
This cache has been deprecated and will be removed in the future. The
functionality is now provided by :func:`functools.lru_cache`.
"""

date_by_instant_cache: Dict[Any, Any] = {}
"""Cache to store :obj:`datetime.date` reprentations of :obj:`.Instant`.
.. deprecated:: 35.9.0
This cache has been deprecated and will be removed in the future. The
functionality is now provided by :func:`functools.lru_cache`.
"""

year_or_month_or_day_re = YEAR_OR_MONTH_OR_DAY_RE
"""???
.. deprecated:: 35.9.0
??? has been deprecated and it will be removed in 36.0.0.
"""
34 changes: 23 additions & 11 deletions openfisca_core/periods/config.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import calendar
import datetime
import functools
import re
import typing
from typing import Pattern

DAY = 'day'
MONTH = 'month'
YEAR = 'year'
ETERNITY = 'eternity'
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]))?$")
"""Pattern to validate a valid :obj:`.Instant`.
# Matches "2015", "2015-01", "2015-01-01"
# Does not match "2015-13", "2015-12-32"
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]))?$")
Matches: "2015", "2015-01", "2015-01-01"…
Does not match: "2015-13", "2015-12-32"…
date_by_instant_cache: typing.Dict = {}
str_by_instant_cache: typing.Dict = {}
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]))?)?$')
"""

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]))?)?$")
"""???
.. deprecated:: 35.9.0
??? has been deprecated and it will be removed in 36.0.0.
"""

DATE = functools.lru_cache(maxsize = None)(datetime.date)
"""A memoized date constructor."""

LAST = functools.lru_cache(maxsize = None)(calendar.monthrange)
"""A memoized date range constructor, useful for last-of month offsets."""
271 changes: 271 additions & 0 deletions openfisca_core/periods/date_unit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
from __future__ import annotations

import enum
from typing import Any, Tuple, TypeVar

from openfisca_core.indexed_enums import Enum

T = TypeVar("T", bound = "DateUnit")


class DateUnitMeta(enum.EnumMeta):

def __contains__(self, item: Any) -> bool:
if isinstance(item, str):
return super().__contains__(self[item.upper()])

return super().__contains__(item)

def __getitem__(self, key: object) -> T:
if not isinstance(key, (int, slice, str, DateUnit)):
return NotImplemented

if isinstance(key, (int, slice)):
return self[self.__dict__["_member_names_"][key]]

if isinstance(key, str):
return super().__getitem__(key.upper())

return super().__getitem__(key.value.upper())

@property
def ethereal(self) -> Tuple[DateUnit, ...]:
"""Creates a :obj:`tuple` of ``key`` with ethereal items.
Returns:
tuple(str): A :obj:`tuple` containing the ``keys``.
Examples:
>>> DateUnit.ethereal
(<DateUnit.DAY(day)>, <DateUnit.MONTH(month)>, <DateUnit.YEAR(year)>)
>>> DateUnit.DAY in DateUnit.ethereal
True
>>> "DAY" in DateUnit.ethereal
True
>>> "day" in DateUnit.ethereal
True
>>> "eternity" in DateUnit.ethereal
False
"""

return DateUnit.DAY, DateUnit.MONTH, DateUnit.YEAR

@property
def eternal(self) -> Tuple[DateUnit, ...]:
"""Creates a :obj:`tuple` of ``key`` with eternal items.
Returns:
tuple(str): A :obj:`tuple` containing the ``keys``.
Examples:
>>> DateUnit.eternal
(<DateUnit.ETERNITY(eternity)>,)
>>> DateUnit.ETERNITY in DateUnit.eternal
True
>>> "ETERNITY" in DateUnit.eternal
True
>>> "eternity" in DateUnit.eternal
True
>>> "day" in DateUnit.eternal
False
"""

return (DateUnit.ETERNITY,)


class DateUnit(Enum, metaclass = DateUnitMeta):
"""The date units of a rule system.
Attributes:
index (:obj:`int`): The ``index`` of each item.
name (:obj:`str`): The ``name`` of each item.
value (tuple(str, int)): The ``value`` of each item.
Examples:
>>> repr(DateUnit)
"<enum 'DateUnit'>"
>>> repr(DateUnit.DAY)
'<DateUnit.DAY(day)>'
>>> str(DateUnit.DAY)
'DateUnit.DAY'
>>> dict([(DateUnit.DAY, DateUnit.DAY.value)])
{<DateUnit.DAY(day)>: 'day'}
>>> tuple(DateUnit)
(<DateUnit.WEEK_DAY(week_day)>, <DateUnit.WEEK(week)>, <DateUnit.DA...)
>>> len(DateUnit)
6
>>> DateUnit["DAY"]
<DateUnit.DAY(day)>
>>> DateUnit["day"]
<DateUnit.DAY(day)>
>>> DateUnit[2]
<DateUnit.DAY(day)>
>>> DateUnit[-4]
<DateUnit.DAY(day)>
>>> DateUnit[DateUnit.DAY]
<DateUnit.DAY(day)>
>>> DateUnit("day")
<DateUnit.DAY(day)>
>>> DateUnit.DAY in DateUnit
True
>>> "DAY" in DateUnit
True
>>> "day" in DateUnit
True
>>> DateUnit.DAY == DateUnit.DAY
True
>>> "DAY" == DateUnit.DAY
True
>>> "day" == DateUnit.DAY
True
>>> DateUnit.DAY < DateUnit.DAY
False
>>> DateUnit.DAY > DateUnit.DAY
False
>>> DateUnit.DAY <= DateUnit.DAY
True
>>> DateUnit.DAY >= DateUnit.DAY
True
>>> "DAY" < DateUnit.DAY
False
>>> "DAY" > DateUnit.DAY
False
>>> "DAY" <= DateUnit.DAY
True
>>> "DAY" >= DateUnit.DAY
True
>>> "day" < DateUnit.DAY
False
>>> "day" > DateUnit.DAY
False
>>> "day" <= DateUnit.DAY
True
>>> "day" >= DateUnit.DAY
True
>>> DateUnit.DAY.index
2
>>> DateUnit.DAY.name
'DAY'
>>> DateUnit.DAY.value
'day'
.. versionadded:: 35.9.0
"""

# Attributes

index: int
name: str
value: str

# Members

WEEK_DAY = "week_day"
WEEK = "week"
DAY = "day"
MONTH = "month"
YEAR = "year"
ETERNITY = "eternity"

__hash__ = object.__hash__

def __eq__(self, other):
if isinstance(other, str):
return self.value == other.lower()

return NotImplemented

def __lt__(self, other: Any) -> bool:
if isinstance(other, str):
return self.index < DateUnit[other.upper()].index

return self.index < other

def __le__(self, other: Any) -> bool:
if isinstance(other, str):
return self.index <= DateUnit[other.upper()].index

return self.index <= other

def __gt__(self, other: Any) -> bool:
if isinstance(other, str):
return self.index > DateUnit[other.upper()].index

return self.index > other

def __ge__(self, other: Any) -> bool:
if isinstance(other, str):
return self.index >= DateUnit[other.upper()].index

return self.index >= other

def upper(self) -> str:
"""Uppercases the :class:`.Unit`.
Returns:
:obj:`str`: The uppercased :class:`.Unit`.
Examples:
>>> DateUnit.DAY.upper()
'DAY'
"""

return self.value.upper()

def lower(self) -> str:
"""Lowecases the :class:`.Unit`.
Returns:
:obj:`str`: The lowercased :class:`.Unit`.
Examples:
>>> DateUnit.DAY.lower()
'day'
"""

return self.value.lower()
Loading

0 comments on commit 6f4a04f

Please sign in to comment.