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

Test assert_near #1228

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## 42.0.0 [#1228](https://github.com/openfisca/openfisca-core/pull/1228)

#### New features

- Introduce `openfisca_test`.
- Provides `assert_near` and `parse` to prepare tests.

#### Technical changes

- Move `assert_near` to `openfisca_test`.
- Add tests to `assert_near`.

### 41.5.6 [#1185](https://github.com/openfisca/openfisca-core/pull/1185)

#### Technical changes
Expand Down
2 changes: 1 addition & 1 deletion STYLEGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ And avoid:

from openfisca_country_template.entities import Person
from openfisca_core import variables
from openfisca_core.tools import assert_near
from openfisca_test import assert_near
from openfisca_core import axes

from numpy import ndarray
Expand Down
3 changes: 2 additions & 1 deletion openfisca_core/holders/tests/test_helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest

from openfisca_core import holders, tools
import openfisca_test as tools
from openfisca_core import holders
from openfisca_core.entities import Entity
from openfisca_core.holders import Holder
from openfisca_core.periods import DateUnit, Instant, Period
Expand Down
2 changes: 1 addition & 1 deletion openfisca_core/scripts/measure_performances.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
from openfisca_core.entities import build_entity
from openfisca_core.periods import DateUnit
from openfisca_core.taxbenefitsystems import TaxBenefitSystem
from openfisca_core.tools import assert_near
from openfisca_core.variables import Variable
from openfisca_test import assert_near

args = None

Expand Down
67 changes: 6 additions & 61 deletions openfisca_core/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,67 +1,10 @@
from __future__ import annotations

import os

import numexpr

from openfisca_core.indexed_enums import EnumArray


def assert_near(
value,
target_value,
absolute_error_margin=None,
message="",
relative_error_margin=None,
):
""":param value: Value returned by the test
:param target_value: Value that the test should return to pass
:param absolute_error_margin: Absolute error margin authorized
:param message: Error message to be displayed if the test fails
:param relative_error_margin: Relative error margin authorized

Limit : This function cannot be used to assert near periods.

"""
import numpy

if absolute_error_margin is None and relative_error_margin is None:
absolute_error_margin = 0
if not isinstance(value, numpy.ndarray):
value = numpy.array(value)
if isinstance(value, EnumArray):
return assert_enum_equals(value, target_value, message)
if numpy.issubdtype(value.dtype, numpy.datetime64):
target_value = numpy.array(target_value, dtype=value.dtype)
assert_datetime_equals(value, target_value, message)
if isinstance(target_value, str):
target_value = eval_expression(target_value)

target_value = numpy.array(target_value).astype(numpy.float32)

value = numpy.array(value).astype(numpy.float32)
diff = abs(target_value - value)
if absolute_error_margin is not None:
assert (
diff <= absolute_error_margin
).all(), f"{message}{value} differs from {target_value} with an absolute margin {diff} > {absolute_error_margin}"
if relative_error_margin is not None:
assert (
diff <= abs(relative_error_margin * target_value)
).all(), f"{message}{value} differs from {target_value} with a relative margin {diff} > {abs(relative_error_margin * target_value)}"
return None
return None


def assert_datetime_equals(value, target_value, message="") -> None:
assert (
value == target_value
).all(), f"{message}{value} differs from {target_value}."


def assert_enum_equals(value, target_value, message="") -> None:
value = value.decode_to_str()
assert (
value == target_value
).all(), f"{message}{value} differs from {target_value}."
from openfisca_core import types as t


def indent(text):
Expand Down Expand Up @@ -89,7 +32,9 @@ def get_trace_tool_link(scenario, variables, api_url, trace_tool_url):
)


def eval_expression(expression):
def eval_expression(
expression: str,
) -> str | t.Array[t.ArrayBool | t.ArrayInt | t.ArrayFloat]:
try:
return numexpr.evaluate(expression)
except (KeyError, TypeError):
Expand Down
14 changes: 7 additions & 7 deletions openfisca_core/tools/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

from openfisca_core.errors import SituationParsingError, VariableNotFound
from openfisca_core.simulation_builder import SimulationBuilder
from openfisca_core.tools import assert_near
from openfisca_core.warnings import LibYAMLWarning
from openfisca_test import assert_near


class Options(TypedDict, total=False):
Expand All @@ -36,9 +36,9 @@ class Options(TypedDict, total=False):

@dataclasses.dataclass(frozen=True)
class ErrorMargin:
__root__: dict[str | Literal["default"], float | None]
__root__: dict[str | Literal["default"], float]

