Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

profiling-compatible functools.wraps #88633

Open
asottile mannequin opened this issue Jun 20, 2021 · 2 comments
Open

profiling-compatible functools.wraps #88633

asottile mannequin opened this issue Jun 20, 2021 · 2 comments
Labels
3.11 only security fixes stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@asottile
Copy link
Mannequin

asottile mannequin commented Jun 20, 2021

BPO 44467
Nosy @rhettinger, @asottile

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2021-06-20.20:40:39.165>
labels = ['type-feature', 'library', '3.11']
title = 'profiling-compatible functools.wraps'
updated_at = <Date 2021-06-20.22:57:55.470>
user = 'https://github.com/asottile'

bugs.python.org fields:

activity = <Date 2021-06-20.22:57:55.470>
actor = 'pablogsal'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2021-06-20.20:40:39.165>
creator = 'Anthony Sottile'
dependencies = []
files = []
hgrepos = []
issue_num = 44467
keywords = []
message_count = 1.0
messages = ['396199']
nosy_count = 2.0
nosy_names = ['rhettinger', 'Anthony Sottile']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue44467'
versions = ['Python 3.11']

@asottile
Copy link
Mannequin Author

asottile mannequin commented Jun 20, 2021

this is a small proposal to add a new function to the functools module which provides better profiling-compatible @functools.wraps(...)

the rationale comes from https://github.com/Yelp/named_decorator (which is dead / abandoned)

the tl;dr from there is any time a decorator is involved in a profile it becomes very difficult to trace because everything becomes tangled around common decorators (because function names are used from the code object)

here is the proposal and an initial implementation:

def wraps_with_name(func, decorator, **kwargs):
    def wraps_with_name_decorator(wrapped):
        new_name = f'{func.__name__}@{decorator.__name__}'
        new_code = wrapped.__code__.replace(co_name=new_name)
        # would be nice if `types.FunctionType` had a `.replace(...)` too!
        new_wrapped = types.FunctionType(
            new_code,
            wrapped.__globals__,
            new_name,
            wrapped.__defaults__,
            wrapped.__closure__,
        )
        return functools.wraps(func, **kwargs)(new_wrapped)
    return better_wraps_decorator

the usage would be similar to functools.wraps, here is an example:

def my_decorator(func):
    @functools.wraps_with_name(func, my_decorator)
    def my_decorator_inner(*args, **kwargs):
        return func(*args, **kwargs)
    return my_decorator

@asottile asottile mannequin added 3.11 only security fixes stdlib Python modules in the Lib dir type-feature A feature request or enhancement labels Jun 20, 2021
@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
@fwinkl
Copy link

fwinkl commented Nov 28, 2023

I was curious why functools.[lru_]cache doesn't suffer from this problem. Looking at its implementation a simple work-around for custom decorators is to use the following pattern:

def my_decorator(f):
    def wrapper(f):
        return f
    new_wrapper = wrapper(f)  # create new code object on each invocation
    return functools.update_wrapper(new_wrapper, f)

@my_decorator
def foo():
    pass

With that the profiler can correctly identify the call-sequence. I assume this would also lend itself as a simpler implementation for the proposed wraps_with_name.

Although personally, I would argue that the default wraps should already be doing this. It's rather confusing seeing the __name__, etc. correctly remapped but not the names in profiles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.11 only security fixes stdlib Python modules in the Lib dir type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

1 participant