Skip to content

Commit

Permalink
Fix doc & type definitions in the entities module (#1220)
Browse files Browse the repository at this point in the history
  • Loading branch information
bonjourmauko authored Sep 18, 2024
2 parents 77cc91f + 7b37709 commit 00fe69a
Show file tree
Hide file tree
Showing 15 changed files with 190 additions and 123 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

### 41.5.5 [#1220](https://github.com/openfisca/openfisca-core/pull/1220)

#### Technical changes

- Fix doc & type definitions in the entities module

### 41.5.4 [#1219](https://github.com/openfisca/openfisca-core/pull/1219)

#### Technical changes
Expand Down
12 changes: 11 additions & 1 deletion openfisca_core/entities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,14 @@
from .helpers import build_entity, find_role
from .role import Role

__all__ = ["Entity", "GroupEntity", "Role", "build_entity", "find_role", "types"]
SingleEntity = Entity

__all__ = [
"Entity",
"SingleEntity",
"GroupEntity",
"Role",
"build_entity",
"find_role",
"types",
]
31 changes: 16 additions & 15 deletions openfisca_core/entities/_core_entity.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
from __future__ import annotations

from typing import Any

from openfisca_core.types import TaxBenefitSystem, Variable

import os
from abc import abstractmethod

from . import types as t
from .role import Role
from .types import Entity


class _CoreEntity:
"""Base class to build entities from."""

#: A key to identify the entity.
key: str

key: t.EntityKey
#: The ``key``, pluralised.
plural: str | None
plural: t.EntityPlural | None

#: A summary description.
label: str | None
Expand All @@ -30,31 +25,37 @@ class _CoreEntity:
is_person: bool

#: A TaxBenefitSystem instance.
_tax_benefit_system: TaxBenefitSystem | None = None
_tax_benefit_system: t.TaxBenefitSystem | None = None

@abstractmethod
def __init__(self, key: str, plural: str, label: str, doc: str, *args: Any) -> None:
def __init__(
self, key: str, plural: str, label: str, doc: str, *args: object
) -> None:
...

def __repr__(self) -> str:
return f"{self.__class__.__name__}({self.key})"

def set_tax_benefit_system(self, tax_benefit_system: TaxBenefitSystem) -> None:
def set_tax_benefit_system(self, tax_benefit_system: t.TaxBenefitSystem) -> None:
"""An Entity belongs to a TaxBenefitSystem."""
self._tax_benefit_system = tax_benefit_system

def get_variable(
self,
variable_name: str,
check_existence: bool = False,
) -> Variable | None:
) -> t.Variable | None:
"""Get a ``variable_name`` from ``variables``."""
if self._tax_benefit_system is None:
raise ValueError(
"You must set 'tax_benefit_system' before calling this method."
)
return self._tax_benefit_system.get_variable(variable_name, check_existence)

def check_variable_defined_for_entity(self, variable_name: str) -> None:
"""Check if ``variable_name`` is defined for ``self``."""
variable: Variable | None
entity: Entity
variable: t.Variable | None
entity: t.CoreEntity

variable = self.get_variable(variable_name, check_existence=True)

Expand All @@ -71,7 +72,7 @@ def check_variable_defined_for_entity(self, variable_name: str) -> None:
)
raise ValueError(os.linesep.join(message))

def check_role_validity(self, role: Any) -> None:
def check_role_validity(self, role: object) -> None:
"""Check if a ``role`` is an instance of Role."""
if role is not None and not isinstance(role, Role):
raise ValueError(f"{role} is not a valid role")
5 changes: 3 additions & 2 deletions openfisca_core/entities/entity.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import textwrap

from . import types as t
from ._core_entity import _CoreEntity


