Skip to content
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.4.1 [#1202](https://github.com/openfisca/openfisca-core/pull/1202)

#### Technical changes

- Check that entities are fully specified when expanding over axes.

## 41.4.0 [#1197](https://github.com/openfisca/openfisca-core/pull/1197)

#### New features
Expand Down
10 changes: 8 additions & 2 deletions openfisca_core/errors/situation_parsing_error.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from __future__ import annotations

from collections.abc import Iterable

import os

import dpath.util
Expand All @@ -8,13 +12,15 @@ class SituationParsingError(Exception):
Exception raised when the situation provided as an input for a simulation cannot be parsed
"""

def __init__(self, path, message, code=None):
def __init__(
self, path: Iterable[str], message: str, code: int | None = None
) -> None:
self.error = {}
dpath_path = "/".join([str(item) for item in path])
message = str(message).strip(os.linesep).replace(os.linesep, " ")
dpath.util.new(self.error, dpath_path, message)
self.code = code
Exception.__init__(self, str(self.error))

def __str__(self):
def __str__(self) -> str:
return str(self.error)
162 changes: 162 additions & 0 deletions openfisca_core/simulations/_build_default_simulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
"""This module contains the _BuildDefaultSimulation class."""

from typing import Union
from typing_extensions import Self

import numpy

from .simulation import Simulation
from .typing import Entity, Population, TaxBenefitSystem


class _BuildDefaultSimulation:
"""Build a default simulation.

Args:
tax_benefit_system(TaxBenefitSystem): The tax-benefit system.
count(int): The number of periods.

Examples:
>>> from openfisca_core import entities, taxbenefitsystems

>>> role = {"key": "stray", "plural": "stray", "label": "", "doc": ""}
>>> single_entity = entities.Entity("dog", "dogs", "", "")
>>> group_entity = entities.GroupEntity("pack", "packs", "", "", [role])
>>> test_entities = [single_entity, group_entity]
>>> tax_benefit_system = taxbenefitsystems.TaxBenefitSystem(test_entities)
>>> count = 1
>>> builder = (
... _BuildDefaultSimulation(tax_benefit_system, count)
... .add_count()
... .add_ids()
... .add_members_entity_id()
... )

>>> builder.count
1

>>> sorted(builder.populations.keys())
['dog', 'pack']

>>> sorted(builder.simulation.populations.keys())
['dog', 'pack']

"""

#: The number of Population.
count: int

#: The built populations.
populations: dict[str, Union[Population[Entity]]]

#: The built simulation.
simulation: Simulation

def __init__(self, tax_benefit_system: TaxBenefitSystem, count: int) -> None:
self.count = count
self.populations = tax_benefit_system.instantiate_entities()
self.simulation = Simulation(tax_benefit_system, self.populations)

def add_count(self) -> Self:
"""Add the number of Population to the simulation.

Returns:
_BuildDefaultSimulation: The builder.

Examples:
>>> from openfisca_core import entities, taxbenefitsystems

>>> role = {"key": "stray", "plural": "stray", "label": "", "doc": ""}
>>> single_entity = entities.Entity("dog", "dogs", "", "")
>>> group_entity = entities.GroupEntity("pack", "packs", "", "", [role])
>>> test_entities = [single_entity, group_entity]
>>> tax_benefit_system = taxbenefitsystems.TaxBenefitSystem(test_entities)
>>> count = 2
>>> builder = _BuildDefaultSimulation(tax_benefit_system, count)

>>> builder.add_count()
<..._BuildDefaultSimulation object at ...>

>>> builder.populations["dog"].count
2

>>> builder.populations["pack"].count
2

"""

for population in self.populations.values():
population.count = self.count

return self

def add_ids(self) -> Self:
"""Add the populations ids to the simulation.

Returns:
_BuildDefaultSimulation: The builder.

Examples:
>>> from openfisca_core import entities, taxbenefitsystems

>>> role = {"key": "stray", "plural": "stray", "label": "", "doc": ""}
>>> single_entity = entities.Entity("dog", "dogs", "", "")
>>> group_entity = entities.GroupEntity("pack", "packs", "", "", [role])
>>> test_entities = [single_entity, group_entity]
>>> tax_benefit_system = taxbenefitsystems.TaxBenefitSystem(test_entities)
>>> count = 2
>>> builder = _BuildDefaultSimulation(tax_benefit_system, count)

>>> builder.add_ids()
<..._BuildDefaultSimulation object at ...>

>>> builder.populations["dog"].ids
array([0, 1])

>>> builder.populations["pack"].ids
array([0, 1])

"""

for population in self.populations.values():
population.ids = numpy.array(range(self.count))

return self

def add_members_entity_id(self) -> Self:
"""Add ???

Each SingleEntity has its own GroupEntity.

Returns:
_BuildDefaultSimulation: The builder.

Examples:
>>> from openfisca_core import entities, taxbenefitsystems

>>> role = {"key": "stray", "plural": "stray", "label": "", "doc": ""}
>>> single_entity = entities.Entity("dog", "dogs", "", "")
>>> group_entity = entities.GroupEntity("pack", "packs", "", "", [role])
>>> test_entities = [single_entity, group_entity]
>>> tax_benefit_system = taxbenefitsystems.TaxBenefitSystem(test_entities)
>>> count = 2
>>> builder = _BuildDefaultSimulation(tax_benefit_system, count)

>>> builder.add_members_entity_id()
<..._BuildDefaultSimulation object at ...>

>>> population = builder.populations["pack"]

>>> hasattr(population, "members_entity_id")
True

>>> population.members_entity_id
array([0, 1])

"""

for population in self.populations.values():
if hasattr(population, "members_entity_id"):
population.members_entity_id = numpy.array(range(self.count))

return self
Loading