|
13 | 13 | # limitations under the License. |
14 | 14 |
|
15 | 15 | import argparse |
| 16 | +import cgi |
| 17 | +import doctest |
16 | 18 | import inspect |
17 | 19 | import json |
18 | 20 | import os |
|
27 | 29 | from verify_included_modules import get_public_modules |
28 | 30 |
|
29 | 31 |
|
| 32 | +_DOCSTRING_TEST_PARSER = doctest.DocTestParser() |
| 33 | + |
| 34 | + |
30 | 35 | class Module(object): |
31 | 36 |
|
32 | 37 | def __init__(self, module_id, name, description=None, |
@@ -148,36 +153,38 @@ def from_pdoc(cls, element): |
148 | 153 | components = element.refname.split('.') |
149 | 154 |
|
150 | 155 | mod = __import__(components[0]) |
151 | | - |
152 | 156 | for comp in components[1:]: |
153 | 157 | mod = getattr(mod, comp) |
154 | 158 |
|
155 | | - build_source(mod, method) |
| 159 | + # Get method line number. |
| 160 | + method.add_source_line(get_source_line_number(mod)) |
| 161 | + |
| 162 | + # Get method Examples. |
| 163 | + examples = get_examples_from_docstring(element.docstring) |
| 164 | + if examples: |
| 165 | + method.add_example(examples) |
156 | 166 |
|
157 | 167 | if element.docstring: |
158 | 168 | if not isinstance(element, pdoc.Class) and element.cls: |
159 | | - cls = element.cls.cls |
| 169 | + klass = element.cls.cls |
160 | 170 | elif element.cls: |
161 | | - cls = element.cls |
| 171 | + klass = element.cls |
162 | 172 | else: |
163 | | - cls = None |
| 173 | + klass = None |
164 | 174 |
|
165 | 175 | # Hack for old-style classes |
166 | | - if str(cls)[0] != '<': |
167 | | - cls = '<class \'' + str(cls) + '\'>' |
| 176 | + if not str(klass).startswith('<'): |
| 177 | + klass = '<class \'%s\'>' % (klass,) |
168 | 178 |
|
169 | 179 | try: |
170 | | - method_info = parse_docstring(element.docstring, cls) |
| 180 | + method_info = parse_docstring(element.docstring, klass) |
171 | 181 | except (MethodParsingException, IndexError): |
172 | 182 | return method |
173 | 183 |
|
174 | 184 | for name, data in method_info['arguments'].items(): |
175 | 185 | param = Param.from_docstring_section(name, data) |
176 | 186 | method.add_param(param) |
177 | 187 |
|
178 | | - if method_info.get('example'): |
179 | | - method.add_example(method_info['example']) |
180 | | - |
181 | 188 | if method_info.get('return'): |
182 | 189 | if len(method_info['return']['type_name']) > 0: |
183 | 190 | type_name = method_info.get('return').get('type_name') |
@@ -296,9 +303,35 @@ def clean_source_path(module): |
296 | 303 | return '%s.py' % (source_id.replace('.', '/'),) |
297 | 304 |
|
298 | 305 |
|
| 306 | +def get_examples_from_docstring(doc_str): |
| 307 | + """Parse doctest style code examples from a docstring.""" |
| 308 | + examples = _DOCSTRING_TEST_PARSER.get_examples(doc_str) |
| 309 | + example_str = '' |
| 310 | + for example in examples: |
| 311 | + example_str += '%s' % (example.source,) |
| 312 | + example_str += '%s' % (example.want,) |
| 313 | + |
| 314 | + return cgi.escape(example_str) |
| 315 | + |
| 316 | + |
| 317 | +def get_source_line_number(module): |
| 318 | + if isinstance(module, (types.ModuleType, types.ClassType, |
| 319 | + types.MethodType, types.FunctionType, |
| 320 | + types.TracebackType, types.FrameType, |
| 321 | + types.CodeType, types.TypeType)): |
| 322 | + |
| 323 | + _, line = inspect.getsourcelines(module) |
| 324 | + source_path = clean_source_path(module) |
| 325 | + |
| 326 | + if line: |
| 327 | + source_path = source_path + '#L' + str(line) |
| 328 | + return source_path |
| 329 | + |
| 330 | + |
299 | 331 | def process_code_blocks(doc): |
300 | 332 | blocks = [] |
301 | 333 | index = 0 |
| 334 | + |
302 | 335 | for line in doc.splitlines(True): |
303 | 336 | if len(blocks) - 1 < index: |
304 | 337 | blocks.append('') |
|
0 commit comments