Commit 9168e25e authored by Christophe Benz's avatar Christophe Benz

Refactor code, add VariablesDefinitions class

parent 2d1e3d43
# -*- coding: utf-8 -*-
from toolz import keyfilter
def find_restituee_variables():
from .generated.variables_definitions import definition_by_variable_name
return list(keyfilter(is_restituee_variable, definition_by_variable_name).keys())
def get_variable_applications(variable_name):
return get_variable_definition(variable_name, {}).get('applications')
def get_variable_definition(variable_name, default=None):
from .generated.variables_definitions import definition_by_variable_name
return definition_by_variable_name.get(variable_name, default)
def get_variable_description(variable_name):
return get_variable_definition(variable_name, {}).get('description')
def get_variable_type(variable_name):
"""Return variable type given its name or None if `variable_name` is not a variable."""
return get_variable_definition(variable_name, {}).get('type')
def has_subtype(tag, variable_name):
return tag in get_variable_definition(variable_name, {}).get('subtypes', [])
def is_constant(variable_name):
from .generated import constants
return variable_name in constants.__dict__
def is_base_variable(variable_name):
return is_calculee_variable(variable_name) and has_subtype('base', variable_name)
def is_calculee_variable(variable_name):
return get_variable_type(variable_name) == 'variable_calculee'
def is_restituee_variable(variable_name):
return is_calculee_variable(variable_name) and has_subtype('restituee', variable_name)
def is_saisie_variable(variable_name):
return get_variable_type(variable_name) == 'variable_saisie'
# Applications tests
def is_batch(variable_name):
return is_variable_in_application(variable_name, 'batch')
def is_variable_in_application(variable_name, application_name):
return application_name in get_variable_definition(variable_name, {}).get('applications', [])
# Variable name sanitization
def sanitized_variable_name(value):
# Python variables must not begin with a digit.
return '_' + value if value[0].isdigit() else value
# -*- coding: utf-8 -*-
import math
......
# -*- coding: utf-8 -*-
# flake8: noqa
# WARNING: This file is automatically generated by a script. No not modify it by hand!
ABAT_ENF_MARIES = 5726
ABAT_FENF_MARIES = 4023
ABAT_UNVIEUX = 1172
AG_LIMFG = 7
DIVGL1 = 1
DIVGL2 = 2
DIVGL3 = 3
DIVGL4 = 4
DIVGL5 = 5
DIVGL6 = 6
LIM10000 = 10000
LIM15000 = 15000
LIM18000 = 18000
LIM25000 = 25000
LIMCELLIER = 300000
LIMCODEV = 20000
LIMDEFREL = 10700
LIMDEPENV = 20000
LIMDEV1DEMI = 5617
LIMDEV1DEMI2 = 4421
LIMDEV1DEMIDOM1 = 6164
LIMDEV1DEMIDOM2 = 5877
LIMDEV1DEMIDOM3 = 5249
LIMDEV1PAR = 24043
LIMDEV1PARGM = 31843
LIMDEV1PARMGR = 29058
LIMDEV2DEMI = 5842
LIMDEV2DEMI2 = 4598
LIMDEV2DEMIDOM1 = 6411
LIMDEV2DEMIDOM2 = 6112
LIMDEV2DEMIDOM3 = 5459
LIMDEV2DEMIDOM4 = 4598
LIMDEV2PAR = 25005
LIMDEV2PARGM = 33117
LIMDEV2PARMGR = 30220
LIMDUFLO = 300000
LIMFIPDOM = 12000
LIMHR1 = 250000
LIMHR2 = 500000
LIMHRTX1 = 500000
LIMIT13A = 10000
LIMIT13B = 10000
LIMLOC = 50000
LIMLOC1 = 45760
LIMLOC2 = 33333
LIMMOB = 2000
LIMMOD = 14145
LIMMODQAR = 1768
LIMPARPAR = 12475
LIMRNBRLOG = 3
LIM_ABTRNGDBL = 23700
LIM_ABTRNGSIMP = 14710
LIM_AFFDBLELIQ = 14
LIM_AGE_ABVIEUX = 65
LIM_AGE_EXO = 65
LIM_AGE_LET_S = 75
LIM_AIDOMI = 12000
LIM_AIDOMI2 = 20000
LIM_AIDOMI3 = 15000
LIM_AMENDE = 12
LIM_ASSUR1 = 23000
LIM_ASSUR2 = 107000
LIM_ASSUR3 = 200000
LIM_BAR1 = 0
LIM_BAR1A = 6011
LIM_BAR2 = 9690
LIM_BAR2A = 11991
LIM_BAR3 = 26764
LIM_BAR3A = 26631
LIM_BAR4 = 71754
LIM_BAR4A = 71397
LIM_BAR5 = 151956
LIM_BAR5A = 151200
LIM_BARN2 = 26030
LIM_BTIMP = 150
LIM_BTREVFONC = 5400
LIM_BTRNI = 6000
LIM_BTRNI10 = 10000
LIM_CONTROLE = 600
LIM_CREDFORM = 760000
LIM_CREDGA = 1500
LIM_CREDRECH = 16000000
LIM_CURE = 10000
LIM_DIFAGRI = 5000
LIM_FAIDOMI = 6900
LIM_FIPCORSE = 12000
LIM_FORET = 1000
LIM_FRACC = 3403
LIM_FSOCNOUV2 = 5717
LIM_INVFOREST = 5700
LIM_INVLOC = 11440
LIM_INVLOC2 = 12500
LIM_INVLOC3 = 8333
LIM_ISFDEC = 1400000
LIM_ISFINF = 1300000
LIM_ISFSUP = 2570000
LIM_MIBPRES = 32900
LIM_MIBPRES2 = 34900
LIM_MIBVEN = 82200
LIM_MIBVEN2 = 90300
LIM_MICFON = 15000
LIM_NAVAG1 = 76000
LIM_NAVAG2 = 152000
LIM_NBGPL = 4
LIM_PATNAT = 10000
LIM_PENSALENF = 5726
LIM_PERPMAX = 30038
LIM_PERPMAXBT = 29626
LIM_PERPMIN = 3755
LIM_PERPMINBT = 3703
LIM_PREMAIDE = 15000
LIM_PREMAIDE2 = 18000
LIM_PRETUD = 1000
LIM_PROSP = 80000
LIM_REPCOMPENS = 30500
LIM_REPORT = 600
LIM_RESTIMO = 100000
LIM_RESTIT = 10000
LIM_SOCNOUV2 = 20000
LIM_SOCREPR = 20000
LIM_SOUFIP = 12000
LIM_SPEBNC = 32900
LIM_SPEBNC2 = 34900
LIM_TELEIR = 20
LIM_TITPRISE = 50000
LIM_TR1_ISF = 800000
LIM_TR2_ISF = 1300000
LIM_TR3_ISF = 2570000
LIM_TR4_ISF = 5000000
LIM_TR5_ISF = 10000000
MAJREV = 1.25
MAJSALDOM = 1500
MAX_CIJEUNE1 = 10060
MAX_CIJEUNE2 = 12060
MIN_CIJEUNE1 = 2970
MIN_CIJEUNE2 = 10060
MIN_DEDPR = 379
MIN_DEDSFORFTS = 426
MIN_DEMEMPLOI = 936
MIN_MBIC = 305
MIN_SPEBNC = 305
MTPAC = 10
MTRC = 61
MTRCQAR = 31
MTRL = 153
MTRLQAR = 77
MTRS = 183
MTRSQAR = 92
MTRURAL = 61
MTVILLE = 46
MT_CIJEUNE = 1500
PLAFHABPRIN = 3750
PLAFHABPRINENF = 500
PLAFIMP = 1680
PLAFINVDOM2 = 270000
PLAFPRESCOMP = 30500
PLAF_99999 = 99999
PLAF_ABTTSPR = 120100
PLAF_AF = 80
PLAF_AF2 = 450
PLAF_ASVIE = 610
PLAF_CDPART = 901
PLAF_CDPART2 = 0
PLAF_CIJEUNE = 25000
PLAF_CIJEUNE1 = 20000
PLAF_CIJEUNE2 = 3421
PLAF_CIJEUNE3 = 4276
PLAF_CINE = 18000
PLAF_COMPASVIE = 150
PLAF_COMPASVIEQAR = 75
PLAF_COMPPART = 3558
PLAF_COMPSURV = 300
PLAF_COMPSURVQAR = 150
PLAF_CRENTR = 1000
PLAF_CRENTRH = 400
PLAF_DEDFORFTS = 12157
PLAF_DEDPRFOYER = 3707
PLAF_DEFFO = 1000
PLAF_DEMIPART = 1508
PLAF_DEVDUR = 8000
PLAF_FCDPART = 1014
PLAF_FCDPART2 = 1014
PLAF_FCPI = 12000
PLAF_FCPI2 = 24000
PLAF_FOREST = 5700
PLAF_FOREST1 = 6250
PLAF_FOREST2 = 2000
PLAF_FORFBA = 76225
PLAF_FRCOMPTA = 915
PLAF_GE2 = 5000
PLAF_GE2_ENF2 = 500
PLAF_GE2_ENF2QAR = 250
PLAF_GE2_ENF3 = 600
PLAF_GE2_ENF3QAR = 300
PLAF_GE2_PAC = 400
PLAF_GE2_PACQAR = 200
PLAF_INVDOM = 40000
PLAF_INVDOM1 = 74286
PLAF_INVDOM2 = 300000
PLAF_INVDOM3 = 36000
PLAF_INVDOM4 = 30600
PLAF_INVDOM5 = 270000
PLAF_INVDOM6 = 229500
PLAF_INVDOM7 = 93333
PLAF_INVDOMR = 60000
PLAF_NUREPAR = 25000
PLAF_PLACOMP = 1504
PLAF_PRECONS = 600
PLAF_RABDOM = 5100
PLAF_RABGUY = 6700
PLAF_RCMAV1 = 4600
PLAF_REDGARD = 2300
PLAF_REDGARDQAR = 1150
PLAF_REDREPAS = 526
PLAF_RENOV = 20000
PLAF_RESINEUV = 300000
PLAF_RFRN3 = 30000
PLAF_RSURV = 1525
PLAF_SOFICA = 18000
PLAF_TEC = 60000
PPEFLIMRPB = 3353
PPEFLIMRPH = 15644
PPEFLIMRPH2 = 23829
PPEFLIMRPHI = 22348
PPEFLIMSMIC = 11175
PPELIMC = 16251
PPELIMM = 32498
PPELIMPAC = 4490
PPELIMRPB = 3743
PPELIMRPH = 17451
PPELIMRPH2 = 26572
PPELIMRPHI = 24950
PPELIMSMIC = 12475
PPELIMTOT = 30
PPEMONMAJO = 36
PPENBJAN = 360
PPESEUIL = 25
PPETXMAJ1 = 0.15
PPETXMAJ2 = 0.85
PPETXRPRO = 11.11
PPE_FTX1 = 4.4
PPE_FTX2 = 11
PPE_FTX3 = 5.5
PPE_PRIMETTE = 83
PPE_TX1 = 7.7
PPE_TX2 = 19.3
PPE_TX3 = 5.1
PRIMMOD = 350
SEUIL_12 = 12
SEUIL_61 = 61
SEUIL_8 = 8
SEUIL_ACOMPTE = 347
SEUIL_AVMAXETU = 4000
SEUIL_CIJEUNE = 25
SEUIL_DECOTE1 = 1135
SEUIL_DECOTE2 = 1870
SEUIL_DECOTEA = 1016
SEUIL_EXO1 = 8680
SEUIL_EXO2 = 9490
SEUIL_IMPDEFBA = 107610
SEUIL_TXMIN = 305
SPETXAB = 34
T07 = 10
T08 = 40
T09 = 80
T10 = 10
T11 = 40
T12 = 80
T17 = 10
T31 = 80
TAUX_CONV = 6.55957
TCDIS = 30
TX005 = 0.05
TX01 = 1
TX038 = 3.8
TX05 = 5
TX051 = 5.1
TX062 = 6.2
TX066 = 6.6
TX068 = 6.8
TX07 = 7
TX075 = 7.5
TX082 = 8.2
TX09 = 9
TX10 = 10
TX11 = 11
TX12 = 12
TX13 = 13
TX14 = 14
TX15 = 15
TX16 = 16
TX17 = 17
TX1758A = 10
TX18 = 18
TX19 = 19
TX20 = 20
TX21 = 21
TX22 = 22
TX225 = 22.5
TX23 = 23
TX24 = 24
TX25 = 25
TX26 = 26
TX29 = 29
TX30 = 30
TX32 = 32
TX34 = 34
TX35 = 35
TX36 = 36
TX375 = 37.5
TX40 = 40
TX41 = 41
TX44 = 44
TX45 = 45
TX4737 = 47.37
TX50 = 50
TX6 = 6
TX60 = 60
TX65 = 65
TX70 = 70
TX75 = 75
TX76 = 76
TX90 = 90
TXFIPDOM = 42
TXGAIN0 = 16
TXGAIN1 = 19
TXGAIN2 = 22.5
TXGAIN3 = 30
TXGAIN4 = 41
TXGAIN5 = 18
TXHABPRIN1 = 40
TXHABPRIN2 = 40
TXHABPRIN3 = 20
TXHR1 = 3
TXHR2 = 4
TXMOISRETARD = 0.75
TXMOISRETARD2 = 0.4
TXPERT = 19
TXRVT1 = 70
TXRVT2 = 50
TXRVT3 = 40
TXRVT4 = 30
TXTQ = 7.5
TXTQDED = 5.1
TXTV = 6.6
TXTVDED = 4.2
TXTW = 6.2
TXTWDED = 3.8
TXTX = 3.8
TXTXDED = 3.8
TX_ABTSPR = 20
TX_ABTTSAPR = 10
TX_AIDOMI = 50
TX_ASSUR1 = 2
TX_ASSUR2 = 0.6
TX_ASSUR3 = 2.6
TX_ASSUR4 = 0.6
TX_BAIL = 2.5
TX_BAR0 = 0
TX_BAR1 = 0
TX_BAR1A = 5.5
TX_BAR2 = 14
TX_BAR3 = 30
TX_BAR4 = 41
TX_BAR5 = 45
TX_BASDOMENT = 50
TX_BASDOMHOTEL = 60
TX_BASECOTSYN = 1
TX_BASEDUP = 20
TX_BASREDOM = 20
TX_CIAQCUL = 40
TX_CIDONENTR = 60
TX_CIGPLDESTR = 3000
TX_CIJEUNE = 75
TX_CINE1 = 36
TX_CINE2 = 30
TX_CINE3 = 25
TX_CODEV = 25
TX_CREREVET = 16
TX_CURE = 25
TX_DEDFORFTS = 10
TX_DEDPER = 10
TX_DEFFO = 25
TX_DIFAGRI = 50
TX_DPAEAV = 35
TX_FBAR0 = 0
TX_FBAR1 = 7.5
TX_FBAR2 = 21
TX_FBAR3 = 31
TX_FBAR4 = 41
TX_FBASEDUP = 10
TX_FCPI = 18
TX_FIPCORSE = 38
TX_FORET = 50
TX_FREDDON = 50
TX_FREDREPAS = 60
TX_ISF = 25
TX_LIM_SOFICA = 25
TX_LOYIMP = 38
TX_MIBPRES = 50
TX_MIBVEN = 71
TX_MICFON = 30
TX_MIN_DOM = 18
TX_MIN_MET = 20
TX_PATNAT = 18
TX_PERPPLAF = 10
TX_PRECONS = 25
TX_PRESCOMP = 25
TX_PRETUD = 25
TX_PREVLIB = 7.5
TX_PREVLIB2 = 19
TX_RABDOM = 30
TX_RABGUY = 40
TX_RASAR = 12
TX_REDASVIE = 25
TX_REDCOTSYN = 66
TX_REDDOM = 25
TX_REDDOMINT = 40
TX_REDDON = 66
TX_REDFIP = 18
TX_REDGARD = 50
TX_REDHP2 = 25
TX_REDIL10 = 10
TX_REDIL15 = 15
TX_REDIL18 = 18
TX_REDIL20 = 20
TX_REDIL25 = 25
TX_REDIL36 = 36
TX_REDIL40 = 40
TX_REDOEUVRE = 60
TX_REDREPAS = 75
TX_REDSOC1 = 25
TX_REDSOC2 = 22
TX_REDSURV = 25
TX_RENOV = 18
TX_RESINEUV = 25
TX_RESTIMO1 = 27
TX_RESTIMO2 = 36
TX_RGEAUTRE = 15
TX_RGEPAHA = 25
TX_RGTECH = 30
TX_SOCREPR = 25
TX_TITPRISE = 22
TX_TR2_ISF = 50
TX_TR3_ISF = 70
TX_TR4_ISF = 1
TX_TR5_ISF = 125
TX_TR6_ISF = 15
TYPE0 = 0
TYPE1 = 1
TYPE2 = 2
TYPE3 = 3
TYPE4 = 4
T_CSG = 8.2
T_GAINSAL = 8
T_IDCSG = 5.1
T_PCAPTAX = 7.5
T_PREL_SOC = 6.8
T_PREL_SOCDOM = 2.3
T_PREL_SUI = 3.4
T_RDS = 0.5
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
# -*- coding: utf-8 -*-
"""Functions to load JSON files distributed with this package."""
import json
import os
import pkg_resources
from toolz.curried import map, pipe
m_language_parser_dir_path = pkg_resources.get_distribution('calculette_impots_m_language_parser').location
json_dir_path = os.path.join(m_language_parser_dir_path, 'json')
# Functions to load data
def load_constants():
return load_json(os.path.join(json_dir_path, 'constants.json'))
def load_errors_definitions():
"""Return `definition_by_error_name` dict from the file `errH.json`."""
return pipe(
load_json(os.path.join(json_dir_path, 'ast', 'errH.json')),
map(lambda d: (d['name'], d)), # Index by name and keep singleton value (groupby creates list values)
dict,
)
def load_formulas_dependencies():
"""Return `dependencies_by_formula_name` dict from the file `formulas_dependencies.json`."""
return load_json(os.path.join(json_dir_path, 'formulas_dependencies.json'))
def load_json(file_path):
with open(file_path) as file:
file_str = file.read()
return json.loads(file_str)
def load_variables_definitions():
"""Return `definition_by_variable_name` dict from the file `variables_definitions.json`."""
return load_json(os.path.join(json_dir_path, 'variables_definitions.json'))
......@@ -4,7 +4,7 @@
"""
Functions used to transpile the JSON AST nodes to Python source code.
Each function `visit_abc` handles a node of type 'abc' and returns either a string or None.
These functions are called by transpiler.core.
The dispatcher function (`visit_node`) is called from the script `json_ast_to_python.py`.
"""
......@@ -17,27 +17,25 @@ import textwrap
from calculette_impots_m_language_parser.unloop_helpers import iter_unlooped_nodes
from toolz import concatv, interpose, mapcat
from . import core
log = logging.getLogger(__name__)
variables_definitions = None
# Helpers
def make_formula_source(formula_name, expression, cached=True, description=None):
sanitized_name = core.sanitized_variable_name(formula_name)
def make_formula_source(formula_name, expression, cached=False, description=None):
return """\
{decorator}def {sanitized_name}():
{decorator}def {function_name}():
{docstring}return {expression}
formulas[{formula_name!r}] = {sanitized_name}
formulas[{formula_name!r}] = {function_name}
""".format(
decorator='@cached(cache)\n' if cached else '',
docstring='' if description is None else '"""{}"""\n '.format(description),
expression=expression,
formula_name=formula_name,
sanitized_name=sanitized_name,
function_name='_' + formula_name if formula_name[0].isdigit() else formula_name,
)
......@@ -150,16 +148,17 @@ def visit_float(node):
def visit_formula(node):
global variables_definitions
formula_name = node['name']
sanitized_name = core.sanitized_variable_name(formula_name)
expression_source = visit_node(node['expression'])
description = core.get_variable_description(formula_name)
description = variables_definitions.get_description(formula_name)
source = make_formula_source(
cached=True,
description=description,
expression=expression_source,
formula_name=formula_name,
)
return (sanitized_name, source)
return (formula_name, source)
def visit_function_call(node):
......@@ -218,15 +217,7 @@ def visit_sum_expression(node):
def visit_symbol(node):
symbol = node['value']
sanitized_name = core.sanitized_variable_name(symbol)
return 'saisie_variables.get({!r}, 0)'.format(symbol) \
if core.is_saisie_variable(symbol) \
else (
'formulas[{!r}]()'.format(symbol)
if core.is_calculee_variable(symbol)
else sanitized_name
)
return 'formulas[{!r}]()'.format(node['value'])
def visit_ternary_operator(node):
......
......@@ -7,26 +7,25 @@ import argparse
import json
import logging
import os
import pkg_resources
import sys
from toolz.curried import get, map, merge, pipe, unique, valfilter
from toolz.curried import get, map, unique, valfilter
from calculette_impots import core
from calculette_impots import loaders
from calculette_impots.generated import formulas, verifs
# Globals
from calculette_impots.variables_definitions import VariablesDefinitions
args = None
script_name = os.path.splitext(os.path.basename(__file__))[0]
log = logging.getLogger(script_name)
script_dir_name = os.path.dirname(os.path.abspath(__file__))
constants = loaders.load_constants()
variables_definitions = VariablesDefinitions(constants=constants)
def iter_saisie_variables(values):
global variables_definitions
for value, words in map(lambda value: (value, value.strip('=').split('=', 1)), values):
if len(words) == 1:
parser.error('Missing value for variable saisie: "{}"'.format(value))
......@@ -37,23 +36,14 @@ def iter_saisie_variables(values):
variable_value = float(variable_value)
except ValueError:
parser.error('Variable "{}" value is not a float'.format(value))
variable_type = core.get_variable_type(variable_name)
if variable_type != 'variable_saisie':
if not variables_definitions.is_saisie(variable_name):
parser.error('Variable "{}" is not a variable saisie'.format(variable_name))
yield variable_name, variable_value
def load_errors_definitions():
m_language_parser_dir_path = pkg_resources.get_distribution('calculette_impots_m_language_parser').location
errors_definitions_file_path = os.path.join(m_language_parser_dir_path, 'json', 'ast', 'errH.json')
with open(errors_definitions_file_path) as errors_definitions_file:
errors_definitions_str = errors_definitions_file.read()
errors_definitions = json.loads(errors_definitions_str)
return errors_definitions
def main():
global args, parser
global args, constants, parser, variables_definitions