Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/wrapt/doc.py: 35%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""The `with_doc` decorator: override the docstring that introspection tools
2see for a wrapped callable without mutating the wrapped function itself.
3Accepts the docstring directly, or a factory that derives it from the
4wrapped function at decoration time.
6This is the companion of `with_signature`, which overrides the signature in
7the same way. Assigning to `__doc__` on an ordinary wrapt wrapper writes
8through to the wrapped function, because `__doc__` on every proxy delegates
9to the wrapped object, so a wrapper carrying its own docstring is the only
10way to change what is reported without touching the wrapped function.
11"""
13from .__wrapt__ import BoundFunctionWrapper, FunctionWrapper
15# Marker for a wrapper which carries no docstring override, so that `__doc__`
16# keeps delegating to the wrapped function. Distinct from None, which is a
17# legitimate docstring override.
19_NO_DOC_OVERRIDE = object()
21# The `__doc__` property for a function wrapper which may carry a docstring
22# override in its `_self_doc` slot. The wrapper class must assign this to
23# `__doc__` in its own class body, rather than inherit it from a mixin, and
24# set `_self_doc` in its `__init__()`, to `_NO_DOC_OVERRIDE` when there is
25# none.
26#
27# Both the pure Python metaclass and the C extension attribute hooks
28# recognise a `__doc__` descriptor defined by a derived class and consult it
29# in place of the default delegation to the wrapped object. It has to be in
30# the class dictionary of the wrapper class itself though, because `pydoc`
31# reads `__doc__` using `object.__getattribute__()` to avoid inherited
32# docstrings, and with the C extension that bypasses the attribute hooks and
33# would otherwise find the copy of the wrapped function's docstring which is
34# held in the instance dictionary.
35#
36# Without an override, assignment and deletion write through to the wrapped
37# function as they do for any other wrapt wrapper. With one, assignment
38# replaces the override and deletion removes it, restoring delegation to the
39# wrapped function.
42def _get_doc(self):
43 doc = self._self_doc
44 if doc is _NO_DOC_OVERRIDE:
45 return self.__wrapped__.__doc__
46 return doc
49def _set_doc(self, value):
50 if self._self_doc is _NO_DOC_OVERRIDE:
51 self.__wrapped__.__doc__ = value
52 else:
53 self._self_doc = value
56def _del_doc(self):
57 if self._self_doc is _NO_DOC_OVERRIDE:
58 del self.__wrapped__.__doc__
59 else:
60 self._self_doc = _NO_DOC_OVERRIDE
63_DOC_PROPERTY = property(_get_doc, _set_doc, _del_doc)
65# The `__doc__` property for the bound wrapper of a function wrapper which
66# may carry a docstring override, reading it from the parent. A bound
67# wrapper is read only, as `__doc__` of a bound method is.
70def _get_bound_doc(self):
71 doc = self._self_parent._self_doc
72 if doc is _NO_DOC_OVERRIDE:
73 return self.__wrapped__.__doc__
74 return doc
77_BOUND_DOC_PROPERTY = property(_get_bound_doc)
80class _BoundDocFunctionWrapper(BoundFunctionWrapper):
81 __doc__ = _BOUND_DOC_PROPERTY
84class _DocFunctionWrapper(FunctionWrapper):
85 __doc__ = _DOC_PROPERTY
87 __bound_function_wrapper__ = _BoundDocFunctionWrapper
89 def __init__(self, wrapped, wrapper, doc):
90 super().__init__(wrapped, wrapper)
91 self._self_doc = doc
94def with_doc(wrapped=None, /, *, doc=None, factory=None):
95 """Override the docstring of a wrapped callable.
97 Exactly one of `doc` or `factory` must be supplied:
99 - `doc`: the docstring to report.
100 - `factory`: a callable `factory(wrapped)` invoked at decoration time
101 that returns the docstring to report.
103 The resulting wrapper reports the override as its `__doc__`, and so it
104 is what `help()` and `pydoc` display. The wrapped function is not
105 mutated, and assigning to `__doc__` on the wrapper replaces the override
106 rather than writing through to the wrapped function. Calling behaviour
107 is unchanged.
108 """
110 if doc is None and factory is None:
111 raise TypeError("with_doc requires one of doc= or factory=")
112 if doc is not None and factory is not None:
113 raise TypeError("with_doc accepts only one of doc= or factory=")
115 def _decorator(wrapped):
116 def _wrapper(wrapped, instance, args, kwargs):
117 return wrapped(*args, **kwargs)
119 if factory is not None:
120 resolved = factory(wrapped)
121 else:
122 resolved = doc
124 return _DocFunctionWrapper(wrapped, _wrapper, resolved)
126 if wrapped is None:
127 return _decorator
128 return _decorator(wrapped)