Пример #1
0
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
Пример #2
0
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
Пример #3
0
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
Пример #4
0
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
Пример #5
0
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
Пример #6
0
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,
        )
Пример #7
0
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,
        )
Пример #8
0
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,
    )