Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: fix doc & type definitions in the entities module #1220

Merged
merged 3 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading