2

I am working on a decorator library that is modifying keyword arguments of a function, and the library is doing what I want it to do, but it's very inconvenient that while debugging, whenever the user function is called, the debugger has to pass through the decorator library code.

I implemented the decorator as a class (see https://github.com/mapa17/configfy/blob/master/configfy/decorator.py)

and the user function is wrapped by the following library code:

def __call__(self, *args, **kwargs):
    if self.needs_wrapping:
        self.needs_wrapping = False
        self.func = args[0]
        functools.update_wrapper(self, self.func)
        self.kwargs = self.__get_kw_args(self.func)

        # If config file is specified in decorator, new kwargs can be precalculated!
        if self.config is not None:
            self.new_kwargs = self._get_new_kwargs()

        return self

    # Use precalculated kwargs if available
    if self.new_kwargs is None:
        new_kwargs = self._get_new_kwargs()
    else:
        new_kwargs = self.new_kwargs

    # Overwrite them with any passed arguments; passed arguments have priority!
    new_kwargs.update(kwargs)

    # Call target (aka user) function with altered kwargs
    return self.func(*args, **new_kwargs)

So is it possible to somehow skip this library code when debugging?

Georgy
  • 12,464
  • 7
  • 65
  • 73
Manuel Pasieka
  • 151
  • 1
  • 1
  • 10
  • If you don't want to step through that code, why are you setting a breakpoint there? – John Gordon Sep 07 '18 at 15:45
  • Which debugger are you using? – Georgy Sep 07 '18 at 15:45
  • Sorry for not being clearer. I am not setting any breakpoint in the library code, but in the user code. I am using pudb and when stepping into a function that is making use of the decorator, i get into the decorator library (the __call__ method). – Manuel Pasieka Sep 08 '18 at 19:34

2 Answers2

1

There's nothing magical with decorators. The @decorator syntax is only syntactic sugar, so when you write:

@decorate
def some_func(...):
   # ...

technically what really happens is:

def some_func(...):
   # ...

some_func = decorate(some_func)

IOW, no, there is no way to "make a decorator transparent to the debugger", since a "decorator" is just a plain ordinary callable that (usually but not necessarily) returns another plain ordinary callable - in fact there's just no such thing as a "decorator", a callable is a decorator if you use it as such, and that's all.

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • Thank you @bruno-desthuilliers, but I am aware that decorators are only syntactic sugar. Thats the reason I have framed the question how to make the decorator transparent to the debugger (not to the python interpreter). Because the debugger as I found out can be pushed into skipping the decorator code (see my answer) – Manuel Pasieka Sep 12 '18 at 12:20
1

As @bruno-desthuilliers mentioned, the decorator is a wrapper around the user function, and there is no way to somehow remove it.

What can be done is, to make the debugger skip the decorator module code, using the skip option see

As i am interested in using pudb for debugging, i created a pull request, enabling a similar feature for pdb see

for pdb

import pdb
from configfy import configfy as cfy    

@cfy
def fuu(kw_me=42):
    print(kw_me)

if __name__ == '__main__':
    pdb.Pdb(skip=['configfy.*']).set_trace()
    fuu()

for pudb (if the pull request is accepted)

import pudb
from configfy import configfy as cfy

# Prevent pudb from stepping into the decorator library code
pudb._get_debugger(skip=['configfy.*'])


@cfy
def fuu(kw_me=42):
    print(kw_me)

if __name__ == '__main__':
    pudb.set_trace()
    fuu()
Manuel Pasieka
  • 151
  • 1
  • 1
  • 10
  • Interesting and good to know - but this only allow to skip full modules, which is not the same as skipping specific decorators (function or class-based) - it doesn't work if the decorator is in the same module (which is not uncommon) nor if you don't want to skeep other code in the same module as the decorator (which is not uncommon either). – bruno desthuilliers Sep 13 '18 at 07:16
  • Yes thats true. Luckily its sufficient for configfy. – Manuel Pasieka Sep 14 '18 at 13:00