Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/scipy/_lib/doccer.py: 85%
96 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-12 06:31 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-12 06:31 +0000
1''' Utilities to allow inserting docstring fragments for common
2parameters into function and method docstrings'''
4import sys
6__all__ = [
7 'docformat', 'inherit_docstring_from', 'indentcount_lines',
8 'filldoc', 'unindent_dict', 'unindent_string', 'extend_notes_in_docstring',
9 'replace_notes_in_docstring', 'doc_replace'
10]
13def docformat(docstring, docdict=None):
14 ''' Fill a function docstring from variables in dictionary
16 Adapt the indent of the inserted docs
18 Parameters
19 ----------
20 docstring : string
21 docstring from function, possibly with dict formatting strings
22 docdict : dict, optional
23 dictionary with keys that match the dict formatting strings
24 and values that are docstring fragments to be inserted. The
25 indentation of the inserted docstrings is set to match the
26 minimum indentation of the ``docstring`` by adding this
27 indentation to all lines of the inserted string, except the
28 first.
30 Returns
31 -------
32 outstring : string
33 string with requested ``docdict`` strings inserted
35 Examples
36 --------
37 >>> docformat(' Test string with %(value)s', {'value':'inserted value'})
38 ' Test string with inserted value'
39 >>> docstring = 'First line\\n Second line\\n %(value)s'
40 >>> inserted_string = "indented\\nstring"
41 >>> docdict = {'value': inserted_string}
42 >>> docformat(docstring, docdict)
43 'First line\\n Second line\\n indented\\n string'
44 '''
45 if not docstring:
46 return docstring
47 if docdict is None:
48 docdict = {}
49 if not docdict:
50 return docstring
51 lines = docstring.expandtabs().splitlines()
52 # Find the minimum indent of the main docstring, after first line
53 if len(lines) < 2:
54 icount = 0
55 else:
56 icount = indentcount_lines(lines[1:])
57 indent = ' ' * icount
58 # Insert this indent to dictionary docstrings
59 indented = {}
60 for name, dstr in docdict.items():
61 lines = dstr.expandtabs().splitlines()
62 try:
63 newlines = [lines[0]]
64 for line in lines[1:]:
65 newlines.append(indent+line)
66 indented[name] = '\n'.join(newlines)
67 except IndexError:
68 indented[name] = dstr
69 return docstring % indented
72def inherit_docstring_from(cls):
73 """
74 This decorator modifies the decorated function's docstring by
75 replacing occurrences of '%(super)s' with the docstring of the
76 method of the same name from the class `cls`.
78 If the decorated method has no docstring, it is simply given the
79 docstring of `cls`s method.
81 Parameters
82 ----------
83 cls : Python class or instance
84 A class with a method with the same name as the decorated method.
85 The docstring of the method in this class replaces '%(super)s' in the
86 docstring of the decorated method.
88 Returns
89 -------
90 f : function
91 The decorator function that modifies the __doc__ attribute
92 of its argument.
94 Examples
95 --------
96 In the following, the docstring for Bar.func created using the
97 docstring of `Foo.func`.
99 >>> class Foo:
100 ... def func(self):
101 ... '''Do something useful.'''
102 ... return
103 ...
104 >>> class Bar(Foo):
105 ... @inherit_docstring_from(Foo)
106 ... def func(self):
107 ... '''%(super)s
108 ... Do it fast.
109 ... '''
110 ... return
111 ...
112 >>> b = Bar()
113 >>> b.func.__doc__
114 'Do something useful.\n Do it fast.\n '
116 """
117 def _doc(func):
118 cls_docstring = getattr(cls, func.__name__).__doc__
119 func_docstring = func.__doc__
120 if func_docstring is None:
121 func.__doc__ = cls_docstring
122 else:
123 new_docstring = func_docstring % dict(super=cls_docstring)
124 func.__doc__ = new_docstring
125 return func
126 return _doc
129def extend_notes_in_docstring(cls, notes):
130 """
131 This decorator replaces the decorated function's docstring
132 with the docstring from corresponding method in `cls`.
133 It extends the 'Notes' section of that docstring to include
134 the given `notes`.
135 """
136 def _doc(func):
137 cls_docstring = getattr(cls, func.__name__).__doc__
138 # If python is called with -OO option,
139 # there is no docstring
140 if cls_docstring is None:
141 return func
142 end_of_notes = cls_docstring.find(' References\n')
143 if end_of_notes == -1:
144 end_of_notes = cls_docstring.find(' Examples\n')
145 if end_of_notes == -1:
146 end_of_notes = len(cls_docstring)
147 func.__doc__ = (cls_docstring[:end_of_notes] + notes +
148 cls_docstring[end_of_notes:])
149 return func
150 return _doc
153def replace_notes_in_docstring(cls, notes):
154 """
155 This decorator replaces the decorated function's docstring
156 with the docstring from corresponding method in `cls`.
157 It replaces the 'Notes' section of that docstring with
158 the given `notes`.
159 """
160 def _doc(func):
161 cls_docstring = getattr(cls, func.__name__).__doc__
162 notes_header = ' Notes\n -----\n'
163 # If python is called with -OO option,
164 # there is no docstring
165 if cls_docstring is None:
166 return func
167 start_of_notes = cls_docstring.find(notes_header)
168 end_of_notes = cls_docstring.find(' References\n')
169 if end_of_notes == -1:
170 end_of_notes = cls_docstring.find(' Examples\n')
171 if end_of_notes == -1:
172 end_of_notes = len(cls_docstring)
173 func.__doc__ = (cls_docstring[:start_of_notes + len(notes_header)] +
174 notes +
175 cls_docstring[end_of_notes:])
176 return func
177 return _doc
180def indentcount_lines(lines):
181 ''' Minimum indent for all lines in line list
183 >>> lines = [' one', ' two', ' three']
184 >>> indentcount_lines(lines)
185 1
186 >>> lines = []
187 >>> indentcount_lines(lines)
188 0
189 >>> lines = [' one']
190 >>> indentcount_lines(lines)
191 1
192 >>> indentcount_lines([' '])
193 0
194 '''
195 indentno = sys.maxsize
196 for line in lines:
197 stripped = line.lstrip()
198 if stripped:
199 indentno = min(indentno, len(line) - len(stripped))
200 if indentno == sys.maxsize:
201 return 0
202 return indentno
205def filldoc(docdict, unindent_params=True):
206 ''' Return docstring decorator using docdict variable dictionary
208 Parameters
209 ----------
210 docdict : dictionary
211 dictionary containing name, docstring fragment pairs
212 unindent_params : {False, True}, boolean, optional
213 If True, strip common indentation from all parameters in
214 docdict
216 Returns
217 -------
218 decfunc : function
219 decorator that applies dictionary to input function docstring
221 '''
222 if unindent_params:
223 docdict = unindent_dict(docdict)
225 def decorate(f):
226 f.__doc__ = docformat(f.__doc__, docdict)
227 return f
228 return decorate
231def unindent_dict(docdict):
232 ''' Unindent all strings in a docdict '''
233 can_dict = {}
234 for name, dstr in docdict.items():
235 can_dict[name] = unindent_string(dstr)
236 return can_dict
239def unindent_string(docstring):
240 ''' Set docstring to minimum indent for all lines, including first
242 >>> unindent_string(' two')
243 'two'
244 >>> unindent_string(' two\\n three')
245 'two\\n three'
246 '''
247 lines = docstring.expandtabs().splitlines()
248 icount = indentcount_lines(lines)
249 if icount == 0:
250 return docstring
251 return '\n'.join([line[icount:] for line in lines])
254def doc_replace(obj, oldval, newval):
255 """Decorator to take the docstring from obj, with oldval replaced by newval
257 Equivalent to ``func.__doc__ = obj.__doc__.replace(oldval, newval)``
259 Parameters
260 ----------
261 obj : object
262 The object to take the docstring from.
263 oldval : string
264 The string to replace from the original docstring.
265 newval : string
266 The string to replace ``oldval`` with.
267 """
268 # __doc__ may be None for optimized Python (-OO)
269 doc = (obj.__doc__ or '').replace(oldval, newval)
271 def inner(func):
272 func.__doc__ = doc
273 return func
275 return inner