Expand All @@ -9,8 +10,8 @@ class Entity(_CoreEntity):
"""

def __init__(self, key: str, plural: str, label: str, doc: str) -> None:
self.key = key
self.key = t.EntityKey(key)
self.label = label
self.plural = plural
self.plural = t.EntityPlural(plural)
self.doc = textwrap.dedent(doc)
self.is_person = True
10 changes: 5 additions & 5 deletions openfisca_core/entities/group_entity.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from __future__ import annotations

from collections.abc import Iterable, Mapping
from typing import Any
from collections.abc import Iterable, Sequence

import textwrap
from itertools import chain

from . import types as t
from ._core_entity import _CoreEntity
from .role import Role

Expand Down Expand Up @@ -34,12 +34,12 @@ def __init__(
plural: str,
label: str,
doc: str,
roles: Iterable[Mapping[str, Any]],
roles: Sequence[t.RoleParams],
containing_entities: Iterable[str] = (),
) -> None:
self.key = key
self.key = t.EntityKey(key)
self.label = label
self.plural = plural
self.plural = t.EntityPlural(plural)
self.doc = textwrap.dedent(doc)
self.is_person = False
self.roles_description = roles
Expand Down
33 changes: 18 additions & 15 deletions openfisca_core/entities/helpers.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
from __future__ import annotations

from typing import Iterable
from collections.abc import Iterable, Sequence
from typing import Optional

from . import types as t
from .entity import Entity
from .group_entity import GroupEntity
from .types import Role


def build_entity(
key,
plural,
label,
doc="",
roles=None,
is_person=False,
class_override=None,
containing_entities=(),
):
key: str,
plural: str,
label: str,
doc: str = "",
roles: Optional[Sequence[t.RoleParams]] = None,
is_person: bool = False,
class_override: object | None = None,
containing_entities: Sequence[str] = (),
) -> t.SingleEntity | t.GroupEntity:
"""Build a SingleEntity or a GroupEntity.
Args:
Expand All @@ -35,7 +36,7 @@ def build_entity(
:obj:`.GroupEntity`: When ``is_person`` is False.
Raises:
ValueError if ``roles`` is not a sequence.
NotImplementedError: if ``roles`` is None.
Examples:
>>> from openfisca_core import entities
Expand Down Expand Up @@ -73,15 +74,17 @@ def build_entity(
if is_person:
return Entity(key, plural, label, doc)

else:
if roles is not None:
return GroupEntity(
key, plural, label, doc, roles, containing_entities=containing_entities
)

raise NotImplementedError


def find_role(
roles: Iterable[Role], key: str, *, total: int | None = None
) -> Role | None:
roles: Iterable[t.Role], key: t.RoleKey, *, total: int | None = None
) -> t.Role | None:
"""Find a Role in a GroupEntity.
Args:
Expand Down
6 changes: 3 additions & 3 deletions openfisca_core/entities/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import dataclasses
import textwrap

from .types import Entity
from .types import SingleEntity


class Role:
Expand Down Expand Up @@ -48,7 +48,7 @@ class Role:
"""

#: The Entity the Role belongs to.
entity: Entity
entity: SingleEntity

#: A description of the Role.
description: _Description
Expand Down Expand Up @@ -79,7 +79,7 @@ def doc(self) -> str | None:
"""A full description, non-indented."""
return self.description.doc

def __init__(self, description: Mapping[str, Any], entity: Entity) -> None:
def __init__(self, description: Mapping[str, Any], entity: SingleEntity) -> None:
self.description = _Description(
**{
key: value
Expand Down
51 changes: 41 additions & 10 deletions openfisca_core/entities/types.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,61 @@
from __future__ import annotations

from collections.abc import Iterable
from typing import Protocol, TypedDict
from typing import NewType, Protocol
from typing_extensions import Required, TypedDict

from openfisca_core import types as t

class Entity(Protocol):
# Entities

#: For example "person".
EntityKey = NewType("EntityKey", str)

#: For example "persons".
EntityPlural = NewType("EntityPlural", str)

#: For example "principal".
RoleKey = NewType("RoleKey", str)

#: For example "parents".
RolePlural = NewType("RolePlural", str)


class CoreEntity(t.CoreEntity, Protocol):
key: EntityKey
plural: EntityPlural | None


class SingleEntity(t.SingleEntity, Protocol):
...


class GroupEntity(Protocol):
class GroupEntity(t.GroupEntity, Protocol):
...


class Role(Protocol):
max: int | None
class Role(t.Role, Protocol):
subroles: Iterable[Role] | None

@property
def key(self) -> str:
...


class RoleParams(TypedDict, total=False):
key: str
key: Required[str]
plural: str
label: str
doc: str
max: int
subroles: list[str]


# Tax-Benefit systems


class TaxBenefitSystem(t.TaxBenefitSystem, Protocol):
...


# Variables


class Variable(t.Variable, Protocol):
...
6 changes: 3 additions & 3 deletions openfisca_core/populations/population.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import Dict, NamedTuple, Optional, Sequence, Union
from typing_extensions import TypedDict

from openfisca_core.types import Array, Entity, Period, Role, Simulation
from openfisca_core.types import Array, Period, Role, Simulation, SingleEntity

import traceback

Expand All @@ -16,12 +16,12 @@

class Population:
simulation: Optional[Simulation]
entity: Entity
entity: SingleEntity
_holders: Dict[str, holders.Holder]
count: int
ids: Array[str]

def __init__(self, entity: Entity) -> None:
def __init__(self, entity: SingleEntity) -> None:
self.simulation = None
self.entity = entity
self._holders = {}
Expand Down
4 changes: 2 additions & 2 deletions openfisca_core/projectors/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from collections.abc import Mapping

from openfisca_core.entities.types import Entity, GroupEntity, Role
from openfisca_core.types import GroupEntity, Role, SingleEntity

from openfisca_core import entities, projectors

Expand Down Expand Up @@ -110,7 +110,7 @@ def get_projector_from_shortcut(
"""

entity: Entity | GroupEntity = population.entity
entity: SingleEntity | GroupEntity = population.entity

if isinstance(entity, entities.Entity):
populations: Mapping[
Expand Down
4 changes: 2 additions & 2 deletions openfisca_core/projectors/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from collections.abc import Mapping
from typing import Protocol

from openfisca_core.entities.types import Entity, GroupEntity
from openfisca_core.types import GroupEntity, SingleEntity


class Population(Protocol):
@property
def entity(self) -> Entity:
def entity(self) -> SingleEntity:
...

@property
Expand Down
Loading

0 comments on commit 00fe69a

Please sign in to comment.