From 31a74602b6494ef0fafbeeb72a183f2f82de5520 Mon Sep 17 00:00:00 2001 From: Mauko Quiroga Date: Sun, 31 Jul 2022 19:45:51 +0200 Subject: [PATCH 1/5] Add test to dispatch by month --- openfisca_core/holders/tests/test_helpers.py | 78 ++++++++++++++++++++ setup.cfg | 3 + 2 files changed, 81 insertions(+) create mode 100644 openfisca_core/holders/tests/test_helpers.py diff --git a/openfisca_core/holders/tests/test_helpers.py b/openfisca_core/holders/tests/test_helpers.py new file mode 100644 index 0000000000..85c702db3a --- /dev/null +++ b/openfisca_core/holders/tests/test_helpers.py @@ -0,0 +1,78 @@ +import numpy +import pytest + +from openfisca_core import holders, periods +from openfisca_core.entities import Entity +from openfisca_core.holders import Holder +from openfisca_core.periods import Instant, Period +from openfisca_core.populations import Population +from openfisca_core.variables import Variable + + +@pytest.fixture +def people(): + return Entity( + key = "person", + plural = "people", + label = "An individual member of a larger group.", + doc = "People have the particularity of not being someone else.", + ) + + +@pytest.fixture +def Income(people): + return type( + "Income", + (Variable,), { + "value_type": float, + "entity": people + }, + ) + + +@pytest.fixture +def population(people): + population = Population(people) + population.count = 1 + return population + + +@pytest.fixture +def beggining_of_year(): + return Instant((2022, 1, 1)) + + +@pytest.fixture +def three_years(beggining_of_year): + return Period((periods.YEAR, beggining_of_year, 3)) + + +@pytest.fixture +def three_months(beggining_of_year): + return Period((periods.MONTH, beggining_of_year, 3)) + + +@pytest.fixture +def three_days(beggining_of_year): + return Period((periods.DAY, beggining_of_year, 3)) + + +def test_set_input_dispatch_by_period( + Income, + population, + three_years, + ): + """Yearly income propagates evenly to the following years.""" + + Income.definition_period = periods.MONTH + income = Income() + holder = Holder(income, population) + values = [1000.] + + holders.set_input_dispatch_by_period(holder, three_years, values) + + known_periods = holder.get_known_periods() + period_count = len(known_periods) + + assert period_count == 36 # Three years in months + assert sum(map(holder.get_array, known_periods)) == [36000.] diff --git a/setup.cfg b/setup.cfg index bb3ff50fc5..724c6529e1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -51,5 +51,8 @@ non_interactive = True [mypy-openfisca_core.commons.tests.*] ignore_errors = True +[mypy-openfisca_core.holders.tests.*] +ignore_errors = True + [mypy-openfisca_core.scripts.*] ignore_errors = True From 3e302e8dd11bcdd1c111e513424708ae3cce3a3a Mon Sep 17 00:00:00 2001 From: Mauko Quiroga Date: Sun, 31 Jul 2022 20:09:24 +0200 Subject: [PATCH 2/5] Add general test to dispatch --- openfisca_core/holders/tests/test_helpers.py | 63 +++++++++++++++++--- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/openfisca_core/holders/tests/test_helpers.py b/openfisca_core/holders/tests/test_helpers.py index 85c702db3a..673b4e7976 100644 --- a/openfisca_core/holders/tests/test_helpers.py +++ b/openfisca_core/holders/tests/test_helpers.py @@ -57,22 +57,67 @@ def three_days(beggining_of_year): return Period((periods.DAY, beggining_of_year, 3)) -def test_set_input_dispatch_by_period( +@pytest.mark.parametrize("definition_period, values, expected", [ + [periods.YEAR, [43800.], [43800. * 3]], + [periods.MONTH, [3650.], [3650. * 12 * 3]], + # [periods.DAY, [120.], [131400.]], + ]) +def test_set_input_dispatch_by_period_over_3_years( Income, + definition_period, population, three_years, + values, + expected, ): - """Yearly income propagates evenly to the following years.""" - - Income.definition_period = periods.MONTH + Income.definition_period = definition_period income = Income() holder = Holder(income, population) - values = [1000.] holders.set_input_dispatch_by_period(holder, three_years, values) - known_periods = holder.get_known_periods() - period_count = len(known_periods) + assert sum(map(holder.get_array, holder.get_known_periods())) == expected + + +@pytest.mark.parametrize("definition_period, values, expected", [ + [periods.YEAR, [43800.], [43800.]], + [periods.MONTH, [3650.], [3650. * 3]], + # [periods.DAY, [120.], [131400.]], + ]) +def test_set_input_dispatch_by_period_over_3_months( + Income, + definition_period, + population, + three_months, + values, + expected, + ): + Income.definition_period = definition_period + income = Income() + holder = Holder(income, population) + + holders.set_input_dispatch_by_period(holder, three_months, values) + + assert sum(map(holder.get_array, holder.get_known_periods())) == expected + + +@pytest.mark.parametrize("definition_period, values, expected", [ + [periods.YEAR, [43800.], [43800.]], + [periods.MONTH, [3650.], [3650.]], + # [periods.DAY, [120.], [131400.]], + ]) +def test_set_input_dispatch_by_period_over_3_days( + Income, + definition_period, + population, + three_days, + values, + expected, + ): + Income.definition_period = definition_period + income = Income() + holder = Holder(income, population) + + holders.set_input_dispatch_by_period(holder, three_days, values) - assert period_count == 36 # Three years in months - assert sum(map(holder.get_array, known_periods)) == [36000.] + assert sum(map(holder.get_array, holder.get_known_periods())) == expected From 3467deb25708838c233455738599ba04e3896c5f Mon Sep 17 00:00:00 2001 From: Mauko Quiroga Date: Sun, 31 Jul 2022 20:30:03 +0200 Subject: [PATCH 3/5] Add tests to set divide by period --- openfisca_core/holders/tests/test_helpers.py | 86 ++++++++++++++++++-- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/openfisca_core/holders/tests/test_helpers.py b/openfisca_core/holders/tests/test_helpers.py index 673b4e7976..0c307e9ab1 100644 --- a/openfisca_core/holders/tests/test_helpers.py +++ b/openfisca_core/holders/tests/test_helpers.py @@ -1,7 +1,6 @@ -import numpy import pytest -from openfisca_core import holders, periods +from openfisca_core import holders, periods, tools from openfisca_core.entities import Entity from openfisca_core.holders import Holder from openfisca_core.periods import Instant, Period @@ -58,8 +57,8 @@ def three_days(beggining_of_year): @pytest.mark.parametrize("definition_period, values, expected", [ - [periods.YEAR, [43800.], [43800. * 3]], - [periods.MONTH, [3650.], [3650. * 12 * 3]], + [periods.YEAR, [43800.], [131400.]], + [periods.MONTH, [3650.], [131400.]], # [periods.DAY, [120.], [131400.]], ]) def test_set_input_dispatch_by_period_over_3_years( @@ -75,13 +74,14 @@ def test_set_input_dispatch_by_period_over_3_years( holder = Holder(income, population) holders.set_input_dispatch_by_period(holder, three_years, values) + total = sum(map(holder.get_array, holder.get_known_periods())) - assert sum(map(holder.get_array, holder.get_known_periods())) == expected + tools.assert_near(total, expected, absolute_error_margin = 0.001) @pytest.mark.parametrize("definition_period, values, expected", [ [periods.YEAR, [43800.], [43800.]], - [periods.MONTH, [3650.], [3650. * 3]], + [periods.MONTH, [3650.], [10950.]], # [periods.DAY, [120.], [131400.]], ]) def test_set_input_dispatch_by_period_over_3_months( @@ -97,8 +97,9 @@ def test_set_input_dispatch_by_period_over_3_months( holder = Holder(income, population) holders.set_input_dispatch_by_period(holder, three_months, values) + total = sum(map(holder.get_array, holder.get_known_periods())) - assert sum(map(holder.get_array, holder.get_known_periods())) == expected + tools.assert_near(total, expected, absolute_error_margin = 0.001) @pytest.mark.parametrize("definition_period, values, expected", [ @@ -119,5 +120,74 @@ def test_set_input_dispatch_by_period_over_3_days( holder = Holder(income, population) holders.set_input_dispatch_by_period(holder, three_days, values) + total = sum(map(holder.get_array, holder.get_known_periods())) - assert sum(map(holder.get_array, holder.get_known_periods())) == expected + tools.assert_near(total, expected, absolute_error_margin = 0.001) + +@pytest.mark.parametrize("definition_period, values, expected", [ + [periods.YEAR, [131400.], [43800.]], + [periods.MONTH, [131400.], [3650.]], + # [periods.DAY, [120.], [131400.]], + ]) +def test_set_input_divide_by_period_over_3_years( + Income, + definition_period, + population, + three_years, + values, + expected, + ): + Income.definition_period = definition_period + income = Income() + holder = Holder(income, population) + + holders.set_input_divide_by_period(holder, three_years, values) + last = holder.get_array(holder.get_known_periods()[-1]) + + tools.assert_near(last, expected, absolute_error_margin = 0.001) + + +@pytest.mark.parametrize("definition_period, values, expected", [ + [periods.YEAR, [43800.], [43800.]], + [periods.MONTH, [10950.], [3650.]], + # [periods.DAY, [120.], [131400.]], + ]) +def test_set_input_divide_by_period_over_3_months( + Income, + definition_period, + population, + three_months, + values, + expected, + ): + Income.definition_period = definition_period + income = Income() + holder = Holder(income, population) + + holders.set_input_divide_by_period(holder, three_months, values) + last = holder.get_array(holder.get_known_periods()[-1]) + + tools.assert_near(last, expected, absolute_error_margin = 0.001) + + +@pytest.mark.parametrize("definition_period, values, expected", [ + [periods.YEAR, [43800.], [43800.]], + [periods.MONTH, [3650.], [3650.]], + # [periods.DAY, [120.], [131400.]], + ]) +def test_set_input_divide_by_period_over_3_days( + Income, + definition_period, + population, + three_days, + values, + expected, + ): + Income.definition_period = definition_period + income = Income() + holder = Holder(income, population) + + holders.set_input_divide_by_period(holder, three_days, values) + last = holder.get_array(holder.get_known_periods()[-1]) + + tools.assert_near(last, expected, absolute_error_margin = 0.001) From e7f3a0d65e3f43f6e6a8ac4244e3cab026dbeeed Mon Sep 17 00:00:00 2001 From: Mauko Quiroga Date: Sun, 31 Jul 2022 21:05:20 +0200 Subject: [PATCH 4/5] Add days to set input dispatch/divide --- openfisca_core/holders/helpers.py | 18 +- openfisca_core/holders/tests/test_helpers.py | 163 ++++--------------- 2 files changed, 40 insertions(+), 141 deletions(-) diff --git a/openfisca_core/holders/helpers.py b/openfisca_core/holders/helpers.py index efe16388e0..fbb0b0592a 100644 --- a/openfisca_core/holders/helpers.py +++ b/openfisca_core/holders/helpers.py @@ -20,13 +20,10 @@ def set_input_dispatch_by_period(holder, period, array): period_size = period.size period_unit = period.unit - if holder.variable.definition_period == periods.MONTH: - cached_period_unit = periods.MONTH - elif holder.variable.definition_period == periods.YEAR: - cached_period_unit = periods.YEAR - else: - raise ValueError('set_input_dispatch_by_period can be used only for yearly or monthly variables.') + if holder.variable.definition_period == periods.ETERNITY: + raise ValueError("set_input_dispatch_by_period can't be used for eternal variables.") + cached_period_unit = holder.variable.definition_period after_instant = period.start.offset(period_size, period_unit) # Cache the input data, skipping the existing cached months @@ -55,13 +52,10 @@ def set_input_divide_by_period(holder, period, array): period_size = period.size period_unit = period.unit - if holder.variable.definition_period == periods.MONTH: - cached_period_unit = periods.MONTH - elif holder.variable.definition_period == periods.YEAR: - cached_period_unit = periods.YEAR - else: - raise ValueError('set_input_divide_by_period can be used only for yearly or monthly variables.') + if holder.variable.definition_period == periods.ETERNITY: + raise ValueError("set_input_divide_by_period can't be used for eternal variables.") + cached_period_unit = holder.variable.definition_period after_instant = period.start.offset(period_size, period_unit) # Count the number of elementary periods to change, and the difference with what is already known. diff --git a/openfisca_core/holders/tests/test_helpers.py b/openfisca_core/holders/tests/test_helpers.py index 0c307e9ab1..6ba1e7a815 100644 --- a/openfisca_core/holders/tests/test_helpers.py +++ b/openfisca_core/holders/tests/test_helpers.py @@ -36,158 +36,63 @@ def population(people): return population -@pytest.fixture -def beggining_of_year(): - return Instant((2022, 1, 1)) - - -@pytest.fixture -def three_years(beggining_of_year): - return Period((periods.YEAR, beggining_of_year, 3)) - - -@pytest.fixture -def three_months(beggining_of_year): - return Period((periods.MONTH, beggining_of_year, 3)) - - -@pytest.fixture -def three_days(beggining_of_year): - return Period((periods.DAY, beggining_of_year, 3)) - - -@pytest.mark.parametrize("definition_period, values, expected", [ - [periods.YEAR, [43800.], [131400.]], - [periods.MONTH, [3650.], [131400.]], - # [periods.DAY, [120.], [131400.]], - ]) -def test_set_input_dispatch_by_period_over_3_years( - Income, - definition_period, - population, - three_years, - values, - expected, - ): - Income.definition_period = definition_period - income = Income() - holder = Holder(income, population) - - holders.set_input_dispatch_by_period(holder, three_years, values) - total = sum(map(holder.get_array, holder.get_known_periods())) - - tools.assert_near(total, expected, absolute_error_margin = 0.001) - - -@pytest.mark.parametrize("definition_period, values, expected", [ - [periods.YEAR, [43800.], [43800.]], - [periods.MONTH, [3650.], [10950.]], - # [periods.DAY, [120.], [131400.]], +@pytest.mark.parametrize("dispatch_unit, definition_unit, values, expected", [ + [periods.YEAR, periods.YEAR, [1.], [3.]], + [periods.YEAR, periods.MONTH, [1.], [36.]], + [periods.YEAR, periods.DAY, [1.], [1096.]], + [periods.MONTH, periods.YEAR, [1.], [1.]], + [periods.MONTH, periods.MONTH, [1.], [3.]], + [periods.MONTH, periods.DAY, [1.], [90.]], + [periods.DAY, periods.YEAR, [1.], [1.]], + [periods.DAY, periods.MONTH, [1.], [1.]], + [periods.DAY, periods.DAY, [1.], [3.]], ]) -def test_set_input_dispatch_by_period_over_3_months( +def test_set_input_dispatch_by_period( Income, - definition_period, population, - three_months, + dispatch_unit, + definition_unit, values, expected, ): - Income.definition_period = definition_period + Income.definition_period = definition_unit income = Income() holder = Holder(income, population) + instant = Instant((2022, 1, 1)) + dispatch_period = Period((dispatch_unit, instant, 3)) - holders.set_input_dispatch_by_period(holder, three_months, values) + holders.set_input_dispatch_by_period(holder, dispatch_period, values) total = sum(map(holder.get_array, holder.get_known_periods())) tools.assert_near(total, expected, absolute_error_margin = 0.001) -@pytest.mark.parametrize("definition_period, values, expected", [ - [periods.YEAR, [43800.], [43800.]], - [periods.MONTH, [3650.], [3650.]], - # [periods.DAY, [120.], [131400.]], - ]) -def test_set_input_dispatch_by_period_over_3_days( - Income, - definition_period, - population, - three_days, - values, - expected, - ): - Income.definition_period = definition_period - income = Income() - holder = Holder(income, population) - - holders.set_input_dispatch_by_period(holder, three_days, values) - total = sum(map(holder.get_array, holder.get_known_periods())) - - tools.assert_near(total, expected, absolute_error_margin = 0.001) - -@pytest.mark.parametrize("definition_period, values, expected", [ - [periods.YEAR, [131400.], [43800.]], - [periods.MONTH, [131400.], [3650.]], - # [periods.DAY, [120.], [131400.]], - ]) -def test_set_input_divide_by_period_over_3_years( - Income, - definition_period, - population, - three_years, - values, - expected, - ): - Income.definition_period = definition_period - income = Income() - holder = Holder(income, population) - - holders.set_input_divide_by_period(holder, three_years, values) - last = holder.get_array(holder.get_known_periods()[-1]) - - tools.assert_near(last, expected, absolute_error_margin = 0.001) - - -@pytest.mark.parametrize("definition_period, values, expected", [ - [periods.YEAR, [43800.], [43800.]], - [periods.MONTH, [10950.], [3650.]], - # [periods.DAY, [120.], [131400.]], - ]) -def test_set_input_divide_by_period_over_3_months( - Income, - definition_period, - population, - three_months, - values, - expected, - ): - Income.definition_period = definition_period - income = Income() - holder = Holder(income, population) - - holders.set_input_divide_by_period(holder, three_months, values) - last = holder.get_array(holder.get_known_periods()[-1]) - - tools.assert_near(last, expected, absolute_error_margin = 0.001) - - -@pytest.mark.parametrize("definition_period, values, expected", [ - [periods.YEAR, [43800.], [43800.]], - [periods.MONTH, [3650.], [3650.]], - # [periods.DAY, [120.], [131400.]], +@pytest.mark.parametrize("divide_unit, definition_unit, values, expected", [ + [periods.YEAR, periods.YEAR, [3.], [1.]], + [periods.YEAR, periods.MONTH, [36.], [1.]], + [periods.YEAR, periods.DAY, [1095.], [1.]], + [periods.MONTH, periods.YEAR, [1.], [1.]], + [periods.MONTH, periods.MONTH, [3.], [1.]], + [periods.MONTH, periods.DAY, [90.], [1.]], + [periods.DAY, periods.YEAR, [1.], [1.]], + [periods.DAY, periods.MONTH, [1.], [1.]], + [periods.DAY, periods.DAY, [3.], [1.]], ]) -def test_set_input_divide_by_period_over_3_days( +def test_set_input_divide_by_period( Income, - definition_period, population, - three_days, + divide_unit, + definition_unit, values, expected, ): - Income.definition_period = definition_period + Income.definition_period = definition_unit income = Income() holder = Holder(income, population) + instant = Instant((2022, 1, 1)) + divide_period = Period((divide_unit, instant, 3)) - holders.set_input_divide_by_period(holder, three_days, values) + holders.set_input_divide_by_period(holder, divide_period, values) last = holder.get_array(holder.get_known_periods()[-1]) tools.assert_near(last, expected, absolute_error_margin = 0.001) From 8644ef9b2c0b10fb892104ca7c448f206da01814 Mon Sep 17 00:00:00 2001 From: Mauko Quiroga Date: Sun, 31 Jul 2022 21:18:44 +0200 Subject: [PATCH 5/5] Version & CHANGELOG bump --- CHANGELOG.md | 9 +++++++++ setup.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ffe4dfaed..db44866fc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +### 35.10.1 [#1143](https://github.com/openfisca/openfisca-core/pull/1143) + +#### Bug fix + +- Reintroduce support for the ``day`` date unit in `holders.set_input_dispatch_by_period` and `holders. + set_input_divide_by_period` + - Allows for dispatching values per day, for example, to provide a daily (week, fortnight) to an yearly variable. + - Inversely, allows for calculating the daily (week, fortnight) value of a yearly input. + ## 35.10.0 [#1151](https://github.com/openfisca/openfisca-core/pull/1151) #### New features diff --git a/setup.py b/setup.py index b988587194..cc1216e69b 100644 --- a/setup.py +++ b/setup.py @@ -48,7 +48,7 @@ setup( name = 'OpenFisca-Core', - version = '35.10.0', + version = '35.10.1', author = 'OpenFisca Team', author_email = 'contact@openfisca.org', classifiers = [