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
« 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#
9"""Common functions for working with docstrings.
11For internal use only.
12"""
14import contextlib
15import inspect
16import io
17import os.path
18import re
20from . import compression
21from . import transport
23PLACEHOLDER = ' smart_open/doctools.py magic goes here'
26def extract_kwargs(docstring):
27 """Extract keyword argument documentation from a function's docstring.
29 Parameters
30 ----------
31 docstring: str
32 The docstring to extract keyword arguments from.
34 Returns
35 -------
36 list of (str, str, list str)
38 str
39 The name of the keyword argument.
40 str
41 Its type.
42 str
43 Its documentation as a list of lines.
45 Notes
46 -----
47 The implementation is rather fragile. It expects the following:
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.
55 Examples
56 --------
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.'])
71 """
72 if not docstring:
73 return []
75 lines = inspect.cleandoc(docstring).split('\n')
76 retval = []
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)
85 if not lines:
86 return []
88 lines.pop(0)
89 lines.pop(0)
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))
99 return retval
102def to_docstring(kwargs, lpad=''):
103 """Reconstruct a docstring from keyword argument info.
105 Basically reverses :func:`extract_kwargs`.
107 Parameters
108 ----------
109 kwargs: list
110 Output from the extract_kwargs function
111 lpad: str, optional
112 Padding string (from the left).
114 Returns
115 -------
116 str
117 The docstring snippet documenting the keyword arguments.
119 Examples
120 --------
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.
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()
141def extract_examples_from_readme_rst(indent=' '):
142 """Extract examples from this project's README.rst file.
144 Parameters
145 ----------
146 indent: str
147 Prepend each line with this string. Should contain some number of spaces.
149 Returns
150 -------
151 str
152 The examples.
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'
171def tweak_open_docstring(f):
172 buf = io.StringIO()
173 seen = set()
175 root_path = os.path.dirname(os.path.dirname(__file__))
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)
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()
192 kwargs = extract_kwargs(submodule.open.__doc__)
193 if kwargs:
194 print(to_docstring(kwargs, lpad=u' '))
196 print(' Examples')
197 print(' --------')
198 print()
199 print(extract_examples_from_readme_rst())
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.')
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())
216def tweak_parse_uri_docstring(f):
217 buf = io.StringIO()
218 seen = set()
219 schemes = []
220 examples = []
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)
228 try:
229 examples.extend(submodule.URI_EXAMPLES)
230 except AttributeError:
231 pass
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)
244 if f.__doc__:
245 f.__doc__ = f.__doc__.replace(PLACEHOLDER, buf.getvalue())