From 03b44f5b1580a072f897320e9ebe3b366e12d978 Mon Sep 17 00:00:00 2001 From: Denis Merigoux Date: Fri, 25 Jun 2021 00:47:12 +0200 Subject: [PATCH] Python backend debugged and tested --- Makefile | 16 ++++++++--- .../tests_allocations_familiales.catala_fr | 23 ++++++++++++++++ french_law/python/Makefile | 5 +++- french_law/python/main.py | 12 +++++---- french_law/python/src/catala.py | 27 ++++++++++++++----- 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index ac3fb5b3..31472130 100644 --- a/Makefile +++ b/Makefile @@ -170,7 +170,7 @@ test_examples: .FORCE tests: test_suite test_examples #> tests_ocaml : Run OCaml unit tests for the Catala-generated code -tests_ocaml: run_french_law_library_tests +tests_ocaml: run_french_law_library_ocaml_tests #> bench_ocaml : Run OCaml benchmarks for the Catala-generated code bench_ocaml: run_french_law_library_benchmark_ocaml @@ -178,6 +178,10 @@ bench_ocaml: run_french_law_library_benchmark_ocaml #> bench_js : Run JS benchmarks for the Catala-generated code bench_js: run_french_law_library_benchmark_js +#> tests_python : Run Python unit tests for the Catala-generated code +tests_python: run_french_law_library_python_tests + + ########################################## # French law library ########################################## @@ -211,12 +215,12 @@ build_french_law_library_ocaml: generate_french_law_library_ocaml format run_french_law_library_benchmark_ocaml: generate_french_law_library_ocaml dune exec --profile release $(FRENCH_LAW_OCAML_LIB_DIR)/bench.exe +run_french_law_library_ocaml_tests: build_french_law_library_ocaml + dune exec $(FRENCH_LAW_OCAML_LIB_DIR)/law_source/unit_tests/run_tests.exe + run_french_law_library_benchmark_js: build_french_law_library_js $(MAKE) -C $(FRENCH_LAW_JS_LIB_DIR) bench -run_french_law_library_tests: generate_french_law_library_ocaml - dune exec $(FRENCH_LAW_OCAML_LIB_DIR)/law_source/unit_tests/run_tests.exe - #> build_french_law_library_js : Builds the JS version of the OCaml French law library build_french_law_library_js: generate_french_law_library_ocaml format dune build --profile release $(FRENCH_LAW_OCAML_LIB_DIR)/api_web.bc.js @@ -233,6 +237,10 @@ type_french_law_library_python: generate_french_law_library_python . $(FRENCH_LAW_PYTHON_LIB_DIR)/env/bin/activate ;\ $(MAKE) -C $(FRENCH_LAW_PYTHON_LIB_DIR) type +run_french_law_library_python_tests: type_french_law_library_python + . $(FRENCH_LAW_PYTHON_LIB_DIR)/env/bin/activate ;\ + $(MAKE) -C $(FRENCH_LAW_PYTHON_LIB_DIR) test + ########################################## # Website assets diff --git a/examples/allocations_familiales/tests/tests_allocations_familiales.catala_fr b/examples/allocations_familiales/tests/tests_allocations_familiales.catala_fr index 09722099..a4a223eb 100644 --- a/examples/allocations_familiales/tests/tests_allocations_familiales.catala_fr +++ b/examples/allocations_familiales/tests/tests_allocations_familiales.catala_fr @@ -193,4 +193,27 @@ champ d'application Test9: définition f.résidence égal à Guadeloupe règle f.personne_charge_effective_permanente_est_parent rempli assertion f.montant_versé = 0€ + +déclaration champ d'application Test10: + contexte f champ d'application InterfaceAllocationsFamiliales + +champ d'application Test10: + définition f.enfants égal à [EnfantEntrée { + -- d_identifiant: 0 + -- d_date_de_naissance: |2003-02-22| + -- d_rémuneration_mensuelle: 0€ + -- d_prise_en_charge: EffectiveEtPermanente + -- d_a_déjà_ouvert_droit_aux_allocations_familiales: vrai + };EnfantEntrée { + -- d_identifiant: 1 + -- d_date_de_naissance: |2013-09-30| + -- d_rémuneration_mensuelle: 300€ + -- d_prise_en_charge: GardeAlternéePartageAllocations + -- d_a_déjà_ouvert_droit_aux_allocations_familiales: vrai + }] + définition f.ressources_ménage égal à 30000 € + définition f.date_courante égal à |2020-04-20| + définition f.résidence égal à Métropole + règle f.personne_charge_effective_permanente_est_parent rempli + assertion f.montant_versé = 99,37€ ``` diff --git a/french_law/python/Makefile b/french_law/python/Makefile index fb021685..d71886e4 100644 --- a/french_law/python/Makefile +++ b/french_law/python/Makefile @@ -7,4 +7,7 @@ type: mypy $(SOURCES) format: - autopep8 --in-place $(SOURCES) \ No newline at end of file + autopep8 --in-place $(SOURCES) + +test: + python main.py \ No newline at end of file diff --git a/french_law/python/main.py b/french_law/python/main.py index a8cf096a..fd3e8f0a 100755 --- a/french_law/python/main.py +++ b/french_law/python/main.py @@ -1,20 +1,20 @@ #!python3 -from src.catala import date_of_numbers, Unit, integer_of_int, money_of_units_int, no_input +from src.catala import date_of_numbers, Unit, integer_of_int, money_of_units_int, no_input, money_to_float from src.allocations_familiales import interface_allocations_familiales, InterfaceAllocationsFamilialesIn, EnfantEntree, PriseEnCharge, PriseEnCharge_Code, Collectivite, Collectivite_Code def main(): - print(interface_allocations_familiales( + out = interface_allocations_familiales( InterfaceAllocationsFamilialesIn( date_courante_in=lambda _: date_of_numbers(2020, 4, 20), enfants_in=lambda _: [ - EnfantEntree(d_identifiant=integer_of_int(0), d_remuneration_mensuelle=integer_of_int(0), + EnfantEntree(d_identifiant=integer_of_int(0), d_remuneration_mensuelle=money_of_units_int(0), d_date_de_naissance=date_of_numbers(2003, 2, 2), d_prise_en_charge=PriseEnCharge( PriseEnCharge_Code.EffectiveEtPermanente, Unit()), d_a_deja_ouvert_droit_aux_allocations_familiales=True), - EnfantEntree(d_identifiant=integer_of_int(1), d_remuneration_mensuelle=integer_of_int(300), + EnfantEntree(d_identifiant=integer_of_int(1), d_remuneration_mensuelle=money_of_units_int(300), d_date_de_naissance=date_of_numbers(2013, 9, 30), d_prise_en_charge=PriseEnCharge( PriseEnCharge_Code.GardeAlterneePartageAllocations, Unit()), @@ -27,7 +27,9 @@ def main(): personne_charge_effective_permanente_remplit_titre_I_in=lambda _: True, enfants_a_charge_in=no_input(), montant_verse_in=no_input() - ))) + )) + money_given = money_to_float(out.montant_verse_out) + assert (money_given == 99.37) if __name__ == '__main__': diff --git a/french_law/python/src/catala.py b/french_law/python/src/catala.py index 345ee748..40d87717 100644 --- a/french_law/python/src/catala.py +++ b/french_law/python/src/catala.py @@ -9,7 +9,7 @@ # This file should be in sync with compiler/runtime.{ml, mli} ! -from gmpy2 import log2, mpz, mpq, mpfr, mpc # type: ignore +from gmpy2 import log2, mpz, mpq, mpfr, t_divmod # type: ignore import datetime import dateutil.relativedelta from typing import NewType, List, Callable, Tuple, Optional, TypeVar, Iterable, Union @@ -66,9 +66,12 @@ class Integer: else: return False + def __str__(self) -> str: + return self.value.__str__() + class Decimal: - def __init__(self, value: Union[str, int, float, Integer]) -> None: + def __init__(self, value: Union[str, int, float]) -> None: self.value = mpq(value) def __add__(self, other: 'Decimal') -> 'Decimal': @@ -110,6 +113,9 @@ class Decimal: else: return False + def __str__(self) -> str: + return self.value.__str__() + class Money: def __init__(self, value: Integer) -> None: @@ -122,7 +128,15 @@ class Money: return Money(self.value - other.value) def __mul__(self, other: Decimal) -> 'Money': - return Money(Integer(self.value.value * other.value)) + cents = self.value.value + coeff = other.value + rat_result = self.value.value * other.value + out = Money(Integer(rat_result)) + res, remainder = t_divmod(rat_result.numerator, rat_result.denominator) + if 2 * remainder >= rat_result.denominator: + return Money(Integer(res + 1)) + else: + return Money(Integer(res)) def __truediv__(self, other: 'Money') -> Decimal: return Decimal(mpq(self.value.value / other.value.value)) @@ -154,6 +168,9 @@ class Money: else: return False + def __str__(self) -> str: + return "${:.2}".format(self.value.value / 100) + class Date: def __init__(self, value: datetime.date) -> None: @@ -449,7 +466,7 @@ def list_map(f: Callable[[Alpha], Beta], l: List[Alpha]) -> List[Beta]: def list_length(l: List[Alpha]) -> Integer: - return mpz(len(l)) + return Integer(len(l)) # ======== # Defaults @@ -506,6 +523,4 @@ def log_end_call(headings: List[str], value: Alpha) -> Alpha: def log_decision_taken(pos: SourcePosition, value: bool) -> bool: - if value: - print(">> Decision taken {}".format(pos)) return value