Initial writeup of Python calling to housing benefits

This commit is contained in:
Denis Merigoux 2022-09-21 17:37:57 +02:00
parent e53f6b6087
commit 431a0b99c1
No known key found for this signature in database
GPG Key ID: EE99DCFA365C3EE3
4 changed files with 464 additions and 807 deletions

View File

@ -50,136 +50,102 @@ function run_computation_AF(log) {
function run_computation_AL(log) {
var result = Law.computeAidesAuLogement({
dateCouranteIn: "2022-01-01",
menageIn: {
prestationsRecues: [
{ kind: "AllocationSoutienEnfantHandicape", payload: null },
{ kind: "ComplementFamilial", payload: null },
{ kind: "AllocationsFamiliales", payload: null },
"menageIn": {
"prestationsRecues": [],
"logement": {
"residencePrincipale": true,
"estEhpadOuMaisonAutonomieL31312Asf": false,
"modeOccupation": {
"kind": "Locataire",
"payload": {
"bailleur": {
"kind": "BailleurPrive"
},
"beneficiaireAideAdulteOuEnfantHandicapes": false,
"logementEstChambre": false,
"colocation": false,
"ageesOuHandicapAdultesHebergeesOnereuxParticuliers": false,
"reductionLoyerSolidarite": 0,
"logementMeubleD8422": false,
"changementLogementD8424": {
"kind": "PasDeChangement",
"payload": null
},
"loyerPrincipal": 450
}
},
"proprietaire": {
"kind": "Autre",
"payload": null
},
"loueOuSousLoueADesTiers": {
"kind": "Non"
},
"usufruit": {
"kind": "Autre",
"payload": null
},
"logementDecentL89462": true,
"zone": {
"kind": "Zone2"
},
"surfaceMCarres": 65
},
"personnesACharge": [
{
"kind": "EnfantACharge",
"payload": {
"beneficieTitrePersonnelAidePersonnelleLogement": false,
"aDejaOuvertDroitAuxAllocationsFamiliales": true,
"remunerationMensuelle": 0,
"obligationScolaire": {
"kind": "Pendant"
},
"situationGardeAlternee": {
"kind": "PasDeGardeAlternee"
},
"dateDeNaissance": "2015-01-01",
"identifiant": 0
}
},
{
"kind": "EnfantACharge",
"payload": {
"beneficieTitrePersonnelAidePersonnelleLogement": false,
"aDejaOuvertDroitAuxAllocationsFamiliales": true,
"remunerationMensuelle": 0,
"obligationScolaire": {
"kind": "Pendant"
},
"situationGardeAlternee": {
"kind": "PasDeGardeAlternee"
},
"dateDeNaissance": "2016-01-01",
"identifiant": 1
}
}
],
situationFamiliale: {
kind: "Maries",
payload: "2010-11-26",
},
personnesACharge: [
{
kind: "EnfantACharge",
payload: {
beneficieTitrePersonnelAidePersonnelleLogement: false,
priseEnCharge: { kind: "EffectiveEtPermanente", payload: null },
age: 19,
identifiant: 0,
aDejaOuvertDroitAuxAllocationsFamiliales: true,
dateDeNaissance: "2003-01-01",
remunerationMensuelle: 0,
obligationScolaire: { kind: "Apres", payload: null },
situationGardeAlternee: {
kind: "GardeAlterneeCoefficientPriseEnCharge",
payload: 0.5,
},
},
},
{
kind: "EnfantACharge",
payload: {
beneficieTitrePersonnelAidePersonnelleLogement: false,
priseEnCharge: { kind: "EffectiveEtPermanente", payload: null },
age: 11,
identifiant: 1,
aDejaOuvertDroitAuxAllocationsFamiliales: true,
dateDeNaissance: "2011-01-01",
remunerationMensuelle: 0,
obligationScolaire: { kind: "Pendant", payload: null },
situationGardeAlternee: {
kind: "PasDeGardeAlternee",
payload: null,
},
},
},
{
kind: "EnfantACharge",
payload: {
beneficieTitrePersonnelAidePersonnelleLogement: false,
priseEnCharge: { kind: "EffectiveEtPermanente", payload: null },
age: 8,
identifiant: 2,
aDejaOuvertDroitAuxAllocationsFamiliales: true,
dateDeNaissance: "2014-01-01",
remunerationMensuelle: 0,
obligationScolaire: { kind: "Pendant", payload: null },
situationGardeAlternee: {
kind: "PasDeGardeAlternee",
payload: null,
},
},
},
],
logement: {
zone: { kind: "Zone1", payload: null },
residencePrincipale: true,
estEhpadOuMaisonAutonomieL31312Asf: false,
modeOccupation: {
kind: "Locataire",
payload: {
bailleur: {
typeBailleur: { kind: "BailleurPrive", payload: null },
respecteConventionTitreV: true,
respecteConventionTitreII: true,
construitAmelioreConditionsL83114: false,
acquisitionAidesEtatPretTitreIIOuLivreIII: false,
},
},
},
proprietaire: { kind: "Autre", payload: null },
loueOuSousLoueADesTiers: { kind: "Non", payload: null },
usufruit: { kind: "Autre", payload: null },
logementDecentL89462: true,
loyersL8233: 700,
surfaceMCarres: 80,
estAncienL8312: false,
situeCommuneDesequilibreL8312: false,
},
nombreAutresOccupantsLogement: 1,
conditionRattacheFoyerFiscalParentIfi: false,
nombreEnfantsANaitreApresTroisiemeMoisGrossesse: 0,
enfantANaitreApresQuatriemeMoisGrossesse: false,
dateNaissanceTroisiemeEnfantOuDernierSiPlus: {
kind: "PlusDeTroisEnfants",
payload: {
kind: "DateDeNaissance",
payload: "2014-09-15",
},
"nombreAutresOccupantsLogement": 0,
"situationFamiliale": {
"kind": "Concubins",
"payload": null
},
"conditionRattacheFoyerFiscalParentIfi": false,
"nombreEnfantsANaitreApresTroisiemeMoisGrossesse": 0,
},
demandeurIn: {
personneHebergeeCentreSoinLL162223SecuriteSociale: false,
satisfaitConditionsL5122CodeSecuriteSociale: true,
ageDemandeur: 52,
dateNaissance: "1970-05-02",
contratDeTravail: { kind: "CDI", payload: null },
nationalite: { kind: "Francaise", payload: null },
patrimoine: {
produisantRevenuPeriodeR82233R8224: 0,
neProduisantPasRevenuPeriodeR82233R8224: 0,
"demandeurIn": {
"nationalite": {
"kind": "Francaise"
},
},
informationsCalculIn: {
kind: "InfosLocatif",
payload: {
loyerPrincipal: 1700,
beneficiaireAideAdulteOuEnfantHandicapes: false,
logementEstChambre: false,
colocation: false,
ageesOuHandicapAdultesHebergeesOnereuxParticuliers: false,
reductionLoyerSolidarite: 0,
logementMeubleD8422: false,
changementLogementD8424: {
kind: "PasDeChangement",
payload: null,
},
"patrimoine": {
"produisantRevenuPeriodeR82233R8224": 0,
"neProduisantPasRevenuPeriodeR82233R8224": 0
},
"personneHebergeeCentreSoinLL162223SecuriteSociale": false,
"dateNaissance": "1992-01-01"
},
ressourcesMenagePrisesEnCompteIn: 20000,
"dateCouranteIn": "2022-05-01",
"ressourcesMenagePrisesEnCompteIn": 11500
});
if (log) {
console.log(

View File

@ -1,8 +1,10 @@
#!python3
from datetime import date
from src.allocations_familiales import PriseEnCharge_Code, Collectivite_Code
from src.api import allocations_familiales, Enfant
from tkinter import N
from src.aides_logement import ModeOccupation_Code, Nationalite_Code, PrestationRecue_Code, SituationFamiliale_Code, SituationGardeAlternee_Code, SituationObligationScolaire_Code, TypeBailleur_Code, ZoneDHabitation_Code
from src.allocations_familiales import PriseEnCharge_Code, Collectivite_Code, SituationObligationScolaire
from src.api import EnfantAPL, InfosLocation, aides_logement, allocations_familiales, Enfant
from catala.runtime import LogEvent, LogEventCode, reset_log, retrieve_log
import timeit
import argparse
@ -33,6 +35,67 @@ def call_allocations_familiales() -> float:
)
def call_aides_logement() -> float:
return aides_logement(
date_courante=date(2022, 1, 1),
ressources_menage_prises_en_compte=11_500.0,
date_naissance_demandeur=date(1992, 1, 1),
nationalite_demandeur=Nationalite_Code.Francaise,
patrimoine_produisant_revenu=0.0,
patrimoine_ne_produisant_pas_revenu=0.0,
personne_hebergee_centre_soins=False,
personne_rattache_foyer_fiscal_parent_ifi=False,
nombre_autres_occupants_logement_hors_menage=0,
enfant_a_naitre_apres_quatrieme_mois_grossesse=False,
situation_familiale=SituationFamiliale_Code.Concubins,
date_mariage=None,
prestations_recues=[],
residence_principale=True,
logement_est_maison_de_retraite=False,
surface_logement_m_carres=65,
zone=ZoneDHabitation_Code.Zone1,
parts_logement_propriete_famille=None,
parts_logement_usufruits_famille=None,
date_naissance_et_conformite_sous_locataire_tiers=None,
mode_occupation=ModeOccupation_Code.Locataire,
personnes_a_charge=[
EnfantAPL(
identifiant=1,
beneficie_titre_personnel_aide_personnelle_logement=False,
a_deja_ouvert_droit_aux_allocations_familiales=True,
date_de_naissance=date(2015, 1, 1),
remuneration_mensuelle=0.0,
obligation_scolaire=SituationObligationScolaire_Code.Pendant,
situation_garde_alternee=SituationGardeAlternee_Code.PasDeGardeAlternee,
coefficient_garde_alternee=None
),
EnfantAPL(
identifiant=2,
beneficie_titre_personnel_aide_personnelle_logement=False,
a_deja_ouvert_droit_aux_allocations_familiales=True,
date_de_naissance=date(2016, 1, 1),
remuneration_mensuelle=0.0,
obligation_scolaire=SituationObligationScolaire_Code.Pendant,
situation_garde_alternee=SituationGardeAlternee_Code.PasDeGardeAlternee,
coefficient_garde_alternee=None)
],
logement_est_decent=True,
infos_specifiques=InfosLocation(
loyer_principal=450,
beneficiaire_aide_adulte_ou_enfant_handicapes=False,
colocation=False,
logement_est_chambre=False,
agees_ou_handicap_adultes_hebergees_onereux_particuliers=False,
logement_meuble_d842_2=False,
ancien_loyer_et_apl_relogement=None,
type_bailleur=TypeBailleur_Code.BailleurPrive,
bailleur_conventionne=None,
reduction_loyer_solidarite=None
)
)
def benchmark_iteration():
money_given = call_allocations_familiales()
assert (money_given == 99.46)

View File

@ -1,5 +1,9 @@
from abc import ABC
from catala.runtime import *
from .allocations_familiales import Collectivite, Collectivite_Code, InterfaceAllocationsFamilialesIn, PriseEnCharge, interface_allocations_familiales, PriseEnCharge_Code, EnfantEntree, InterfaceAllocationsFamilialesIn
from .aides_logement import AutrePersonneACharge, CategorieEquivalenceLoyerAllocationLogementFoyer, CategorieEquivalenceLoyerAllocationLogementFoyer_Code, ChangementLogementD8424, ChangementLogementD8424_Code, ConventionANHA, ConventionBailleurSocial, EnfantACharge, InfosChangementLogementD8424, Location, Logement, LogementFoyer, LoueOuSousLoueADesTiers, LoueOuSousLoueADesTiers_Code, Menage, ModeOccupation, ModeOccupation_Code, Nationalite, Nationalite_Code, NeufOuAncien, NeufOuAncien_Code, ParentOuAutre, ParentOuAutre_Code, Parente, Parente_Code, Patrimoine, PersonneACharge, PersonneSousLocation, PrestationRecue, PrestationRecue_Code, Pret, Proprietaire, SituationFamiliale, SituationFamiliale_Code, SituationGardeAlternee_Code, SituationObligationScolaire_Code, TitulairePret, TitulairePret_Code, TypeBailleur, TypeBailleur_Code, TypeLogementFoyer, TypeLogementFoyer_Code, TypePret, TypePret_Code, TypeTravauxLogementD83215, TypeTravauxLogementD83215_Code, TypeTravauxLogementR8425, TypeTravauxLogementR8425_Code, ZoneDHabitation, ZoneDHabitation_Code, calculette_aides_au_logement_garde_alternee, CalculetteAidesAuLogementGardeAlterneeIn, ressources_aides_personnelle_logement, Demandeur, PersonneACharge_Code, SituationObligationScolaire, SituationGardeAlternee
# Allocations familiales
class Enfant:
@ -51,3 +55,308 @@ def allocations_familiales(
i_avait_enfant_a_charge_avant_1er_janvier_2012_in=avait_enfant_a_charge_avant_1er_janvier_2012
))
return money_to_float(out.i_montant_verse_out)
# Aides au logement
class PersonneAChargeAPL(ABC):
pass
class EnfantAPL(PersonneAChargeAPL):
def __init__(self, identifiant: int, beneficie_titre_personnel_aide_personnelle_logement: bool,
a_deja_ouvert_droit_aux_allocations_familiales: bool,
date_de_naissance: datetime.date,
remuneration_mensuelle: float,
obligation_scolaire: SituationObligationScolaire_Code,
situation_garde_alternee: SituationGardeAlternee_Code,
coefficient_garde_alternee: Optional[float]):
self.identifiant = identifiant
self.beneficie_titre_personnel_aide_personnelle_logement = beneficie_titre_personnel_aide_personnelle_logement
self.a_deja_ouvert_droit_aux_allocations_familiales = a_deja_ouvert_droit_aux_allocations_familiales
self.date_de_naissance = date_de_naissance,
self.remuneration_mensuelle = remuneration_mensuelle
self.obligation_scolaire = obligation_scolaire
self.situation_garde_alternee = situation_garde_alternee
self.coefficient_garde_alternee = coefficient_garde_alternee
class ParentAPL(PersonneAChargeAPL):
def __init__(self, date_naissance: datetime.date,
ressources: float, ascendant_descendant_collateral_deuxieme_troisieme_degre: bool,
parente: Parente_Code,
incapacite_80_pourcent_ou_restriction_emploi: bool,
beneficiaire_l161_19_l351_8_l643_3_secu: bool,
titulaire_allocation_personne_agee: bool):
self.date_naissance = date_naissance
self.ressources = ressources
self.ascendant_descendant_collateral_deuxieme_troisieme_degre = ascendant_descendant_collateral_deuxieme_troisieme_degre
self.parente = parente
self.incapacite_80_pourcent_ou_restriction_emploi = incapacite_80_pourcent_ou_restriction_emploi
self.beneficiaire_l161_19_l351_8_l643_3_secu = beneficiaire_l161_19_l351_8_l643_3_secu
self.titulaire_allocation_personne_agee = titulaire_allocation_personne_agee
class InfosSpecifiques(ABC):
pass
class InfosLocation(InfosSpecifiques):
def __init__(self,
loyer_principal: float,
beneficiaire_aide_adulte_ou_enfant_handicapes: bool,
logement_est_chambre: bool,
colocation: bool,
agees_ou_handicap_adultes_hebergees_onereux_particuliers: bool,
logement_meuble_d842_2: bool,
ancien_loyer_et_apl_relogement: Optional[Tuple[float, float]],
type_bailleur: TypeBailleur_Code,
bailleur_conventionne: Optional[bool],
reduction_loyer_solidarite: Optional[float]):
self.loyer_principal = loyer_principal
self.beneficiaire_aide_adulte_ou_enfant_handicapes = beneficiaire_aide_adulte_ou_enfant_handicapes
self.logement_est_chambre = logement_est_chambre
self.colocation = colocation
self.agees_ou_handicap_adultes_hebergees_onereux_particuliers = agees_ou_handicap_adultes_hebergees_onereux_particuliers
self.logement_meuble_d842_2 = logement_meuble_d842_2
self.ancien_loyer_et_apl_relogement = ancien_loyer_et_apl_relogement
self.type_bailleur = type_bailleur
self.bailleur_conventionne = bailleur_conventionne
self.reduction_loyer_solidarite = reduction_loyer_solidarite
class InfosLogementFoyer(InfosSpecifiques):
def __init__(self,
type: TypeLogementFoyer_Code,
remplit_conditions_r832_21: bool,
conventionne_livre_III_titre_V_chap_III: bool,
date_conventionnement: datetime.date,
construit_application_loi_1957_12_III: bool,
redevance: float,
categorie_equivalence_loyer_d842_16: CategorieEquivalenceLoyerAllocationLogementFoyer_Code):
self.type = type
self.remplit_conditions_r832_21 = remplit_conditions_r832_21
self.conventionne_livre_III_titre_V_chap_III = conventionne_livre_III_titre_V_chap_III
self.date_conventionnement = date_conventionnement
self.construit_application_loi_1957_12_III = construit_application_loi_1957_12_III
self.redevance = redevance
self.categorie_equivalence_loyer_d842_16 = categorie_equivalence_loyer_d842_16
class InfosAccessionPropriete(InfosSpecifiques):
def __init__(self,
logement_situe_commune_desequilibre_l831_2: bool,
mensualite_principale: float,
charges_mensuelles_pret: float,
date_entree_logement: datetime.date,
local_habite_premiere_fois_beneficiaire: bool,
copropriete: bool,
situation_r822_11_13_17: bool,
type_travaux_logement_d832_15: TypeTravauxLogementD83215_Code,
type_travaux_logement_r842_5: TypeTravauxLogementR8425_Code,
anciennete_logement: NeufOuAncien_Code,
ameliore_par_occupant: Optional[bool],
type_pret: TypePret_Code,
date_signature_pret: datetime.date,
titulaire_pret: TitulairePret_Code):
self.logement_situe_commune_desequilibre_l831_2 = logement_situe_commune_desequilibre_l831_2
self.mensualite_principale = mensualite_principale
self.charges_mensuelles_pret = charges_mensuelles_pret
self.date_entree_logement = date_entree_logement
self.local_habite_premiere_fois_beneficiaire = local_habite_premiere_fois_beneficiaire
self.copropriete = copropriete
self.situation_r822_11_13_17 = situation_r822_11_13_17
self.type_travaux_logement_d832_15 = type_travaux_logement_d832_15
self.type_travaux_logement_r842_5 = type_travaux_logement_r842_5
self.anciennete_logement = anciennete_logement
self.ameliore_par_occupant = ameliore_par_occupant
self.type_pret = type_pret
self.date_signature_pret = date_signature_pret
self.titulaire_pret = titulaire_pret
def aides_logement(
date_courante: datetime.date,
ressources_menage_prises_en_compte: float,
date_naissance_demandeur: datetime.date,
nationalite_demandeur: Nationalite_Code,
patrimoine_produisant_revenu: float,
patrimoine_ne_produisant_pas_revenu: float,
personne_hebergee_centre_soins: bool,
personne_rattache_foyer_fiscal_parent_ifi: bool,
nombre_autres_occupants_logement_hors_menage: int,
enfant_a_naitre_apres_quatrieme_mois_grossesse: bool,
situation_familiale: SituationFamiliale_Code,
date_mariage: Optional[datetime.date],
prestations_recues: List[PrestationRecue_Code],
residence_principale: bool,
logement_est_maison_de_retraite: bool,
logement_est_decent: bool,
surface_logement_m_carres: int,
zone: ZoneDHabitation_Code,
parts_logement_propriete_famille: Optional[float],
parts_logement_usufruits_famille: Optional[float],
date_naissance_et_conformite_sous_locataire_tiers: Optional[Tuple[datetime.date, bool]],
mode_occupation: ModeOccupation_Code,
infos_specifiques: InfosSpecifiques,
personnes_a_charge: List[PersonneAChargeAPL],
):
out = calculette_aides_au_logement_garde_alternee(CalculetteAidesAuLogementGardeAlterneeIn(
menage_in=Menage(
prestations_recues=[PrestationRecue(
code=presta, value=Unit()) for presta in prestations_recues],
logement=Logement(
residence_principale=residence_principale,
est_ehpad_ou_maison_autonomie_l313_12_asf=logement_est_maison_de_retraite,
mode_occupation=ModeOccupation(
code=mode_occupation,
value=(Location(
loyer_principal=money_of_decimal(
decimal_of_float(infos_specifiques.loyer_principal)),
beneficiaire_aide_adulte_ou_enfant_handicapes=infos_specifiques.beneficiaire_aide_adulte_ou_enfant_handicapes,
logement_est_chambre=infos_specifiques.logement_est_chambre,
colocation=infos_specifiques.colocation,
agees_ou_handicap_adultes_hebergees_onereux_particuliers=infos_specifiques.agees_ou_handicap_adultes_hebergees_onereux_particuliers,
logement_meuble_d842_2=infos_specifiques.logement_meuble_d842_2,
changement_logement_d842_4=ChangementLogementD8424(
code=ChangementLogementD8424_Code.PasDeChangement if infos_specifiques.ancien_loyer_et_apl_relogement is None else
ChangementLogementD8424_Code.Changement,
value=Unit() if infos_specifiques.ancien_loyer_et_apl_relogement is None else
InfosChangementLogementD8424(ancien_loyer_principal=money_of_decimal(decimal_of_float(infos_specifiques.ancien_loyer_et_apl_relogement[0])),
ancienne_allocation_logement=money_of_decimal(decimal_of_float(infos_specifiques.ancien_loyer_et_apl_relogement[1])))
),
bailleur=TypeBailleur(
code=infos_specifiques.type_bailleur,
value=Unit() if infos_specifiques.type_bailleur == TypeBailleur_Code.BailleurPrive else (
ConventionBailleurSocial(
conventionne_livre_III_titre_V_chap_III=False if infos_specifiques.bailleur_conventionne is None else infos_specifiques.bailleur_conventionne,
reduction_loyer_solidarite_percue=money_of_decimal(decimal_of_float(0.0 if infos_specifiques.reduction_loyer_solidarite is None else infos_specifiques.reduction_loyer_solidarite)))
) if infos_specifiques.type_bailleur == TypeBailleur_Code.BailleurSocial else (
ConventionANHA(
conventionne_livre_III_titre_II_chap_I_sec_3=False if infos_specifiques.bailleur_conventionne is None else infos_specifiques.bailleur_conventionne)
if infos_specifiques.type_bailleur == TypeBailleur_Code.BailleurPriveAvecConventionnementSocial else
None # type: ignore
))
) if isinstance(infos_specifiques, InfosLocation) else
(LogementFoyer(
type=TypeLogementFoyer(
code=infos_specifiques.type, value=Unit()),
remplit_conditions_r832_21=infos_specifiques.remplit_conditions_r832_21,
conventionne_livre_III_titre_V_chap_III=infos_specifiques.conventionne_livre_III_titre_V_chap_III,
date_conventionnement=date_of_datetime(
infos_specifiques.date_conventionnement),
construit_application_loi_1957_12_III=infos_specifiques.construit_application_loi_1957_12_III,
redevance=money_of_decimal(
decimal_of_float(infos_specifiques.redevance)),
categorie_equivalence_loyer_d842_16=CategorieEquivalenceLoyerAllocationLogementFoyer(
code=infos_specifiques.categorie_equivalence_loyer_d842_16,
value=Unit()
)
) if isinstance(infos_specifiques, InfosLogementFoyer) else
(Proprietaire(
logement_situe_commune_desequilibre_l831_2=infos_specifiques.logement_situe_commune_desequilibre_l831_2,
mensualite_principale=money_of_decimal(
decimal_of_float(infos_specifiques.mensualite_principale)),
charges_mensuelles_pret=money_of_decimal(
decimal_of_float(infos_specifiques.charges_mensuelles_pret)),
date_entree_logement=date_of_datetime(
infos_specifiques.date_entree_logement),
local_habite_premiere_fois_beneficiaire=infos_specifiques.local_habite_premiere_fois_beneficiaire,
copropriete=infos_specifiques.copropriete,
situation_r822_11_13_17=infos_specifiques.situation_r822_11_13_17,
type_travaux_logement_d832_15=TypeTravauxLogementD83215(
code=infos_specifiques.type_travaux_logement_d832_15, value=Unit()),
type_travaux_logement_r842_5=TypeTravauxLogementR8425(
code=infos_specifiques.type_travaux_logement_r842_5,
value=Unit()
),
anciennete_logement=NeufOuAncien(code=infos_specifiques.anciennete_logement,
value=Unit() if infos_specifiques.ameliore_par_occupant is None else infos_specifiques.ameliore_par_occupant),
pret=Pret(
type_pret=TypePret(
code=infos_specifiques.type_pret, value=Unit()),
date_signature=date_of_datetime(
infos_specifiques.date_signature_pret),
titulaire_pret=TitulairePret(
code=infos_specifiques.titulaire_pret, value=Unit())
)
) if isinstance(infos_specifiques, InfosAccessionPropriete)
else None # type: ignore
)))
),
proprietaire=ParentOuAutre(
code=ParentOuAutre_Code.Autre if parts_logement_propriete_famille is None else ParentOuAutre_Code.DemandeurOuConjointOuParentOuViaPartsSocietes,
value=Unit() if parts_logement_propriete_famille is None else parts_logement_propriete_famille),
usufruit=ParentOuAutre(
code=ParentOuAutre_Code.Autre if parts_logement_usufruits_famille is None else ParentOuAutre_Code.DemandeurOuConjointOuParentOuViaPartsSocietes,
value=Unit() if parts_logement_usufruits_famille is None else parts_logement_usufruits_famille),
loue_ou_sous_loue_a_des_tiers=LoueOuSousLoueADesTiers(
code=LoueOuSousLoueADesTiers_Code.Non if date_naissance_et_conformite_sous_locataire_tiers is None else LoueOuSousLoueADesTiers_Code.Oui,
value=Unit() if date_naissance_et_conformite_sous_locataire_tiers is None else PersonneSousLocation(
date_naissance_personne_sous_location=date_of_datetime(date_naissance_et_conformite_sous_locataire_tiers[
0]),
conforme_article_l442_1=date_naissance_et_conformite_sous_locataire_tiers[
1]
)
),
logement_decent_l89_462=logement_est_decent,
surface_m_carres=integer_of_int(surface_logement_m_carres),
zone=ZoneDHabitation(code=zone, value=Unit())
),
personnes_a_charge=[
(PersonneACharge(code=PersonneACharge_Code.EnfantACharge,
value=EnfantACharge(
identifiant=integer_of_int(
personne_a_charge.identifiant),
beneficie_titre_personnel_aide_personnelle_logement=personne_a_charge.beneficie_titre_personnel_aide_personnelle_logement,
a_deja_ouvert_droit_aux_allocations_familiales=personne_a_charge.a_deja_ouvert_droit_aux_allocations_familiales,
date_de_naissance=date_of_datetime(
personne_a_charge.date_de_naissance[0]),
remuneration_mensuelle=money_of_decimal(
decimal_of_float(personne_a_charge.remuneration_mensuelle)),
obligation_scolaire=SituationObligationScolaire(
code=personne_a_charge.obligation_scolaire, value=Unit()),
situation_garde_alternee=SituationGardeAlternee(code=personne_a_charge.situation_garde_alternee,
value=Unit() if personne_a_charge.coefficient_garde_alternee is None else personne_a_charge.coefficient_garde_alternee)
))
if isinstance(personne_a_charge, EnfantAPL)
else (PersonneACharge(
code=PersonneACharge_Code.AutrePersonneACharge,
value=AutrePersonneACharge(
date_naissance=date_of_datetime(
personne_a_charge.date_naissance),
ressources=money_of_decimal(
decimal_of_float(personne_a_charge.ressources)),
ascendant_descendant_collateral_deuxieme_troisieme_degre=personne_a_charge.ascendant_descendant_collateral_deuxieme_troisieme_degre,
incapacite_80_pourcent_ou_restriction_emploi=personne_a_charge.incapacite_80_pourcent_ou_restriction_emploi,
beneficiaire_l161_19_l351_8_l643_3_secu=personne_a_charge.beneficiaire_l161_19_l351_8_l643_3_secu,
titulaire_allocation_personne_agee=personne_a_charge.titulaire_allocation_personne_agee,
parente=Parente(
code=personne_a_charge.parente, value=Unit())
)) if isinstance(personne_a_charge, ParentAPL)
else None # type: ignore
)) for personne_a_charge in personnes_a_charge],
nombre_autres_occupants_logement=integer_of_int(
nombre_autres_occupants_logement_hors_menage),
situation_familiale=SituationFamiliale(
code=situation_familiale,
value=Unit() if date_mariage is None else date_of_datetime(date_mariage)
),
condition_rattache_foyer_fiscal_parent_ifi=personne_rattache_foyer_fiscal_parent_ifi,
enfant_a_naitre_apres_quatrieme_mois_grossesse=enfant_a_naitre_apres_quatrieme_mois_grossesse
),
demandeur_in=Demandeur(
date_naissance=date_of_datetime(date_naissance_demandeur),
nationalite=Nationalite(code=nationalite_demandeur, value=Unit()),
patrimoine=Patrimoine(
produisant_revenu_periode_r822_3_3_r822_4=money_of_decimal(decimal_of_float(
patrimoine_produisant_revenu)),
ne_produisant_pas_revenu_periode_r822_3_3_r822_4=money_of_decimal(decimal_of_float(
patrimoine_ne_produisant_pas_revenu))
),
personne_hebergee_centre_soin_l_L162_22_3_securite_sociale=personne_hebergee_centre_soins,
),
date_courante_in=date_of_datetime(date_courante),
ressources_menage_prises_en_compte_in=money_of_decimal(
decimal_of_float(ressources_menage_prises_en_compte)),
))

View File

@ -1,681 +0,0 @@
"""
.. module:: catala_runtime
:platform: Unix, Windows
:synopsis: The Python bindings for the functions used in the generated Catala code
:noindex:
.. moduleauthor:: Denis Merigoux <denis.merigoux@inria.fr>
"""
# This file should be in sync with compiler/runtime.{ml, mli} !
from this import d
from gmpy2 import log2, mpz, mpq, mpfr, t_divmod, f_div, sign # type: ignore
import datetime
import calendar
import dateutil.relativedelta
from typing import NewType, List, Callable, Tuple, Optional, TypeVar, Iterable, Union, Any
from functools import reduce
from enum import Enum
import copy
Alpha = TypeVar('Alpha')
Beta = TypeVar('Beta')
# ============
# Type classes
# ============
class Integer:
def __init__(self, value: Union[str, int]) -> None:
self.value = mpz(value)
def __add__(self, other: 'Integer') -> 'Integer':
return Integer(self.value + other.value)
def __sub__(self, other: 'Integer') -> 'Integer':
return Integer(self.value - other.value)
def __mul__(self, other: 'Integer') -> 'Integer':
return Integer(self.value * other.value)
def __truediv__(self, other: 'Integer') -> 'Integer':
return Integer(self.value // other.value)
def __neg__(self: 'Integer') -> 'Integer':
return Integer(- self.value)
def __lt__(self, other: 'Integer') -> bool:
return self.value < other.value
def __le__(self, other: 'Integer') -> bool:
return self.value <= other.value
def __gt__(self, other: 'Integer') -> bool:
return self.value > other.value
def __ge__(self, other: 'Integer') -> bool:
return self.value >= other.value
def __ne__(self, other: object) -> bool:
if isinstance(other, Integer):
return self.value != other.value
else:
return True
def __eq__(self, other: object) -> bool:
if isinstance(other, Integer):
return self.value == other.value
else:
return False
def __str__(self) -> str:
return self.value.__str__()
def __repr__(self) -> str:
return f"Integer({self.value.__repr__()})"
class Decimal:
def __init__(self, value: Union[str, int, float]) -> None:
self.value = mpq(value)
def __add__(self, other: 'Decimal') -> 'Decimal':
return Decimal(self.value + other.value)
def __sub__(self, other: 'Decimal') -> 'Decimal':
return Decimal(self.value - other.value)
def __mul__(self, other: 'Decimal') -> 'Decimal':
return Decimal(self.value * other.value)
def __truediv__(self, other: 'Decimal') -> 'Decimal':
return Decimal(self.value / other.value)
def __neg__(self: 'Decimal') -> 'Decimal':
return Decimal(- self.value)
def __lt__(self, other: 'Decimal') -> bool:
return self.value < other.value
def __le__(self, other: 'Decimal') -> bool:
return self.value <= other.value
def __gt__(self, other: 'Decimal') -> bool:
return self.value > other.value
def __ge__(self, other: 'Decimal') -> bool:
return self.value >= other.value
def __ne__(self, other: object) -> bool:
if isinstance(other, Decimal):
return self.value != other.value
else:
return True
def __eq__(self, other: object) -> bool:
if isinstance(other, Decimal):
return self.value == other.value
else:
return False
def __str__(self) -> str:
return "{}".format(mpfr(self.value))
def __repr__(self) -> str:
return f"Decimal({self.value.__repr__()})"
class Money:
def __init__(self, value: Integer) -> None:
self.value = value
def __add__(self, other: 'Money') -> 'Money':
return Money(self.value + other.value)
def __sub__(self, other: 'Money') -> 'Money':
return Money(self.value - other.value)
def __mul__(self, other: Decimal) -> 'Money':
cents = self.value.value
coeff = other.value
# TODO: change, does not work with negative values. Must divide the
# absolute values and then multiply by the resulting sign.
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))
def __neg__(self: 'Money') -> 'Money':
return Money(- self.value)
def __lt__(self, other: 'Money') -> bool:
return self.value < other.value
def __le__(self, other: 'Money') -> bool:
return self.value <= other.value
def __gt__(self, other: 'Money') -> bool:
return self.value > other.value
def __ge__(self, other: 'Money') -> bool:
return self.value >= other.value
def __ne__(self, other: object) -> bool:
if isinstance(other, Money):
return self.value != other.value
else:
return True
def __eq__(self, other: object) -> bool:
if isinstance(other, Money):
return self.value == other.value
else:
return False
def __str__(self) -> str:
return "${:.2}".format(self.value.value / 100)
def __repr__(self) -> str:
return f"Money({self.value.__repr__()})"
class Date:
def __init__(self, value: datetime.date) -> None:
self.value = value
def __add__(self, other: 'Duration') -> 'Date':
return Date(self.value + other.value)
def __sub__(self, other: 'Date') -> 'Duration':
return Duration(dateutil.relativedelta.relativedelta(self.value, other.value))
def __lt__(self, other: 'Date') -> bool:
return self.value < other.value
def __le__(self, other: 'Date') -> bool:
return self.value <= other.value
def __gt__(self, other: 'Date') -> bool:
return self.value > other.value
def __ge__(self, other: 'Date') -> bool:
return self.value >= other.value
def __ne__(self, other: object) -> bool:
if isinstance(other, Date):
return self.value != other.value
else:
return True
def __eq__(self, other: object) -> bool:
if isinstance(other, Date):
return self.value == other.value
else:
return False
def __str__(self) -> str:
return self.value.__str__()
def __repr__(self) -> str:
return f"Date({self.value.__repr__()})"
class Duration:
def __init__(self, value: dateutil.relativedelta.relativedelta) -> None:
self.value = value
def __add__(self, other: 'Duration') -> 'Duration':
return Duration(self.value + other.value)
def __sub__(self, other: 'Duration') -> 'Duration':
return Duration(self.value - other.value)
def __neg__(self: 'Duration') -> 'Duration':
return Duration(- self.value)
def __truediv__(self, other: 'Duration') -> Decimal:
x = self.value.normalized()
y = other.value.normalized()
if (x.years != 0 or y.years != 0 or x.months != 0 or y.months != 0):
raise Exception("Can only divide durations expressed in days")
else:
return Decimal(x.days / y.days)
def __mul__(self: 'Duration', rhs: Integer) -> 'Duration':
return Duration(
dateutil.relativedelta.relativedelta(years=self.value.years * rhs.value,
months=self.value.months * rhs.value,
days=self.value.days * rhs.value))
def __lt__(self, other: 'Duration') -> bool:
x = self.value.normalized()
y = other.value.normalized()
if (x.years != 0 or y.years != 0 or x.months != 0 or y.months != 0):
raise Exception("Can only compare durations expressed in days")
else:
return x.days < y.days
def __le__(self, other: 'Duration') -> bool:
x = self.value.normalized()
y = other.value.normalized()
if (x.years != 0 or y.years != 0 or x.months != 0 or y.months != 0):
raise Exception("Can only compare durations expressed in days")
else:
return x.days <= y.days
def __gt__(self, other: 'Duration') -> bool:
x = self.value.normalized()
y = other.value.normalized()
if (x.years != 0 or y.years != 0 or x.months != 0 or y.months != 0):
raise Exception("Can only compare durations expressed in days")
else:
return x.days > y.days
def __ge__(self, other: 'Duration') -> bool:
x = self.value.normalized()
y = other.value.normalized()
if (x.years != 0 or y.years != 0 or x.months != 0 or y.months != 0):
raise Exception("Can only compare durations expressed in days")
else:
return x.days >= y.days
def __ne__(self, other: object) -> bool:
if isinstance(other, Duration):
return self.value != other.value
else:
return True
def __eq__(self, other: object) -> bool:
if isinstance(other, Duration):
return self.value == other.value
else:
return False
def __str__(self) -> str:
return self.value.__str__()
def __repr__(self) -> str:
return f"Duration({self.value.__repr__()})"
class Unit:
def __init__(self) -> None:
...
def __eq__(self, other: object) -> bool:
if isinstance(other, Unit):
return True
else:
return False
def __ne__(self, other: object) -> bool:
if isinstance(other, Unit):
return False
else:
return True
def __str__(self) -> str:
return "()"
def __repr__(self) -> str:
return "Unit()"
class SourcePosition:
def __init__(self,
filename: str,
start_line: int,
start_column: int,
end_line: int,
end_column: int,
law_headings: List[str]) -> None:
self.filename = filename
self.start_line = start_line
self.start_column = start_column
self.end_line = end_line
self.end_column = end_column
self.law_headings = law_headings
def __str__(self) -> str:
return "in file {}, from {}:{} to {}:{}".format(
self.filename, self.start_line, self.start_column, self.end_line, self.end_column)
# ==========
# Exceptions
# ==========
class EmptyError(Exception):
pass
class AssertionFailed(Exception):
def __init__(self, source_position: SourcePosition) -> None:
self.source_position = SourcePosition
class ConflictError(Exception):
def __init__(self, source_position: SourcePosition) -> None:
self.source_position = SourcePosition
class NoValueProvided(Exception):
def __init__(self, source_position: SourcePosition) -> None:
self.source_position = SourcePosition
class AssertionFailure(Exception):
def __init__(self, source_position: SourcePosition) -> None:
self.source_position = SourcePosition
# ============================
# Constructors and conversions
# ============================
# -----
# Money
# -----
def money_of_cents_string(v: str) -> Money:
return Money(Integer(v))
def money_of_units_int(v: int) -> Money:
return Money(Integer(v) * Integer(100))
def money_of_cents_integer(v: Integer) -> Money:
return Money(v)
def money_to_float(m: Money) -> float:
return float(mpfr(mpq(m.value.value, 100)))
def money_to_string(m: Money) -> str:
return str(money_to_float(m))
def money_to_cents(m: Money) -> Integer:
return m.value
def money_round(m: Money) -> Money:
res, remainder = t_divmod(m, 100)
if remainder < 50:
return res * 100
else:
return (res + sign(res)) * 100
def money_of_decimal(m: Decimal) -> Money:
"""
Warning: rounds to nearest cent.
"""
return Money(mpz(m.value))
# --------
# Decimals
# --------
def decimal_of_string(d: str) -> Decimal:
return Decimal(d)
def decimal_to_float(d: Decimal) -> float:
return float(mpfr(d.value))
def decimal_of_float(d: float) -> Decimal:
return Decimal(d)
def decimal_of_integer(d: Integer) -> Decimal:
return Decimal(d.value)
def decimal_to_string(precision: int, i: Decimal) -> str:
return "{1:.{0}}".format(precision, mpfr(i.value, precision * 10 // 2))
def decimal_round(q: Decimal) -> Decimal:
# Implements the workaround by
# https://gmplib.org/list-archives/gmp-discuss/2009-May/003767.html *)
return f_div(2*q.numerator + q.denominator, 2*q.denominator) # type:ignore
def decimal_of_money(m: Money) -> Decimal:
return Decimal(f_div(mpq(m.value), mpq(100)))
# --------
# Integers
# --------
def integer_of_string(s: str) -> Integer:
return Integer(s)
def integer_to_string(d: Integer) -> str:
return str(d.value)
def integer_of_int(d: int) -> Integer:
return Integer(d)
def integer_to_int(d: Integer) -> int:
return int(d.value)
def integer_exponentiation(i: Integer, e: int) -> Integer:
return i ** e # type: ignore
def integer_log2(i: Integer) -> int:
return int(log2(i.value))
# -----
# Dates
# -----
def day_of_month_of_date(d: Date) -> Integer:
return integer_of_int(d.value.day)
def month_number_of_date(d: Date) -> Integer:
return integer_of_int(d.value.month)
def year_of_date(d: Date) -> Integer:
return integer_of_int(d.value.year)
def date_to_string(d: Date) -> str:
return "{}".format(d.value)
def date_of_numbers(year: int, month: int, day: int) -> Date:
# The datetime.date does not take year=0 as an entry, we trick it into
# 1 in that case because year=0 cases don't care about the actual year
return Date(datetime.date(year if year != 0 else 1, month, day))
def date_of_datetime(d: datetime.date) -> Date:
return Date(d)
def first_day_of_month(d: Date) -> Date:
return Date(datetime.date(d.value.year, d.value.month, 1))
def last_day_of_month(d: Date) -> Date:
return Date(datetime.date(d.value.year, d.value.month, calendar.monthrange(d.value.year, d.value.month)[1]))
# ---------
# Durations
# ---------
def duration_of_numbers(years: int, months: int, days: int) -> Duration:
return Duration(dateutil.relativedelta.relativedelta(years=years, months=months, days=days))
def duration_to_years_months_days(d: Duration) -> Tuple[int, int, int]:
return (d.value.years, d.value.months, d.value.days) # type: ignore
def duration_to_string(s: Duration) -> str:
return "{}".format(s.value)
# -----
# Lists
# -----
def list_fold_left(f: Callable[[Alpha, Beta], Alpha], init: Alpha, l: List[Beta]) -> Alpha:
return reduce(f, l, init)
def list_filter(f: Callable[[Alpha], bool], l: List[Alpha]) -> List[Alpha]:
return [i for i in l if f(i)]
def list_map(f: Callable[[Alpha], Beta], l: List[Alpha]) -> List[Beta]:
return [f(i) for i in l]
def list_length(l: List[Alpha]) -> Integer:
return Integer(len(l))
# ========
# Defaults
# ========
def handle_default(
pos: SourcePosition,
exceptions: List[Callable[[Unit], Alpha]],
just: Callable[[Unit], Alpha],
cons: Callable[[Unit], Alpha]
) -> Alpha:
acc: Optional[Alpha] = None
for exception in exceptions:
new_val: Optional[Alpha]
try:
new_val = exception(Unit())
except EmptyError:
new_val = None
if acc is None:
acc = new_val
elif not (acc is None) and new_val is None:
pass # acc stays the same
elif not (acc is None) and not (new_val is None):
raise ConflictError(pos)
if acc is None:
if just(Unit()):
return cons(Unit())
else:
raise EmptyError
else:
return acc
def handle_default_opt(
pos: SourcePosition,
exceptions: List[Optional[Any]],
just: Optional[bool],
cons: Optional[Alpha]
) -> Optional[Alpha]:
acc: Optional[Alpha] = None
for exception in exceptions:
if acc is None:
acc = exception
elif not (acc is None) and exception is None:
pass # acc stays the same
elif not (acc is None) and not (exception is None):
raise ConflictError(pos)
if acc is None:
if just is None:
return None
else:
if just:
return cons
else:
return None
else:
return acc
def no_input() -> Callable[[Unit], Alpha]:
def closure(_: Unit):
raise EmptyError
return closure
# This value is used for the Python code generation to trump mypy and forcing
# it to accept dead code. Indeed, when raising an exception during a variable
# definition, mypy complains that the later dead code will not know what
# this variable was. So we give this variable a dead value.
dead_value: Any = 0
# =======
# Logging
# =======
class LogEventCode(Enum):
VariableDefinition = 0
BeginCall = 1
EndCall = 2
DecisionTaken = 3
class LogEvent:
def __init__(self, code: LogEventCode, payload: Union[List[str], SourcePosition, Tuple[List[str], Alpha]]) -> None:
self.code = code
self.payload = payload
log: List[LogEvent] = []
def reset_log():
log = []
def retrieve_log() -> List[LogEvent]:
return log
def log_variable_definition(headings: List[str], value: Alpha) -> Alpha:
log.append(LogEvent(LogEventCode.VariableDefinition,
(headings, copy.deepcopy(value))))
return value
def log_begin_call(headings: List[str], f: Callable[[Alpha], Beta], value: Alpha) -> Beta:
log.append(LogEvent(LogEventCode.BeginCall, headings))
return f(value)
def log_end_call(headings: List[str], value: Alpha) -> Alpha:
log.append(LogEvent(LogEventCode.EndCall, headings))
return value
def log_decision_taken(pos: SourcePosition, value: bool) -> bool:
log.append(LogEvent(LogEventCode.DecisionTaken, pos))
return value