|
| 1 | +""" |
| 2 | +A backport of Python 3 functools to Python 2/3. The only important change |
| 3 | +we rely upon is that `update_wrapper` handles AttributeError gracefully. |
| 4 | +""" |
| 5 | + |
| 6 | +from functools import partial |
| 7 | + |
| 8 | +from sentry_sdk._types import MYPY |
| 9 | + |
| 10 | +if MYPY: |
| 11 | + from typing import Any |
| 12 | + from typing import Callable |
| 13 | + |
| 14 | + |
| 15 | +WRAPPER_ASSIGNMENTS = ( |
| 16 | + "__module__", |
| 17 | + "__name__", |
| 18 | + "__qualname__", |
| 19 | + "__doc__", |
| 20 | + "__annotations__", |
| 21 | +) |
| 22 | +WRAPPER_UPDATES = ("__dict__",) |
| 23 | + |
| 24 | + |
| 25 | +def update_wrapper( |
| 26 | + wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES |
| 27 | +): |
| 28 | + # type: (Any, Any, Any, Any) -> Any |
| 29 | + """Update a wrapper function to look like the wrapped function |
| 30 | +
|
| 31 | + wrapper is the function to be updated |
| 32 | + wrapped is the original function |
| 33 | + assigned is a tuple naming the attributes assigned directly |
| 34 | + from the wrapped function to the wrapper function (defaults to |
| 35 | + functools.WRAPPER_ASSIGNMENTS) |
| 36 | + updated is a tuple naming the attributes of the wrapper that |
| 37 | + are updated with the corresponding attribute from the wrapped |
| 38 | + function (defaults to functools.WRAPPER_UPDATES) |
| 39 | + """ |
| 40 | + for attr in assigned: |
| 41 | + try: |
| 42 | + value = getattr(wrapped, attr) |
| 43 | + except AttributeError: |
| 44 | + pass |
| 45 | + else: |
| 46 | + setattr(wrapper, attr, value) |
| 47 | + for attr in updated: |
| 48 | + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) |
| 49 | + # Issue #17482: set __wrapped__ last so we don't inadvertently copy it |
| 50 | + # from the wrapped function when updating __dict__ |
| 51 | + wrapper.__wrapped__ = wrapped |
| 52 | + # Return the wrapper so this can be used as a decorator via partial() |
| 53 | + return wrapper |
| 54 | + |
| 55 | + |
| 56 | +def wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES): |
| 57 | + # type: (Callable[..., Any], Any, Any) -> Callable[[Callable[..., Any]], Callable[..., Any]] |
| 58 | + """Decorator factory to apply update_wrapper() to a wrapper function |
| 59 | +
|
| 60 | + Returns a decorator that invokes update_wrapper() with the decorated |
| 61 | + function as the wrapper argument and the arguments to wraps() as the |
| 62 | + remaining arguments. Default arguments are as for update_wrapper(). |
| 63 | + This is a convenience function to simplify applying partial() to |
| 64 | + update_wrapper(). |
| 65 | + """ |
| 66 | + return partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) |
0 commit comments