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,
        "tu_id": 1,
        "hh_id": 1,
        "bruttolohn_m": 1000.0,
        "wohnort_ost": False,
    },
    index=[0],
)
data
[2]:
p_id tu_id hh_id bruttolohn_m wohnort_ost
0 1 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 tu_id p_id bruttolohn_m wohnort_ost ges_rentenv_beitr_m
0 1 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/stable/src/_gettsim/interface.py:148, in compute_taxes_and_transfers(data, params, functions, aggregation_specs, targets, columns_overriding_functions, check_minimal_specification, rounding, debug)
    136         if (
    137             "mindestunterhalt" not in params["unterhalt"]
    138             and "unterhaltsvors_m" in processed_functions
    139         ):
    140             raise NotImplementedError(
    141                 """
    142 Unterhaltsvorschuss is not implemented yet prior to 2016, see
   (...)
    145         """
    146             )
--> 148     results = tax_transfer_function(**input_data)
    150     # Prepare results.
    151     prepared_results = _prepare_results(results, data, debug)

File ~/checkouts/readthedocs.org/user_builds/gettsim/conda/stable/lib/python3.11/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/stable/lib/python3.11/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/stable/lib/python3.11/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/stable/src/_gettsim/functions_loader.py:580, in _vectorize_func.<locals>.wrapper_vectorize_func(*args, **kwargs)
    578 @functools.wraps(func)
    579 def wrapper_vectorize_func(*args, **kwargs):
--> 580     return func_vec(*args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/gettsim/conda/stable/lib/python3.11/site-packages/numpy/lib/function_base.py:2329, in vectorize.__call__(self, *args, **kwargs)
   2326     vargs = [args[_i] for _i in inds]
   2327     vargs.extend([kwargs[_n] for _n in names])
-> 2329 return self._vectorize_call(func=func, args=vargs)

File ~/checkouts/readthedocs.org/user_builds/gettsim/conda/stable/lib/python3.11/site-packages/numpy/lib/function_base.py:2405, in vectorize._vectorize_call(self, func, args)
   2403     res = self._vectorize_call_with_signature(func, args)
   2404 elif not args:
-> 2405     res = func()
   2406 else:
   2407     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 tu_id p_id bruttolohn_m wohnort_ost ges_rentenv_beitr_m
0 1 1 1 1000.0 False 85.753549