Search code examples
pythondebuggingdecoratorpudb

How to make a decorator transparent to debugger


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?


Solution

  • 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()