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

1''' Utilities to allow inserting docstring fragments for common 

2parameters into function and method docstrings''' 

3 

4import sys 

5 

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] 

11 

12 

13def docformat(docstring, docdict=None): 

14 ''' Fill a function docstring from variables in dictionary 

15 

16 Adapt the indent of the inserted docs 

17 

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. 

29 

30 Returns 

31 ------- 

32 outstring : string 

33 string with requested ``docdict`` strings inserted 

34 

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 

70 

71 

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`. 

77 

78 If the decorated method has no docstring, it is simply given the 

79 docstring of `cls`s method. 

80 

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. 

87 

88 Returns 

89 ------- 

90 f : function 

91 The decorator function that modifies the __doc__ attribute 

92 of its argument. 

93 

94 Examples 

95 -------- 

96 In the following, the docstring for Bar.func created using the 

97 docstring of `Foo.func`. 

98 

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 ' 

115 

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 

127 

128 

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 

151 

152 

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 

178 

179 

180def indentcount_lines(lines): 

181 ''' Minimum indent for all lines in line list 

182 

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 

203 

204 

205def filldoc(docdict, unindent_params=True): 

206 ''' Return docstring decorator using docdict variable dictionary 

207 

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 

215 

216 Returns 

217 ------- 

218 decfunc : function 

219 decorator that applies dictionary to input function docstring 

220 

221 ''' 

222 if unindent_params: 

223 docdict = unindent_dict(docdict) 

224 

225 def decorate(f): 

226 f.__doc__ = docformat(f.__doc__, docdict) 

227 return f 

228 return decorate 

229 

230 

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 

237 

238 

239def unindent_string(docstring): 

240 ''' Set docstring to minimum indent for all lines, including first 

241 

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]) 

252 

253 

254def doc_replace(obj, oldval, newval): 

255 """Decorator to take the docstring from obj, with oldval replaced by newval 

256 

257 Equivalent to ``func.__doc__ = obj.__doc__.replace(oldval, newval)`` 

258 

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) 

270 

271 def inner(func): 

272 func.__doc__ = doc 

273 return func 

274 

275 return inner