Skip to content

Commit d0cec25

Browse files
committed
feat(tests): add assert_near parser
1 parent 00fe69a commit d0cec25

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+596
-232
lines changed

STYLEGUIDE.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,8 @@ And avoid:
7272
# No
7373

7474
from openfisca_country_template.entities import Person
75-
from openfisca_core import variables
76-
from openfisca_core.tools import assert_near
77-
from openfisca_core import axes
75+
from openfisca_core import axes, variables
76+
from openfisca_test import assert_near
7877

7978
from numpy import ndarray
8079
from copy import deepcopy

openfisca_core/holders/tests/test_helpers.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pytest
22

3-
from openfisca_core import holders, tools
3+
import openfisca_test as test
4+
from openfisca_core import holders
45
from openfisca_core.entities import Entity
56
from openfisca_core.holders import Holder
67
from openfisca_core.periods import DateUnit, Instant, Period
@@ -86,7 +87,7 @@ def test_set_input_dispatch_by_period(
8687
holders.set_input_dispatch_by_period(holder, dispatch_period, values)
8788
total = sum(map(holder.get_array, holder.get_known_periods()))
8889

89-
tools.assert_near(total, expected, absolute_error_margin=0.001)
90+
test.assert_near(total, expected, absolute_error_margin=0.001)
9091

9192

9293
@pytest.mark.parametrize(
@@ -136,4 +137,4 @@ def test_set_input_divide_by_period(
136137
holders.set_input_divide_by_period(holder, divide_period, values)
137138
last = holder.get_array(holder.get_known_periods()[-1])
138139

139-
tools.assert_near(last, expected, absolute_error_margin=0.001)
140+
test.assert_near(last, expected, absolute_error_margin=0.001)

openfisca_core/indexed_enums/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
#
2222
# See: https://www.python.org/dev/peps/pep-0008/#imports
2323

24-
from .config import ENUM_ARRAY_DTYPE # noqa: F401
25-
from .enum import Enum # noqa: F401
26-
from .enum_array import EnumArray # noqa: F401
24+
from . import types
25+
from .config import ENUM_ARRAY_DTYPE
26+
from .enum import Enum
27+
from .enum_array import EnumArray
28+
29+
__all__ = ["ENUM_ARRAY_DTYPE", "Enum", "EnumArray", "types"]

openfisca_core/indexed_enums/enum.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import numpy
88

9+
from . import types as t
910
from .config import ENUM_ARRAY_DTYPE
1011
from .enum_array import EnumArray
1112

@@ -38,6 +39,7 @@ def encode(
3839
numpy.int_,
3940
numpy.float_,
4041
numpy.object_,
42+
t.Array[t.ArrayBytes],
4143
],
4244
) -> EnumArray:
4345
"""

openfisca_core/indexed_enums/enum_array.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import numpy
77

8+
from . import types as t
9+
810
if typing.TYPE_CHECKING:
911
from openfisca_core.indexed_enums import Enum
1012

@@ -21,7 +23,7 @@ class EnumArray(numpy.ndarray):
2123
# https://docs.scipy.org/doc/numpy-1.13.0/user/basics.subclassing.html#slightly-more-realistic-example-attribute-added-to-existing-array.
2224
def __new__(
2325
cls,
24-
input_array: numpy.int_,
26+
input_array: t.Array[t.ArrayEnum],
2527
possible_values: Optional[Type[Enum]] = None,
2628
) -> EnumArray:
2729
obj = numpy.asarray(input_array).view(cls)

openfisca_core/indexed_enums/types.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from openfisca_core.types import Array, ArrayBytes, ArrayEnum
2+
3+
__all__ = ["Array", "ArrayBytes", "ArrayEnum"]

openfisca_core/periods/instant_.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def __str__(self):
9090
return instant_str
9191

9292
@property
93-
def date(self):
93+
def date(self) -> pendulum.Date:
9494
instant_date = config.date_by_instant_cache.get(self)
9595

9696
if instant_date is None:

openfisca_core/scripts/measure_performances.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
from openfisca_core.entities import build_entity
1717
from openfisca_core.periods import DateUnit
1818
from openfisca_core.taxbenefitsystems import TaxBenefitSystem
19-
from openfisca_core.tools import assert_near
2019
from openfisca_core.variables import Variable
20+
from openfisca_test import assert_near
2121

2222
args = None
2323

openfisca_core/tools/__init__.py

Lines changed: 5 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,10 @@
1-
# -*- coding: utf-8 -*-
2-
1+
from __future__ import annotations
32

43
import os
54

65
import numexpr
76

8-
from openfisca_core.indexed_enums import EnumArray
9-
10-
11-
def assert_near(
12-
value,
13-
target_value,
14-
absolute_error_margin=None,
15-
message="",
16-
relative_error_margin=None,
17-
):
18-
"""
19-
20-
:param value: Value returned by the test
21-
:param target_value: Value that the test should return to pass
22-
:param absolute_error_margin: Absolute error margin authorized
23-
:param message: Error message to be displayed if the test fails
24-
:param relative_error_margin: Relative error margin authorized
25-
26-
Limit : This function cannot be used to assert near periods.
27-
28-
"""
29-
30-
import numpy
31-
32-
if absolute_error_margin is None and relative_error_margin is None:
33-
absolute_error_margin = 0
34-
if not isinstance(value, numpy.ndarray):
35-
value = numpy.array(value)
36-
if isinstance(value, EnumArray):
37-
return assert_enum_equals(value, target_value, message)
38-
if numpy.issubdtype(value.dtype, numpy.datetime64):
39-
target_value = numpy.array(target_value, dtype=value.dtype)
40-
assert_datetime_equals(value, target_value, message)
41-
if isinstance(target_value, str):
42-
target_value = eval_expression(target_value)
43-
44-
target_value = numpy.array(target_value).astype(numpy.float32)
45-
46-
value = numpy.array(value).astype(numpy.float32)
47-
diff = abs(target_value - value)
48-
if absolute_error_margin is not None:
49-
assert (
50-
diff <= absolute_error_margin
51-
).all(), "{}{} differs from {} with an absolute margin {} > {}".format(
52-
message, value, target_value, diff, absolute_error_margin
53-
)
54-
if relative_error_margin is not None:
55-
assert (
56-
diff <= abs(relative_error_margin * target_value)
57-
).all(), "{}{} differs from {} with a relative margin {} > {}".format(
58-
message,
59-
value,
60-
target_value,
61-
diff,
62-
abs(relative_error_margin * target_value),
63-
)
64-
65-
66-
def assert_datetime_equals(value, target_value, message=""):
67-
assert (value == target_value).all(), "{}{} differs from {}.".format(
68-
message, value, target_value
69-
)
70-
71-
72-
def assert_enum_equals(value, target_value, message=""):
73-
value = value.decode_to_str()
74-
assert (value == target_value).all(), "{}{} differs from {}.".format(
75-
message, value, target_value
76-
)
7+
from openfisca_core import types as t
778

789

7910
def indent(text):
@@ -102,7 +33,9 @@ def get_trace_tool_link(scenario, variables, api_url, trace_tool_url):
10233
return url
10334

10435

105-
def eval_expression(expression):
36+
def eval_expression(
37+
expression: str,
38+
) -> str | t.Array[t.ArrayBool | t.ArrayInt | t.ArrayFloat]:
10639
try:
10740
return numexpr.evaluate(expression)
10841
except (KeyError, TypeError):

openfisca_core/tools/test_runner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
from openfisca_core.errors import SituationParsingError, VariableNotFound
1919
from openfisca_core.simulation_builder import SimulationBuilder
20-
from openfisca_core.tools import assert_near
2120
from openfisca_core.warnings import LibYAMLWarning
21+
from openfisca_test import assert_near
2222

2323

2424
class Options(TypedDict, total=False):

openfisca_core/types.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,42 @@
1010

1111
import numpy
1212

13+
# Type aliases
14+
15+
#: Type for arrays of any type.
16+
ArrayAny: TypeAlias = numpy.generic
17+
18+
#: Type for arrays of booleans.
19+
ArrayBool: TypeAlias = numpy.bool_
20+
21+
#: Type for arrays of bytes.
22+
ArrayBytes: TypeAlias = numpy.bytes_
23+
24+
#: Type for arrays of dates.
25+
ArrayDate: TypeAlias = numpy.datetime64
26+
27+
#: Type for arrays of enums.
28+
ArrayEnum: TypeAlias = numpy.int16
29+
30+
#: Type for arrays of floats.
31+
ArrayFloat: TypeAlias = numpy.float32
32+
33+
#: Type for arrays of integers.
34+
ArrayInt: TypeAlias = numpy.int32
35+
36+
#: Type for arrays of Python objects.
37+
ArrayObject: TypeAlias = numpy.object_
38+
39+
#: Type for arrays of strings.
40+
ArrayStr: TypeAlias = numpy.str_
41+
42+
#: Generic numpy type an array can have.
1343
N = TypeVar("N", bound=numpy.generic, covariant=True)
1444

15-
#: Type representing an numpy array.
45+
#: Type representing a numpy array.
1646
Array: TypeAlias = NDArray[N]
1747

48+
#: Generic type a sequence can have.
1849
L = TypeVar("L")
1950

2051
#: Type representing an array-like object.

openfisca_core/variables/__init__.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@
2121
#
2222
# See: https://www.python.org/dev/peps/pep-0008/#imports
2323

24-
from .config import FORMULA_NAME_PREFIX, VALUE_TYPES # noqa: F401
25-
from .helpers import get_annualized_variable, get_neutralized_variable # noqa: F401
26-
from .variable import Variable # noqa: F401
24+
from . import types
25+
from .config import FORMULA_NAME_PREFIX, VALUE_TYPES
26+
from .helpers import get_annualized_variable, get_neutralized_variable
27+
from .variable import Variable
28+
29+
__all__ = [
30+
"FORMULA_NAME_PREFIX",
31+
"VALUE_TYPES",
32+
"Variable",
33+
"get_annualized_variable",
34+
"get_neutralized_variable",
35+
"types",
36+
]

openfisca_core/variables/config.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,46 @@
11
import datetime
22

3-
import numpy
3+
from openfisca_core import indexed_enums as enum
44

5-
from openfisca_core import indexed_enums
6-
from openfisca_core.indexed_enums import Enum
5+
from . import types as t
76

87
VALUE_TYPES = {
98
bool: {
10-
"dtype": numpy.bool_,
9+
"dtype": t.ArrayBool,
1110
"default": False,
1211
"json_type": "boolean",
1312
"formatted_value_type": "Boolean",
1413
"is_period_size_independent": True,
1514
},
1615
int: {
17-
"dtype": numpy.int32,
16+
"dtype": t.ArrayInt,
1817
"default": 0,
1918
"json_type": "integer",
2019
"formatted_value_type": "Int",
2120
"is_period_size_independent": False,
2221
},
2322
float: {
24-
"dtype": numpy.float32,
23+
"dtype": t.ArrayFloat,
2524
"default": 0,
2625
"json_type": "number",
2726
"formatted_value_type": "Float",
2827
"is_period_size_independent": False,
2928
},
3029
str: {
31-
"dtype": object,
30+
"dtype": t.ArrayBytes,
3231
"default": "",
3332
"json_type": "string",
3433
"formatted_value_type": "String",
3534
"is_period_size_independent": True,
3635
},
37-
Enum: {
38-
"dtype": indexed_enums.ENUM_ARRAY_DTYPE,
36+
enum.Enum: {
37+
"dtype": t.ArrayEnum,
3938
"json_type": "string",
4039
"formatted_value_type": "String",
4140
"is_period_size_independent": True,
4241
},
4342
datetime.date: {
44-
"dtype": "datetime64[D]",
43+
"dtype": t.ArrayDate,
4544
"default": datetime.date.fromtimestamp(0), # 0 == 1970-01-01
4645
"json_type": "string",
4746
"formatted_value_type": "Date",

openfisca_core/variables/types.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from openfisca_core.types import (
2+
ArrayBool,
3+
ArrayBytes,
4+
ArrayDate,
5+
ArrayEnum,
6+
ArrayFloat,
7+
ArrayInt,
8+
)
9+
10+
__any__ = [
11+
ArrayBool,
12+
ArrayBytes,
13+
ArrayDate,
14+
ArrayEnum,
15+
ArrayFloat,
16+
ArrayInt,
17+
]

openfisca_tasks/lint.mk

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ check-syntax-errors: .
99
@$(call print_pass,$@:)
1010

1111
## Run linters to check for syntax and style errors.
12-
check-style: $(shell git ls-files "*.py")
12+
check-style: $(shell git ls-files "*.py" "*.pyi")
1313
@$(call print_help,$@:)
1414
@isort --check $?
1515
@black --check $?
@@ -32,21 +32,23 @@ lint-doc-%:
3232
@## able to integrate documentation improvements progresively.
3333
@##
3434
@$(call print_help,$(subst $*,%,$@:))
35-
@flake8 --select=D101,D102,D103,DAR openfisca_core/$*
36-
@pylint openfisca_core/$*
35+
@flake8 --select=D101,D102,D103,DAR openfisca_core/$* openfisca_test
36+
@pylint openfisca_core/$* openfisca_test
3737
@$(call print_pass,$@:)
3838

3939
## Run static type checkers for type errors.
4040
check-types:
4141
@$(call print_help,$@:)
42+
@command -v pyright && pyright
4243
@mypy \
4344
openfisca_core/commons \
4445
openfisca_core/entities \
45-
openfisca_core/types.py
46+
openfisca_core/types.py \
47+
openfisca_test
4648
@$(call print_pass,$@:)
4749

4850
## Run code formatters to correct style errors.
49-
format-style: $(shell git ls-files "*.py")
51+
format-style: $(shell git ls-files "*.py" "*.pyi")
5052
@$(call print_help,$@:)
5153
@isort $?
5254
@black $?

openfisca_tasks/test_code.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ test-core: $(shell pytest --quiet --quiet --collect-only 2> /dev/null | cut -f 1
3636
openfisca_core/entities \
3737
openfisca_core/holders \
3838
openfisca_core/periods \
39-
openfisca_core/projectors
39+
openfisca_core/projectors \
40+
openfisca_test
4041
@PYTEST_ADDOPTS="$${PYTEST_ADDOPTS} ${pytest_args}" \
4142
coverage run -m \
4243
${openfisca} test $? \

0 commit comments

Comments
 (0)