From 201db36c2da6e9db3660f4f149c3a30cbae716f6 Mon Sep 17 00:00:00 2001 From: Mahdi Ben Jelloul Date: Tue, 18 May 2021 16:02:06 +0200 Subject: [PATCH] Alloz variable neutralization in YAML test files Fix text for comparison with country-template parameter Bump Update CHANGELOG.md Co-authored-by: sandcha Test neutralized_variables new attribute for YAML tests Update CHANGELOG.md Co-authored-by: sandcha Add tbs with neutralized variables to yaml tbs cache fixup! Add tbs with neutralized variables to yaml tbs cache Add test on yaml runner on tbs cache with neutralized variable fixup! Add test on yaml runner on tbs cache with neutralized variable --- CHANGELOG.md | 9 ++++- openfisca_core/tools/test_runner.py | 33 ++++++++++++++-- setup.py | 2 +- tests/core/test_yaml.py | 4 ++ .../tools/test_runner/test_yaml_runner.py | 38 +++++++++++++------ .../test_with_neutralized_variables.yaml | 17 +++++++++ 6 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 tests/core/yaml_tests/test_with_neutralized_variables.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index a895e9db65..69804d49e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 35.5.0 [#1021](https://github.com/openfisca/openfisca-core/pull/1021) + +#### New features + +- Introduce `neutralize_variables` option in YAML test files + - A neutralized variable in a YAML test will return its default value when computed. + ### 35.4.2 [#1026](https://github.com/openfisca/openfisca-core/pull/1026) #### Bug fix @@ -38,7 +45,7 @@ - When libraries do not implement their own types, MyPy provides stubs, or type sheds - Thanks to `__future__.annotations`, those stubs or type sheds are casted to `typing.Any` - Since 1.20.x, NumPy now provides their own type definitions - - The introduction of NumPy 1.20.x in #990 caused one major problem: + - The introduction of NumPy 1.20.x in #990 caused one major problem: - It is general practice to do not import at runtime modules only used for typing purposes, thanks to the `typing.TYPE_CHEKING` variable - The new `numpy.typing` module was being imported at runtime, rendering OpenFisca unusable to all users depending on previous versions of NumPy (1.20.x-) - These changes revert #990 and solve #1009 and #1012 diff --git a/openfisca_core/tools/test_runner.py b/openfisca_core/tools/test_runner.py index f6833c74bb..f81d366cba 100644 --- a/openfisca_core/tools/test_runner.py +++ b/openfisca_core/tools/test_runner.py @@ -31,7 +31,22 @@ def import_yaml(): return yaml, Loader -TEST_KEYWORDS = {'absolute_error_margin', 'description', 'extensions', 'ignore_variables', 'input', 'keywords', 'max_spiral_loops', 'name', 'only_variables', 'output', 'period', 'reforms', 'relative_error_margin'} +TEST_KEYWORDS = { + 'absolute_error_margin', + 'description', + 'extensions', + 'ignore_variables', + 'input', + 'keywords', + 'max_spiral_loops', + 'name', + 'neutralized_variables', + 'only_variables', + 'output', + 'period', + 'reforms', + 'relative_error_margin' + } yaml, Loader = import_yaml() @@ -137,7 +152,12 @@ def runtest(self): unexpected_keys = set(self.test.keys()).difference(TEST_KEYWORDS) raise ValueError("Unexpected keys {} in test '{}' in file '{}'".format(unexpected_keys, self.name, self.fspath)) - self.tax_benefit_system = _get_tax_benefit_system(self.baseline_tax_benefit_system, self.test.get('reforms', []), self.test.get('extensions', [])) + self.tax_benefit_system = _get_tax_benefit_system( + self.baseline_tax_benefit_system, + self.test.get('reforms', []), + self.test.get('extensions', []), + self.test.get('neutralized_variables', []) + ) builder = SimulationBuilder() input = self.test.get('input', {}) @@ -262,14 +282,16 @@ def pytest_collect_file(self, parent, path): options = self.options) -def _get_tax_benefit_system(baseline, reforms, extensions): +def _get_tax_benefit_system(baseline, reforms, extensions, neutralized_variables): if not isinstance(reforms, list): reforms = [reforms] if not isinstance(extensions, list): extensions = [extensions] + if not isinstance(neutralized_variables, list): + neutralized_variables = [neutralized_variables] # keep reforms order in cache, ignore extensions order - key = hash((id(baseline), ':'.join(reforms), frozenset(extensions))) + key = hash((id(baseline), ':'.join(reforms), frozenset(extensions), ':'.join(neutralized_variables))) if _tax_benefit_system_cache.get(key): return _tax_benefit_system_cache.get(key) @@ -282,6 +304,9 @@ def _get_tax_benefit_system(baseline, reforms, extensions): current_tax_benefit_system = current_tax_benefit_system.clone() current_tax_benefit_system.load_extension(extension) + for neutralized_variable in neutralized_variables: + current_tax_benefit_system.neutralize_variable(neutralized_variable) + _tax_benefit_system_cache[key] = current_tax_benefit_system return current_tax_benefit_system diff --git a/setup.py b/setup.py index eb83761916..e27c587e68 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ setup( name = 'OpenFisca-Core', - version = '35.4.2', + version = '35.5.0', author = 'OpenFisca Team', author_email = 'contact@openfisca.org', classifiers = [ diff --git a/tests/core/test_yaml.py b/tests/core/test_yaml.py index 15085dbbf3..35ede618fa 100644 --- a/tests/core/test_yaml.py +++ b/tests/core/test_yaml.py @@ -65,6 +65,10 @@ def test_with_anchors(tax_benefit_system): assert run_yaml_test(tax_benefit_system, 'test_with_anchors.yaml') == EXIT_OK +def test_with_neutralized_variables(tax_benefit_system): + assert run_yaml_test(tax_benefit_system, 'test_with_neutralized_variables.yaml') == EXIT_OK + + def test_run_tests_from_directory_fail(tax_benefit_system): assert run_yaml_test(tax_benefit_system, yaml_tests_dir) == EXIT_TESTSFAILED diff --git a/tests/core/tools/test_runner/test_yaml_runner.py b/tests/core/tools/test_runner/test_yaml_runner.py index bd7aaccad7..549441709e 100644 --- a/tests/core/tools/test_runner/test_yaml_runner.py +++ b/tests/core/tools/test_runner/test_yaml_runner.py @@ -27,6 +27,9 @@ def apply_reform(self, path): def load_extension(self, extension): pass + def neutralize_variable(self, variable_name): + pass + def entities_by_singular(self): return {} @@ -95,51 +98,62 @@ def test_variable_not_found(): def test_tax_benefit_systems_with_reform_cache(): baseline = TaxBenefitSystem() - ab_tax_benefit_system = _get_tax_benefit_system(baseline, 'ab', []) - ba_tax_benefit_system = _get_tax_benefit_system(baseline, 'ba', []) + ab_tax_benefit_system = _get_tax_benefit_system(baseline, 'ab', [], []) + ba_tax_benefit_system = _get_tax_benefit_system(baseline, 'ba', [], []) assert ab_tax_benefit_system != ba_tax_benefit_system def test_reforms_formats(): baseline = TaxBenefitSystem() - lonely_reform_tbs = _get_tax_benefit_system(baseline, 'lonely_reform', []) - list_lonely_reform_tbs = _get_tax_benefit_system(baseline, ['lonely_reform'], []) + lonely_reform_tbs = _get_tax_benefit_system(baseline, 'lonely_reform', [], []) + list_lonely_reform_tbs = _get_tax_benefit_system(baseline, ['lonely_reform'], [], []) assert lonely_reform_tbs == list_lonely_reform_tbs def test_reforms_order(): baseline = TaxBenefitSystem() - abba_tax_benefit_system = _get_tax_benefit_system(baseline, ['ab', 'ba'], []) - baab_tax_benefit_system = _get_tax_benefit_system(baseline, ['ba', 'ab'], []) + abba_tax_benefit_system = _get_tax_benefit_system(baseline, ['ab', 'ba'], [], []) + baab_tax_benefit_system = _get_tax_benefit_system(baseline, ['ba', 'ab'], [], []) assert abba_tax_benefit_system != baab_tax_benefit_system # keep reforms order in cache def test_tax_benefit_systems_with_extensions_cache(): baseline = TaxBenefitSystem() - xy_tax_benefit_system = _get_tax_benefit_system(baseline, [], 'xy') - yx_tax_benefit_system = _get_tax_benefit_system(baseline, [], 'yx') + xy_tax_benefit_system = _get_tax_benefit_system(baseline, [], 'xy', []) + yx_tax_benefit_system = _get_tax_benefit_system(baseline, [], 'yx', []) assert xy_tax_benefit_system != yx_tax_benefit_system def test_extensions_formats(): baseline = TaxBenefitSystem() - lonely_extension_tbs = _get_tax_benefit_system(baseline, [], 'lonely_extension') - list_lonely_extension_tbs = _get_tax_benefit_system(baseline, [], ['lonely_extension']) + lonely_extension_tbs = _get_tax_benefit_system(baseline, [], 'lonely_extension', []) + list_lonely_extension_tbs = _get_tax_benefit_system(baseline, [], ['lonely_extension'], []) assert lonely_extension_tbs == list_lonely_extension_tbs def test_extensions_order(): baseline = TaxBenefitSystem() - xy_tax_benefit_system = _get_tax_benefit_system(baseline, [], ['x', 'y']) - yx_tax_benefit_system = _get_tax_benefit_system(baseline, [], ['y', 'x']) + xy_tax_benefit_system = _get_tax_benefit_system(baseline, [], ['x', 'y'], []) + yx_tax_benefit_system = _get_tax_benefit_system(baseline, [], ['y', 'x'], []) assert xy_tax_benefit_system == yx_tax_benefit_system # extensions order is ignored in cache +def test_tax_benefit_systems_with_neutralized_variables(): + baseline = TaxBenefitSystem() + + re_tax_benefit_system = _get_tax_benefit_system(baseline, 'r', ['e'], []) + ren_tax_benefit_system = _get_tax_benefit_system(baseline, 'r', ['e'], ['n']) + n_tax_benefit_system = _get_tax_benefit_system(baseline, [], [], ['n']) + + assert re_tax_benefit_system != ren_tax_benefit_system + assert ren_tax_benefit_system != n_tax_benefit_system + + def test_performance_graph_option_output(): test = {'input': {'salary': {'2017-01': 2000}}, 'output': {'salary': {'2017-01': 2000}}} test_item = TestItem(test) diff --git a/tests/core/yaml_tests/test_with_neutralized_variables.yaml b/tests/core/yaml_tests/test_with_neutralized_variables.yaml new file mode 100644 index 0000000000..58110c3d58 --- /dev/null +++ b/tests/core/yaml_tests/test_with_neutralized_variables.yaml @@ -0,0 +1,17 @@ +- name: "Result outside neutralized variables" + period: 2021-01 + neutralized_variables: + - housing_allowance + input: + age: 30 + output: + basic_income: 600 + +- name: "Result within neutralized variables" + period: 2021-01 + neutralized_variables: + - basic_income + input: + age: 30 + output: + basic_income: 0