def run():
print('<STR_LIT>')<EOL>md_files = []<EOL>for root, _, filenames in os.walk(os.path.join(package_root, '<STR_LIT>')):<EOL><INDENT>for filename in filenames:<EOL><INDENT>if not filename.endswith('<STR_LIT>'):<EOL><INDENT>continue<EOL><DEDENT>md_files.append(os.path.join(root, filename))<EOL><DEDENT><DEDENT>parser = CommonMark.Parser()<EOL>for md_file in md_files:<EOL><INDENT>md_file_relative = md_file[len(package_root) + <NUM_LIT:1>:]<EOL>if md_file_relative in md_source_map:<EOL><INDENT>py_files = md_source_map[md_file_relative]<EOL>py_paths = [os.path.join(package_root, py_file) for py_file in py_files]<EOL><DEDENT>else:<EOL><INDENT>py_files = [os.path.basename(md_file).replace('<STR_LIT>', '<STR_LIT>')]<EOL>py_paths = [os.path.join(package_root, package_name, py_files[<NUM_LIT:0>])]<EOL>if not os.path.exists(py_paths[<NUM_LIT:0>]):<EOL><INDENT>continue<EOL><DEDENT><DEDENT>with open(md_file, '<STR_LIT:rb>') as f:<EOL><INDENT>markdown = f.read().decode('<STR_LIT:utf-8>')<EOL><DEDENT>original_markdown = markdown<EOL>md_lines = list(markdown.splitlines())<EOL>md_ast = parser.parse(markdown)<EOL>last_class = []<EOL>last = {}<EOL>sections = OrderedDict()<EOL>find_sections(md_ast, sections, last, last_class, markdown.count("<STR_LIT:\n>") + <NUM_LIT:1>)<EOL>md_chunks = {}<EOL>for index, py_file in enumerate(py_files):<EOL><INDENT>py_path = py_paths[index]<EOL>with open(os.path.join(py_path), '<STR_LIT:rb>') as f:<EOL><INDENT>code = f.read().decode('<STR_LIT:utf-8>')<EOL>module_ast = ast.parse(code, filename=py_file)<EOL>code_lines = list(code.splitlines())<EOL><DEDENT>for node in ast.iter_child_nodes(module_ast):<EOL><INDENT>walk_ast(node, code_lines, sections, md_chunks)<EOL><DEDENT><DEDENT>added_lines = <NUM_LIT:0><EOL>def _replace_md(key, sections, md_chunk, md_lines, added_lines):<EOL><INDENT>start, end = sections[key]<EOL>start -= <NUM_LIT:1><EOL>start += added_lines<EOL>end += added_lines<EOL>new_lines = md_chunk.split('<STR_LIT:\n>')<EOL>added_lines += len(new_lines) - (end - start)<EOL>if start > <NUM_LIT:0> and md_lines[start][<NUM_LIT:0>:<NUM_LIT:4>] == '<STR_LIT>' and md_lines[start - <NUM_LIT:1>][<NUM_LIT:0>:<NUM_LIT:1>] == '<STR_LIT:>>':<EOL><INDENT>added_lines += <NUM_LIT:1><EOL>new_lines.insert(<NUM_LIT:0>, '<STR_LIT>')<EOL><DEDENT>md_lines[start:end] = new_lines<EOL>return added_lines<EOL><DEDENT>for key in sections:<EOL><INDENT>if key not in md_chunks:<EOL><INDENT>raise ValueError('<STR_LIT>' % key[<NUM_LIT:1>])<EOL><DEDENT>added_lines = _replace_md(key, sections, md_chunks[key], md_lines, added_lines)<EOL><DEDENT>markdown = '<STR_LIT:\n>'.join(md_lines).strip() + '<STR_LIT:\n>'<EOL>if original_markdown != markdown:<EOL><INDENT>with open(md_file, '<STR_LIT:wb>') as f:<EOL><INDENT>f.write(markdown.encode('<STR_LIT:utf-8>'))<EOL><DEDENT><DEDENT><DEDENT>
Looks through the docs/ dir and parses each markdown document, looking for
sections to update from Python docstrings. Looks for section headers in
the format:

 - ### `ClassName()` class
 - ##### `.method_name()` method
 - ##### `.attribute_name` attribute
 - ### `function_name()` function

The markdown content following these section headers up until the next
section header will be replaced by new markdown generated from the Python
docstrings of the associated source files.

By default maps docs/{name}.md to {modulename}/{name}.py. Allows for
custom mapping via the md_source_map variable.