-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6783cb6
commit 3a147bd
Showing
21 changed files
with
1,744 additions
and
446 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,94 @@ | ||
# Transitional imports to ensure non-breaking changes. | ||
# Could be deprecated in the next major release. | ||
# | ||
# How imports are being used today: | ||
# | ||
# >>> from openfisca_core.module import symbol | ||
# | ||
# The previous example provokes cyclic dependency problems | ||
# that prevent us from modularizing the different components | ||
# of the library so to make them easier to test and to maintain. | ||
# | ||
# How could them be used after the next major release: | ||
# | ||
# >>> from openfisca_core import module | ||
# >>> module.symbol() | ||
# | ||
# And for classes: | ||
# | ||
# >>> from openfisca_core import module | ||
# >>> module.Symbol() | ||
# | ||
# See: https://www.python.org/dev/peps/pep-0008/#imports | ||
|
||
from . import types | ||
from .entity import Entity | ||
from .group_entity import GroupEntity | ||
from .helpers import build_entity, find_role | ||
from .role import Role | ||
|
||
SingleEntity = Entity | ||
|
||
__all__ = [ | ||
"Entity", | ||
"SingleEntity", | ||
"GroupEntity", | ||
"Role", | ||
"build_entity", | ||
"find_role", | ||
"types", | ||
] | ||
"""Provides a way of representing the entities of a rule system. | ||
Each rule system is comprised by legislation and regulations to be applied upon | ||
"someone". In legal and economical terms, "someone" is referred to as people: | ||
individuals, families, tax households, companies, and so on. | ||
People can be either human or non-human, that is a legal entity, also referred | ||
to as a legal person. Human or non-human, a person is an atomic element of a | ||
rule system: for example, in most legislations, a salary is invariably owed | ||
to an indivual, and payroll taxes by a company, as a juridical person. In | ||
OpenFisca, that atomic element is represented as an :class:`.Entity`. | ||
In other cases, legal and regulatory rules are defined for groups or clusters | ||
of people: for example, income tax is usually due by a tax household, that is | ||
a group of individuals. There may also be fiduciary entities where the members, | ||
legal entities, are collectively liable for a property tax. In OpenFisca, those | ||
cluster elements are represented as a :class:`.GroupEntity`. | ||
In the latter case, the atomic members of a given group may have a different | ||
:class:`Role` in the context of a specific rule: for example, income tax | ||
is due, in some legislations, by a tax household, where we find different | ||
roles as the declarant, the spouse, the children, and so on… | ||
What's important is that each rule, or in OpenFisca, a :class:`.Variable`, | ||
is defined either for an :class:`.Entity` or for a :class:`.GroupEntity`, | ||
and in the latter case, the way the rule is going to be applied depends | ||
on the attributes and roles of the members of the group. | ||
Finally, there is a distiction to be made between the "abstract" entities | ||
described by in a rule system, for example an individual, as in "any" | ||
individual, and an actual individual, like Mauko, Andrea, Mehdi, Seiko, | ||
or José. | ||
This module provides tools for modelling the former. For the actual | ||
"simulation" or "application" of any given :class:`.Variable` to a | ||
concrete individual or group of individuals, see :class:`.Population` | ||
and :class:`.GroupPopulation`. | ||
Official Public API: | ||
* :class:`.Entity` | ||
* :class:`.GroupEntity` | ||
* :class:`.Role` | ||
* :func:`.build_entity` | ||
* :func:`.check_role_validity` | ||
Deprecated: | ||
* :meth:`.Entity.set_tax_benefit_system` | ||
* :meth:`.Entity.get_variable` | ||
* :meth:`.Entity.check_variable_defined_for_entity` | ||
* :meth:`.Entity.check_role_validity` | ||
Note: | ||
The ``deprecated`` features are kept so as to give time to users to | ||
migrate, and could be definitely removed from the codebase in a future | ||
major release. | ||
Note: | ||
How imports are being used today:: | ||
from openfisca_core.entities import * # Bad | ||
from openfisca_core.entities.helpers import build_entity # Bad | ||
from openfisca_core.entities.role import Role # Bad | ||
The previous examples provoke cyclic dependency problems, that prevents us | ||
from modularizing the different components of the library, so as to make | ||
them easier to test and to maintain. | ||
How could them be used after the next major release:: | ||
from openfisca_core import entities | ||
from openfisca_core.entities import Role | ||
Role() # Good: import classes as publicly exposed | ||
entities.build_entity() # Good: use functions as publicly exposed | ||
.. seealso:: `PEP8#Imports`_ and `OpenFisca's Styleguide`_. | ||
.. _PEP8#Imports: | ||
https://www.python.org/dev/peps/pep-0008/#imports | ||
.. _OpenFisca's Styleguide: | ||
https://github.com/openfisca/openfisca-core/blob/master/STYLEGUIDE.md | ||
""" | ||
|
||
# Official Public API | ||
|
||
from .entity import Entity # noqa: F401 | ||
from .group_entity import GroupEntity # noqa: F401 | ||
from .helpers import build_entity, check_role_validity # noqa: F401 | ||
from .role import Role # noqa: F401 | ||
|
||
__all__ = ["Entity", "GroupEntity", "Role"] | ||
__all__ = ["build_entity", "check_role_validity", *__all__] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Iterable, Optional, Sequence, Type | ||
|
||
from openfisca_core.types import HasPlural, RoleLike, SupportsRole | ||
|
||
import dataclasses | ||
|
||
|
||
@dataclasses.dataclass(frozen=True) | ||
class RoleBuilder: | ||
"""Builds roles & sub-roles from a given input. | ||
Attributes: | ||
builder (:obj:`.Entity` or :obj:`.GroupEntity`): | ||
A builder object. | ||
buildee (:obj:`.Role`): | ||
The objects to be built. | ||
Args: | ||
builder: A builder object. | ||
buildee: The objects to be built. | ||
Examples: | ||
>>> from openfisca_core.entities import GroupEntity, Role | ||
>>> group_entity = GroupEntity( | ||
... "household", | ||
... "households", | ||
... "A household", | ||
... "All the people who live together in the same place.", | ||
... [] | ||
... ) | ||
>>> items = [{ | ||
... "key": "parent", | ||
... "subroles": ["first_parent", "second_parent"], | ||
... }] | ||
>>> builder = RoleBuilder(group_entity, Role) | ||
>>> repr(RoleBuilder) | ||
"<class 'openfisca_core.entities._role_builder.RoleBuilder'>" | ||
>>> repr(builder) | ||
"<RoleBuilder(households, <class '...Role'>)>" | ||
>>> str(builder) | ||
"<RoleBuilder(households, <class '...Role'>)>" | ||
>>> builder(items) | ||
(<Role(parent)>,) | ||
.. versionadded:: 35.7.0 | ||
""" | ||
|
||
__slots__ = ["builder", "buildee"] | ||
builder: HasPlural | ||
buildee: Type[SupportsRole] | ||
|
||
def __repr__(self) -> str: | ||
return f"<{self.__class__.__name__}({self.builder}, {self.buildee})>" | ||
|
||
def __call__(self, items: Iterable[RoleLike]) -> Sequence[SupportsRole]: | ||
"""Builds a sub/role for each item in ``items``. | ||
Args: | ||
items: Role-like items, see :class:`.RoleLike`. | ||
Returns: | ||
A :obj:`list` of :obj:`.Role`. | ||
.. versionadded:: 35.7.0 | ||
""" | ||
|
||
return tuple(self.build(item) for item in items) | ||
|
||
def build(self, item: RoleLike) -> SupportsRole: | ||
"""Builds a role from ``item``. | ||
Args: | ||
item: A role-like item, see :class:`.RoleLike`. | ||
Returns: | ||
:obj:`.Role`: A :obj:`.Role`. | ||
.. versionadded:: 35.7.0 | ||
""" | ||
|
||
role: SupportsRole | ||
subroles: Optional[Iterable[str]] | ||
|
||
role = self.buildee(item, self.builder) | ||
subroles = item.get("subroles", []) | ||
|
||
if subroles: | ||
role.subroles = [ | ||
self.build(RoleLike({"key": key, "max": 1})) for key in subroles | ||
] | ||
role.max = len(role.subroles) | ||
|
||
return role |
Oops, something went wrong.