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

46 statements  

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. 

5 

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""" 

12 

13from .__wrapt__ import BoundFunctionWrapper, FunctionWrapper 

14 

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. 

18 

19_NO_DOC_OVERRIDE = object() 

20 

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. 

40 

41 

42def _get_doc(self): 

43 doc = self._self_doc 

44 if doc is _NO_DOC_OVERRIDE: 

45 return self.__wrapped__.__doc__ 

46 return doc 

47 

48 

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 

54 

55 

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 

61 

62 

63_DOC_PROPERTY = property(_get_doc, _set_doc, _del_doc) 

64 

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. 

68 

69 

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 

75 

76 

77_BOUND_DOC_PROPERTY = property(_get_bound_doc) 

78 

79 

80class _BoundDocFunctionWrapper(BoundFunctionWrapper): 

81 __doc__ = _BOUND_DOC_PROPERTY 

82 

83 

84class _DocFunctionWrapper(FunctionWrapper): 

85 __doc__ = _DOC_PROPERTY 

86 

87 __bound_function_wrapper__ = _BoundDocFunctionWrapper 

88 

89 def __init__(self, wrapped, wrapper, doc): 

90 super().__init__(wrapped, wrapper) 

91 self._self_doc = doc 

92 

93 

94def with_doc(wrapped=None, /, *, doc=None, factory=None): 

95 """Override the docstring of a wrapped callable. 

96 

97 Exactly one of `doc` or `factory` must be supplied: 

98 

99 - `doc`: the docstring to report. 

100 - `factory`: a callable `factory(wrapped)` invoked at decoration time 

101 that returns the docstring to report. 

102 

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 """ 

109 

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=") 

114 

115 def _decorator(wrapped): 

116 def _wrapper(wrapped, instance, args, kwargs): 

117 return wrapped(*args, **kwargs) 

118 

119 if factory is not None: 

120 resolved = factory(wrapped) 

121 else: 

122 resolved = doc 

123 

124 return _DocFunctionWrapper(wrapped, _wrapper, resolved) 

125 

126 if wrapped is None: 

127 return _decorator 

128 return _decorator(wrapped)