Troubleshooting#

Eventually, all code will fail. Even GETTSIM’s and your code is no exception. Therefore, GETTSIM offers a debug mode for the function compute_taxes_and_transfers which helps you to find the source of the error.

Let us take the same example as used in the tutorial on basic usage, but reduced to the computation of ges_rentenv_beitr_m which are the monthly contribution to the pension insurance.

[1]:
import pandas as pd
from gettsim import compute_taxes_and_transfers, set_up_policy_environment

In the following cell, we create all necessary data to run the example.

[2]:
data = pd.DataFrame(
    {
        "p_id": 1,
        "hh_id": 1,
        "bruttolohn_m": 1000.0,
        "wohnort_ost": False,
    },
    index=[0],
)
data
[2]:
p_id hh_id bruttolohn_m wohnort_ost
0 1 1 1000.0 False
[3]:
policy_params, policy_functions = set_up_policy_environment(2020)

In the following cell, we call the function to compute quantities in the tax and transfer system. Note that, debug = True which enables the debug mode. It is False by default. The debug mode differs from the usual call in two ways:

  1. All necessary inputs to compute the targets and all intermediate variables are returned. This lets you assess your inputs and outputs together which can be useful to identify issues which may be preventing certain variables from being computed.

  2. If an exception occurs while computing the targets, the exception is printed, but not raised. The variables which depend on the variable where the exception occurred are not computed.

The following call shows the effect of the debug mode when no exception occurs.

[4]:
df = compute_taxes_and_transfers(
    data=data,
    functions=policy_functions,
    params=policy_params,
    targets="ges_rentenv_beitr_m",
    debug=True,
)

The resulting DataFrame contains all necessary input variables as well as the target and intermediate variables.

[5]:
df
[5]:
hh_id p_id bruttolohn_m wohnort_ost ges_rentenv_beitr_m
0 1 1 1000.0 False 85.753549

Debug Mode with an Exception#

What happens when an exception is raised while producing the target? We artificially produce an error with a modified user function. For exemplary purposes we modify GETTSIM’s function minijob_grenze which is called when computing the pension contributions. Instead of its usual functionality of returning the income threshold for marginal employment, we overwrite it to raise an error when called (note that we could do so with any other function as well).

[6]:
def minijob_grenze():
    raise ValueError
[7]:
df = compute_taxes_and_transfers(
    data=data,
    functions=[policy_functions, minijob_grenze],
    params=policy_params,
    targets="ges_rentenv_beitr_m",
    debug=True,
)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[7], line 1
----> 1 df = compute_taxes_and_transfers(
      2     data=data,
      3     functions=[policy_functions, minijob_grenze],
      4     params=policy_params,
      5     targets="ges_rentenv_beitr_m",
      6     debug=True,
      7 )

File ~/checkouts/readthedocs.org/user_builds/gettsim/checkouts/latest/src/_gettsim/interface.py:164, in compute_taxes_and_transfers(data, params, functions, aggregate_by_group_specs, aggregate_by_p_id_specs, targets, check_minimal_specification, rounding, debug)
    152         if (
    153             "mindestunterhalt" not in params["unterhalt"]
    154             and "unterhaltsvors_m" in processed_functions
    155         ):
    156             raise NotImplementedError(
    157                 """
    158 Unterhaltsvorschuss is not implemented yet prior to 2016, see
   (...)
    161         """
    162             )
--> 164     results = tax_transfer_function(**input_data)
    166     # Prepare results.
    167     prepared_results = _prepare_results(results, data, debug)

File ~/checkouts/readthedocs.org/user_builds/gettsim/conda/latest/lib/python3.12/site-packages/dags/output.py:22, in dict_output.<locals>.decorator_dict_output.<locals>.wrapper_dict_output(*args, **kwargs)
     20 @functools.wraps(func)
     21 def wrapper_dict_output(*args, **kwargs):
---> 22     raw = func(*args, **kwargs)
     23     out = dict(zip(keys, raw))
     24     return out

File ~/checkouts/readthedocs.org/user_builds/gettsim/conda/latest/lib/python3.12/site-packages/dags/signature.py:77, in with_signature.<locals>.decorator_with_signature.<locals>.wrapper_with_signature(*args, **kwargs)
     73 _fail_if_duplicated_arguments(present_args, present_kwargs, funcname)
     74 _fail_if_invalid_keyword_arguments(
     75     present_kwargs, valid_kwargs, funcname
     76 )
---> 77 return func(*args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/gettsim/conda/latest/lib/python3.12/site-packages/dags/dag.py:382, in _create_concatenated_function.<locals>.concatenated(*args, **kwargs)
    380 for name, info in execution_info.items():
    381     kwargs = {arg: results[arg] for arg in info["arguments"]}
--> 382     result = info["func"](**kwargs)
    383     results[name] = result
    385 out = tuple(results[target] for target in targets)

File ~/checkouts/readthedocs.org/user_builds/gettsim/checkouts/latest/src/_gettsim/functions_loader.py:788, in _vectorize_func.<locals>.wrapper_vectorize_func(*args, **kwargs)
    786 @functools.wraps(func)
    787 def wrapper_vectorize_func(*args, **kwargs):
--> 788     return func_vec(*args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/gettsim/conda/latest/lib/python3.12/site-packages/numpy/lib/function_base.py:2372, in vectorize.__call__(self, *args, **kwargs)
   2369     self._init_stage_2(*args, **kwargs)
   2370     return self
-> 2372 return self._call_as_normal(*args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/gettsim/conda/latest/lib/python3.12/site-packages/numpy/lib/function_base.py:2365, in vectorize._call_as_normal(self, *args, **kwargs)
   2362     vargs = [args[_i] for _i in inds]
   2363     vargs.extend([kwargs[_n] for _n in names])
-> 2365 return self._vectorize_call(func=func, args=vargs)

File ~/checkouts/readthedocs.org/user_builds/gettsim/conda/latest/lib/python3.12/site-packages/numpy/lib/function_base.py:2448, in vectorize._vectorize_call(self, func, args)
   2446     res = self._vectorize_call_with_signature(func, args)
   2447 elif not args:
-> 2448     res = func()
   2449 else:
   2450     ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args)

Cell In[6], line 2, in minijob_grenze()
      1 def minijob_grenze():
----> 2     raise ValueError

ValueError:

The traceback of the error is printed, but the execution is continued. The resulting DataFrame captures all input variables as well as variables which could be produced without errors.

[8]:
df
[8]:
hh_id p_id bruttolohn_m wohnort_ost ges_rentenv_beitr_m
0 1 1 1000.0 False 85.753549