Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/smart_open/doctools.py: 75%

106 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:57 +0000

1# -*- coding: utf-8 -*- 

2# 

3# Copyright (C) 2019 Radim Rehurek <me@radimrehurek.com> 

4# 

5# This code is distributed under the terms and conditions 

6# from the MIT License (MIT). 

7# 

8 

9"""Common functions for working with docstrings. 

10 

11For internal use only. 

12""" 

13 

14import contextlib 

15import inspect 

16import io 

17import os.path 

18import re 

19 

20from . import compression 

21from . import transport 

22 

23PLACEHOLDER = ' smart_open/doctools.py magic goes here' 

24 

25 

26def extract_kwargs(docstring): 

27 """Extract keyword argument documentation from a function's docstring. 

28 

29 Parameters 

30 ---------- 

31 docstring: str 

32 The docstring to extract keyword arguments from. 

33 

34 Returns 

35 ------- 

36 list of (str, str, list str) 

37 

38 str 

39 The name of the keyword argument. 

40 str 

41 Its type. 

42 str 

43 Its documentation as a list of lines. 

44 

45 Notes 

46 ----- 

47 The implementation is rather fragile. It expects the following: 

48 

49 1. The parameters are under an underlined Parameters section 

50 2. Keyword parameters have the literal ", optional" after the type 

51 3. Names and types are not indented 

52 4. Descriptions are indented with 4 spaces 

53 5. The Parameters section ends with an empty line. 

54 

55 Examples 

56 -------- 

57 

58 >>> docstring = '''The foo function. 

59 ... Parameters 

60 ... ---------- 

61 ... bar: str, optional 

62 ... This parameter is the bar. 

63 ... baz: int, optional 

64 ... This parameter is the baz. 

65 ... 

66 ... ''' 

67 >>> kwargs = extract_kwargs(docstring) 

68 >>> kwargs[0] 

69 ('bar', 'str, optional', ['This parameter is the bar.']) 

70 

71 """ 

72 if not docstring: 

73 return [] 

74 

75 lines = inspect.cleandoc(docstring).split('\n') 

76 retval = [] 

77 

78 # 

79 # 1. Find the underlined 'Parameters' section 

80 # 2. Once there, continue parsing parameters until we hit an empty line 

81 # 

82 while lines and lines[0] != 'Parameters': 

83 lines.pop(0) 

84 

85 if not lines: 

86 return [] 

87 

88 lines.pop(0) 

89 lines.pop(0) 

90 

91 while lines and lines[0]: 

92 name, type_ = lines.pop(0).split(':', 1) 

93 description = [] 

94 while lines and lines[0].startswith(' '): 

95 description.append(lines.pop(0).strip()) 

96 if 'optional' in type_: 

97 retval.append((name.strip(), type_.strip(), description)) 

98 

99 return retval 

100 

101 

102def to_docstring(kwargs, lpad=''): 

103 """Reconstruct a docstring from keyword argument info. 

104 

105 Basically reverses :func:`extract_kwargs`. 

106 

107 Parameters 

108 ---------- 

109 kwargs: list 

110 Output from the extract_kwargs function 

111 lpad: str, optional 

112 Padding string (from the left). 

113 

114 Returns 

115 ------- 

116 str 

117 The docstring snippet documenting the keyword arguments. 

118 

119 Examples 

120 -------- 

121 

122 >>> kwargs = [ 

123 ... ('bar', 'str, optional', ['This parameter is the bar.']), 

124 ... ('baz', 'int, optional', ['This parameter is the baz.']), 

125 ... ] 

126 >>> print(to_docstring(kwargs), end='') 

127 bar: str, optional 

128 This parameter is the bar. 

129 baz: int, optional 

130 This parameter is the baz. 

131 

132 """ 

133 buf = io.StringIO() 

134 for name, type_, description in kwargs: 

135 buf.write('%s%s: %s\n' % (lpad, name, type_)) 

136 for line in description: 

137 buf.write('%s %s\n' % (lpad, line)) 

138 return buf.getvalue() 

139 

140 

141def extract_examples_from_readme_rst(indent=' '): 

142 """Extract examples from this project's README.rst file. 

143 

144 Parameters 

145 ---------- 

146 indent: str 

147 Prepend each line with this string. Should contain some number of spaces. 

148 

149 Returns 

150 ------- 

151 str 

152 The examples. 

153 

154 Notes 

155 ----- 

156 Quite fragile, depends on named labels inside the README.rst file. 

157 """ 

158 curr_dir = os.path.dirname(os.path.abspath(__file__)) 

159 readme_path = os.path.join(curr_dir, '..', 'README.rst') 

160 try: 

161 with open(readme_path) as fin: 

162 lines = list(fin) 

163 start = lines.index('.. _doctools_before_examples:\n') 

164 end = lines.index(".. _doctools_after_examples:\n") 

165 lines = lines[start+4:end-2] 

166 return ''.join([indent + re.sub('^ ', '', line) for line in lines]) 

167 except Exception: 

168 return indent + 'See README.rst' 

169 

170 

171def tweak_open_docstring(f): 

172 buf = io.StringIO() 

173 seen = set() 

174 

175 root_path = os.path.dirname(os.path.dirname(__file__)) 

176 

177 with contextlib.redirect_stdout(buf): 

178 print(' smart_open supports the following transport mechanisms:') 

179 print() 

180 for scheme, submodule in sorted(transport._REGISTRY.items()): 

181 if scheme == transport.NO_SCHEME or submodule in seen: 

182 continue 

183 seen.add(submodule) 

184 

185 relpath = os.path.relpath(submodule.__file__, start=root_path) 

186 heading = '%s (%s)' % (scheme, relpath) 

187 print(' %s' % heading) 

188 print(' %s' % ('~' * len(heading))) 

189 print(' %s' % submodule.__doc__.split('\n')[0]) 

190 print() 

191 

192 kwargs = extract_kwargs(submodule.open.__doc__) 

193 if kwargs: 

194 print(to_docstring(kwargs, lpad=u' ')) 

195 

196 print(' Examples') 

197 print(' --------') 

198 print() 

199 print(extract_examples_from_readme_rst()) 

200 

201 print(' This function also supports transparent compression and decompression ') 

202 print(' using the following codecs:') 

203 print() 

204 for extension in compression.get_supported_extensions(): 

205 print(' * %s' % extension) 

206 print() 

207 print(' The function depends on the file extension to determine the appropriate codec.') 

208 

209 # 

210 # The docstring can be None if -OO was passed to the interpreter. 

211 # 

212 if f.__doc__: 

213 f.__doc__ = f.__doc__.replace(PLACEHOLDER, buf.getvalue()) 

214 

215 

216def tweak_parse_uri_docstring(f): 

217 buf = io.StringIO() 

218 seen = set() 

219 schemes = [] 

220 examples = [] 

221 

222 for scheme, submodule in sorted(transport._REGISTRY.items()): 

223 if scheme == transport.NO_SCHEME or submodule in seen: 

224 continue 

225 schemes.append(scheme) 

226 seen.add(submodule) 

227 

228 try: 

229 examples.extend(submodule.URI_EXAMPLES) 

230 except AttributeError: 

231 pass 

232 

233 with contextlib.redirect_stdout(buf): 

234 print(' Supported URI schemes are:') 

235 print() 

236 for scheme in schemes: 

237 print(' * %s' % scheme) 

238 print() 

239 print(' Valid URI examples::') 

240 print() 

241 for example in examples: 

242 print(' * %s' % example) 

243 

244 if f.__doc__: 

245 f.__doc__ = f.__doc__.replace(PLACEHOLDER, buf.getvalue())