def __getitem__(self, key: str) -> float | None:
def __getitem__(self, key: str) -> float:
if key in self.__root__:
return self.__root__[key]

Expand All @@ -65,7 +65,7 @@ def build_test(params: dict[str, Any]) -> Test:
value = params.get(key)

if value is None:
value = {"default": None}
value = {"default": 0}

elif isinstance(value, (float, int, str)):
value = {"default": float(value)}
Expand Down Expand Up @@ -328,9 +328,9 @@ def check_variable(
return assert_near(
actual_value,
expected_value,
self.test.absolute_error_margin[variable_name],
f"{variable_name}@{period}: ",
self.test.relative_error_margin[variable_name],
message=f"{variable_name}@{period}: ",
absolute_error_margin=self.test.absolute_error_margin[variable_name],
relative_error_margin=self.test.relative_error_margin[variable_name],
)

def should_ignore_variable(self, variable_name: str):
Expand Down
5 changes: 4 additions & 1 deletion openfisca_core/variables/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,10 @@ def check_set_value(self, value):
return value

def default_array(self, array_size):
array = numpy.empty(array_size, dtype=self.dtype)
if numpy.issubdtype(self.dtype, numpy.datetime64):
array = numpy.empty(array_size, dtype="datetime64[D]")
else:
array = numpy.empty(array_size, dtype=self.dtype)
if self.value_type == Enum:
array.fill(self.default_value.index)
return EnumArray(array, self.possible_values)
Expand Down
35 changes: 20 additions & 15 deletions openfisca_tasks/lint.mk
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## Lint the codebase.
lint: check-syntax-errors check-style lint-doc
lint: check-syntax-errors check-style check-doc
@$(call print_pass,$@:)

## Compile python files to check for syntax errors.
Expand All @@ -9,31 +9,34 @@ check-syntax-errors: .
@$(call print_pass,$@:)

## Run linters to check for syntax and style errors.
check-style: $(shell git ls-files "*.py")
check-style: $(shell git ls-files "*.py" "*.pyi")
@$(call print_help,$@:)
@isort --check $?
@black --check $?
@flake8 $?
@$(call print_pass,$@:)

## Run linters to check for syntax and style errors in the doc.
lint-doc: \
lint-doc-commons \
lint-doc-entities \
lint-doc-types \
;

## Run linters to check for syntax and style errors in the doc.
lint-doc-%:
check-doc:
@## These checks are exclusively related to doc/strings/test.
@##
@## They can be integrated into setup.cfg once all checks pass.
@## The reason they're here is because otherwise we wouldn't be
@## able to integrate documentation improvements progresively.
@##
@$(call print_help,$(subst $*,%,$@:))
@flake8 --select=D101,D102,D103,DAR openfisca_core/$*
@pylint openfisca_core/$*
@$(call print_help,$@:)
@flake8 --select=D101,D102,D103,DAR \
openfisca_core/commons \
openfisca_core/entities \
openfisca_core/types.py \
openfisca_test \
stubs
@pylint \
openfisca_core/commons \
openfisca_core/entities \
openfisca_core/types.py \
openfisca_test \
stubs
@$(call print_pass,$@:)

## Run static type checkers for type errors.
Expand All @@ -42,11 +45,13 @@ check-types:
@mypy \
openfisca_core/commons \
openfisca_core/entities \
openfisca_core/types.py
openfisca_core/types.py \
openfisca_test \
stubs
@$(call print_pass,$@:)

## Run code formatters to correct style errors.
format-style: $(shell git ls-files "*.py")
format-style: $(shell git ls-files "*.py" "*.pyi")
@$(call print_help,$@:)
@isort $?
@black $?
Expand Down
3 changes: 2 additions & 1 deletion openfisca_tasks/test_code.mk
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ test-core: $(shell pytest --quiet --quiet --collect-only 2> /dev/null | cut -f 1
openfisca_core/entities \
openfisca_core/holders \
openfisca_core/periods \
openfisca_core/projectors
openfisca_core/projectors \
openfisca_test
@PYTEST_ADDOPTS="$${PYTEST_ADDOPTS} ${pytest_args}" \
coverage run -m \
${openfisca} test $? \
Expand Down
5 changes: 5 additions & 0 deletions openfisca_test/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from . import types
from ._assertions import assert_near
from ._parsers import parse

__all__ = ["assert_near", "parse", "types"]
Loading
Loading