def get_cached_composed_reform(reform_keys, tax_benefit_system): full_key = '.'.join( [tax_benefit_system.full_key] + reform_keys if isinstance(tax_benefit_system, reforms.AbstractReform) else reform_keys ) composed_reform = reform_by_full_key.get(full_key) if composed_reform is None: build_reform_functions = [build_reform_function_by_key[reform_key] for reform_key in reform_keys] composed_reform = reforms.compose_reforms( build_functions_and_keys = zip(build_reform_functions, reform_keys), tax_benefit_system = tax_benefit_system, ) assert full_key == composed_reform.full_key reform_by_full_key[full_key] = composed_reform return composed_reform
def get_cached_composed_reform(reform_keys, tax_benefit_system): if reform_by_full_key is None: raise Exception('Cannot use reforms when none has been loaded in the instance configuration')\ full_key = '.'.join( [tax_benefit_system.full_key] + reform_keys if isinstance(tax_benefit_system, reforms.AbstractReform) else reform_keys ) composed_reform = reform_by_full_key.get(full_key) if composed_reform is None: build_reform_functions = [build_reform_function_by_key[reform_key] for reform_key in reform_keys] composed_reform = reforms.compose_reforms( build_functions_and_keys = zip(build_reform_functions, reform_keys), tax_benefit_system = tax_benefit_system, ) assert full_key == composed_reform.full_key reform_by_full_key[full_key] = composed_reform return composed_reform
def get_cached_composed_reform(reform_keys, tax_benefit_system): full_key = '.'.join( [tax_benefit_system.full_key] + reform_keys if isinstance(tax_benefit_system, reforms.AbstractReform) else reform_keys ) composed_reform = reform_by_full_key.get(full_key) if composed_reform is None: build_reform_functions = [] for reform_key in reform_keys: assert reform_key in build_reform_function_by_key, \ 'Error loading cached reform "{}" in build_reform_functions'.format(reform_key) build_reform_function = build_reform_function_by_key[reform_key] build_reform_functions.append(build_reform_function) composed_reform = reforms.compose_reforms( build_functions_and_keys = zip(build_reform_functions, reform_keys), tax_benefit_system = tax_benefit_system, ) assert full_key == composed_reform.full_key reform_by_full_key[full_key] = composed_reform return composed_reform
def get_cached_composed_reform(reform_keys, tax_benefit_system): full_key = '.'.join( [tax_benefit_system.full_key] + reform_keys if isinstance(tax_benefit_system, reforms.AbstractReform ) else reform_keys) composed_reform = reform_by_full_key.get(full_key) if composed_reform is None: build_reform_functions = [] for reform_key in reform_keys: assert reform_key in build_reform_function_by_key, \ 'Error loading cached reform "{}" in build_reform_functions'.format(reform_key) build_reform_function = build_reform_function_by_key[reform_key] build_reform_functions.append(build_reform_function) composed_reform = reforms.compose_reforms( build_functions_and_keys=zip(build_reform_functions, reform_keys), tax_benefit_system=tax_benefit_system, ) assert full_key == composed_reform.full_key, "{} != {}".format( full_key, composed_reform.full_key) reform_by_full_key[full_key] = composed_reform return composed_reform
def get_cached_composed_reform(reform_keys, tax_benefit_system): full_key = '.'.join( [tax_benefit_system.full_key] + reform_keys if isinstance(tax_benefit_system, Reform) else reform_keys ) composed_reform = reform_by_full_key.get(full_key) if composed_reform is None: reforms = [] for reform_key in reform_keys: assert reform_key in reform_list, \ 'Error loading cached reform "{}" in build_reform_functions'.format(reform_key) reform = reform_list[reform_key] reforms.append(reform) composed_reform = compose_reforms( reforms = reforms, tax_benefit_system = tax_benefit_system, ) assert full_key == composed_reform.full_key, (full_key, composed_reform.full_key) reform_by_full_key[full_key] = composed_reform return composed_reform
def api1_simulate(req): ctx = contexts.Ctx(req) headers = wsgihelpers.handle_cross_origin_resource_sharing(ctx) assert req.method == 'POST', req.method if conf['load_alert']: try: load_average = os.getloadavg() except (AttributeError, OSError): # When load average is not available, always accept request. pass else: if load_average[0] / cpu_count > 1: return wsgihelpers.respond_json(ctx, collections.OrderedDict(sorted(dict( apiVersion = 1, error = collections.OrderedDict(sorted(dict( code = 503, # Service Unavailable message = ctx._(u'Server is overloaded: {} {} {}').format(*load_average), ).iteritems())), method = req.script_name, url = req.url.decode('utf-8'), ).iteritems())), headers = headers, ) content_type = req.content_type if content_type is not None: content_type = content_type.split(';', 1)[0].strip() if content_type != 'application/json': return wsgihelpers.respond_json(ctx, collections.OrderedDict(sorted(dict( apiVersion = 1, error = collections.OrderedDict(sorted(dict( code = 400, # Bad Request message = ctx._(u'Bad content-type: {}').format(content_type), ).iteritems())), method = req.script_name, url = req.url.decode('utf-8'), ).iteritems())), headers = headers, ) inputs, error = conv.pipe( conv.make_input_to_json(object_pairs_hook = collections.OrderedDict), conv.test_isinstance(dict), conv.not_none, )(req.body, state = ctx) if error is not None: return wsgihelpers.respond_json(ctx, collections.OrderedDict(sorted(dict( apiVersion = 1, error = collections.OrderedDict(sorted(dict( code = 400, # Bad Request errors = [conv.jsonify_value(error)], message = ctx._(u'Invalid JSON in request POST body'), ).iteritems())), method = req.script_name, params = req.body, url = req.url.decode('utf-8'), ).iteritems())), headers = headers, ) str_to_reforms = conv.make_str_to_reforms() data, errors = conv.struct( dict( # api_key = conv.pipe( # Shared secret between client and server # conv.test_isinstance(basestring), # conv.input_to_uuid_str, # conv.not_none, # ), base_reforms = str_to_reforms, context = conv.test_isinstance(basestring), # For asynchronous calls reforms = str_to_reforms, scenarios = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( conv.not_none, # Real conversion is done once tax-benefit system is known. ), conv.test(lambda scenarios: len(scenarios) >= 1, error = N_(u'At least one scenario is required')), conv.test(lambda scenarios: len(scenarios) <= 100, error = N_(u"There can't be more than 100 scenarios")), conv.not_none, ), trace = conv.pipe( conv.test_isinstance((bool, int)), conv.anything_to_bool, conv.default(False), ), validate = conv.pipe( conv.test_isinstance((bool, int)), conv.anything_to_bool, conv.default(False), ), ), )(inputs, state = ctx) if errors is None: country_tax_benefit_system = model.tax_benefit_system base_tax_benefit_system = reforms.compose_reforms( base_tax_benefit_system = country_tax_benefit_system, build_reform_list = [model.build_reform_function_by_key[reform_key] for reform_key in data['base_reforms']], ) if data['base_reforms'] is not None else country_tax_benefit_system if data['reforms'] is not None: reform_tax_benefit_system = reforms.compose_reforms( base_tax_benefit_system = base_tax_benefit_system, build_reform_list = [model.build_reform_function_by_key[reform_key] for reform_key in data['reforms']], ) base_scenarios, base_scenarios_errors = conv.uniform_sequence( base_tax_benefit_system.Scenario.make_json_to_cached_or_new_instance( repair = data['validate'], tax_benefit_system = base_tax_benefit_system, ) )(data['scenarios'], state = ctx) errors = {'scenarios': base_scenarios_errors} if base_scenarios_errors is not None else None if errors is None and data['reforms'] is not None: reform_scenarios, reform_scenarios_errors = conv.uniform_sequence( reform_tax_benefit_system.Scenario.make_json_to_cached_or_new_instance( repair = data['validate'], tax_benefit_system = reform_tax_benefit_system, ) )(data['scenarios'], state = ctx) errors = {'scenarios': reform_scenarios_errors} if reform_scenarios_errors is not None else None if errors is not None: return wsgihelpers.respond_json(ctx, collections.OrderedDict(sorted(dict( apiVersion = 1, context = inputs.get('context'), error = collections.OrderedDict(sorted(dict( code = 400, # Bad Request errors = [conv.jsonify_value(errors)], message = ctx._(u'Bad parameters in request'), ).iteritems())), method = req.script_name, params = inputs, url = req.url.decode('utf-8'), ).iteritems())), headers = headers, ) # api_key = data['api_key'] # account = model.Account.find_one( # dict( # api_key = api_key, # ), # as_class = collections.OrderedDict, # ) # if account is None: # return wsgihelpers.respond_json(ctx, # collections.OrderedDict(sorted(dict( # apiVersion = 1, # context = data['context'], # error = collections.OrderedDict(sorted(dict( # code = 401, # Unauthorized # message = ctx._('Unknown API Key: {}').format(api_key), # ).iteritems())), # method = req.script_name, # params = inputs, # url = req.url.decode('utf-8'), # ).iteritems())), # headers = headers, # ) scenarios = base_scenarios if data['reforms'] is None else reform_scenarios suggestions = {} for scenario_index, scenario in enumerate(scenarios): if data['validate']: original_test_case = scenario.test_case scenario.test_case = copy.deepcopy(original_test_case) suggestion = scenario.suggest() if data['validate']: scenario.test_case = original_test_case if suggestion is not None: suggestions.setdefault('scenarios', {})[scenario_index] = suggestion if not suggestions: suggestions = None if data['validate']: # Only a validation is requested. Don't launch simulation return wsgihelpers.respond_json(ctx, collections.OrderedDict(sorted(dict( apiVersion = 1, context = inputs.get('context'), method = req.script_name, params = inputs, repaired_scenarios = [ scenario.to_json() for scenario in scenarios ], suggestions = suggestions, url = req.url.decode('utf-8'), ).iteritems())), headers = headers, ) decomposition_json = model.get_cached_or_new_decomposition_json(tax_benefit_system = base_tax_benefit_system) base_simulations = [scenario.new_simulation(trace = data['trace']) for scenario in base_scenarios] base_response_json = decompositions.calculate(base_simulations, decomposition_json) if data['reforms'] is not None: reform_decomposition_json = model.get_cached_or_new_decomposition_json( tax_benefit_system = reform_tax_benefit_system, ) reform_simulations = [scenario.new_simulation(trace = data['trace']) for scenario in reform_scenarios] reform_response_json = decompositions.calculate(reform_simulations, reform_decomposition_json) if data['trace']: simulations_variables_json = [] tracebacks_json = [] simulations = reform_simulations if data['reforms'] is not None else base_simulations for simulation in simulations: simulation_variables_json = {} traceback_json = [] for (variable_name, period), step in simulation.traceback.iteritems(): holder = step['holder'] if variable_name not in simulation_variables_json: variable_value_json = holder.to_value_json() if variable_value_json is not None: simulation_variables_json[variable_name] = variable_value_json input_variables_infos = step.get('input_variables_infos') column = holder.column used_periods = step.get('used_periods') traceback_json.append(dict( cell_type = column.val_type, default_input_variables = step.get('default_input_variables', False), entity = column.entity, input_variables = [ (variable_name, str(variable_period)) for variable_name, variable_period in input_variables_infos ] if input_variables_infos else None, is_computed = step.get('is_computed', False), label = column.label, name = variable_name, period = str(period) if period is not None else None, used_periods = [ str(used_period) for used_period in used_periods ] if used_periods is not None else None, )) simulations_variables_json.append(simulation_variables_json) tracebacks_json.append(traceback_json) else: simulations_variables_json = None tracebacks_json = None response_data = dict( apiVersion = 1, context = data['context'], method = req.script_name, params = inputs, suggestions = suggestions, tracebacks = tracebacks_json, url = req.url.decode('utf-8'), value = reform_response_json if data['reforms'] is not None else base_response_json, variables = simulations_variables_json, ) if data['reforms'] is not None: response_data['base_value'] = base_response_json return wsgihelpers.respond_json(ctx, collections.OrderedDict(sorted(response_data.iteritems())), headers = headers, )
def api1_entities(req): ctx = contexts.Ctx(req) headers = wsgihelpers.handle_cross_origin_resource_sharing(ctx) assert req.method == 'GET', req.method params = req.GET inputs = dict( context = params.get('context'), reforms = params.getall('reform'), ) str_to_reforms = conv.make_str_to_reforms() data, errors = conv.pipe( conv.struct( dict( context = conv.noop, # For asynchronous calls reforms = str_to_reforms, ), default = 'drop', ), )(inputs, state = ctx) if errors is not None: return wsgihelpers.respond_json(ctx, collections.OrderedDict(sorted(dict( apiVersion = 1, context = inputs.get('context'), error = collections.OrderedDict(sorted(dict( code = 400, # Bad Request errors = [conv.jsonify_value(errors)], message = ctx._(u'Bad parameters in request'), ).iteritems())), method = req.script_name, params = inputs, url = req.url.decode('utf-8'), ).iteritems())), headers = headers, ) country_tax_benefit_system = model.tax_benefit_system tax_benefit_system = reforms.compose_reforms( base_tax_benefit_system = country_tax_benefit_system, build_reform_list = [model.build_reform_function_by_key[reform_key] for reform_key in data['reforms']], ) if data['reforms'] is not None else country_tax_benefit_system entities_class = tax_benefit_system.entity_class_by_key_plural.itervalues() entities = { entity_class.key_plural: build_entity_data(entity_class) for entity_class in entities_class } return wsgihelpers.respond_json(ctx, collections.OrderedDict(sorted(dict( apiVersion = 1, context = data['context'], entities = collections.OrderedDict(sorted(entities.iteritems())), method = req.script_name, params = inputs, ).iteritems())), headers = headers, )
def api1_field(req): ctx = contexts.Ctx(req) headers = wsgihelpers.handle_cross_origin_resource_sharing(ctx) assert req.method == "GET", req.method params = req.GET inputs = dict( context=params.get("context"), input_variables=params.get("input_variables"), reforms=params.getall("reform"), variable=params.get("variable"), ) str_to_reforms = conv.make_str_to_reforms() data, errors = conv.pipe( conv.struct( dict( context=conv.noop, # For asynchronous calls input_variables=conv.pipe( conv.test_isinstance((bool, int, basestring)), conv.anything_to_bool, conv.default(False) ), reforms=str_to_reforms, variable=conv.noop, # Real conversion is done once tax-benefit system is known. ), default="drop", ) )(inputs, state=ctx) if errors is None: country_tax_benefit_system = model.tax_benefit_system tax_benefit_system = ( reforms.compose_reforms( base_tax_benefit_system=country_tax_benefit_system, build_reform_list=[model.build_reform_function_by_key[reform_key] for reform_key in data["reforms"]], ) if data["reforms"] is not None else country_tax_benefit_system ) data, errors = conv.struct( dict( variable=conv.pipe( conv.empty_to_none, conv.default(u"revdisp"), conv.test_in(tax_benefit_system.column_by_name) ) ), default=conv.noop, )(data, state=ctx) if errors is not None: return wsgihelpers.respond_json( ctx, collections.OrderedDict( sorted( dict( apiVersion=1, context=inputs.get("context"), error=collections.OrderedDict( sorted( dict( code=400, # Bad Request errors=[conv.jsonify_value(errors)], message=ctx._(u"Bad parameters in request"), ).iteritems() ) ), method=req.script_name, params=inputs, url=req.url.decode("utf-8"), ).iteritems() ) ), headers=headers, ) simulation = simulations.Simulation( period=periods.period(datetime.date.today().year), tax_benefit_system=tax_benefit_system ) holder = simulation.get_or_new_holder(data["variable"]) return wsgihelpers.respond_json( ctx, collections.OrderedDict( sorted( dict( apiVersion=1, context=data["context"], method=req.script_name, params=inputs, url=req.url.decode("utf-8"), value=holder.to_field_json( input_variables_extractor=model.input_variables_extractor if data["input_variables"] else None ), ).iteritems() ) ), headers=headers, )