def visit_doctest_block(self, node: Node) -> None: pysrc = node[0].astext() if node.get('codeblock'): self.body.append(flatten(colorize_codeblock(pysrc))) else: self.body.append(flatten(colorize_doctest(pysrc))) raise SkipNode()
def test_EpydocLinker_translate_identifier_xref_intersphinx_relative_id(): """ Return the link from inventory using short names, by resolving them based on the imports done in the module. """ system = model.System() inventory = SphinxInventory(system.msg) inventory._links['ext_package.ext_module'] = ('http://tm.tld', 'some.html') system.intersphinx = inventory target = model.Module(system, 'ignore-name', 'ignore-docstring') # Here we set up the target module as it would have this import. # from ext_package import ext_module ext_package = model.Module(system, 'ext_package', 'ignore-docstring') target.contents['ext_module'] = model.Module(system, 'ext_module', 'ignore-docstring', parent=ext_package) sut = epydoc2stan._EpydocLinker(target) # This is called for the L{ext_module<Pretty Text>} markup. result = sut.translate_identifier_xref('ext_module', 'Pretty Text') expected = ( '<a href="http://tm.tld/some.html"><code>Pretty Text</code></a>') assert expected == flatten(result)
def visit_title_reference(self, node): m = _TARGET_RE.match(node.astext()) if m: text, target = m.groups() else: target = text = node.astext() xref = self._linker.translate_identifier_xref(target, text) self.body.append(flatten(xref)) raise SkipNode()
def test_annotation_formatter(annotation: str) -> None: """Perform two checks on the annotation formatter: - all type names in the annotation are passed to the linker - the plain text version of the output matches the input """ expected_lookups = [ found[1:-1] for found in re.findall('<[^>]*>', annotation) ] expected_text = annotation.replace('<', '').replace('>', '') mod = fromText(f''' value: {expected_text} ''') obj = mod.contents['value'] parsed = epydoc2stan.get_parsed_type(obj) assert parsed is not None linker = RecordingAnnotationLinker() stan = parsed.to_stan(linker) assert linker.requests == expected_lookups html = flatten(stan) assert html.startswith('<code>') assert html.endswith('</code>') text = html[6:-7] assert text == expected_text
def test_colorize_codeblock(): src = ''' def foo(): """A multi-line docstring. The "doc" part doesn't matter for this test, but the "string" part does. """ return list({1, 2, 3}) class Foo: def __init__(self): # Nothing to do. pass '''.lstrip() expected = ''' <pre class="py-doctest"> <span class="py-keyword">def</span> <span class="py-defname">foo</span>(): <span class="py-string">"""A multi-line docstring.</span> <span class="py-string"> The "doc" part doesn't matter for this test,</span> <span class="py-string"> but the "string" part does.</span> <span class="py-string"> """</span> <span class="py-keyword">return</span> <span class="py-builtin">list</span>({1, 2, 3}) <span class="py-keyword">class</span> <span class="py-defname">Foo</span>: <span class="py-keyword">def</span> <span class="py-defname">__init__</span>(self): <span class="py-comment"># Nothing to do.</span> <span class="py-keyword">pass</span> </pre> '''.strip() assert flatten(colorize_codeblock(src)) == expected
def test_EpydocLinker_translate_identifier_xref_intersphinx_link_not_found(): """ A message is sent to stdout when no link could be found for the reference, while returning the reference name without an A link tag. The message contains the full name under which the reference was resolved. """ system = model.System() target = model.Module(system, 'ignore-name', 'ignore-docstring') # Here we set up the target module as it would have this import. # from ext_package import ext_module ext_package = model.Module(system, 'ext_package', 'ignore-docstring') target.contents['ext_module'] = model.Module(system, 'ext_module', 'ignore-docstring', parent=ext_package) stdout = StringIO() sut = epydoc2stan._EpydocLinker(target) try: # FIXME: https://github.com/twisted/pydoctor/issues/112 # We no have this ugly hack to capture stdout. previousStdout = sys.stdout sys.stdout = stdout # This is called for the L{ext_module} markup. result = sut.translate_identifier_xref(fullID='ext_module', prettyID='ext_module') finally: sys.stdout = previousStdout assert '<code>ext_module</code>' == flatten(result) expected = ("ignore-name:0 invalid ref to 'ext_module' " "resolved as 'ext_package.ext_module'\n") assert expected == stdout.getvalue()
def docstring2html(obj: model.Documentable) -> str: stan = epydoc2stan.format_docstring(obj) assert stan.tagName == 'div', stan # We strip off break lines for the sake of simplicity. return flatten(stan).replace('><', '>\n<').replace('<wbr></wbr>', '').replace( '<wbr>\n</wbr>', '')
def rst2html( docstring: str, linker: DocstringLinker = NotFoundLinker()) -> str: """ Render a docstring to HTML. """ errors: List[ParseError] = [] parsed = parse_docstring(docstring, errors) assert not errors return flatten(parsed.to_stan(linker))
def visit_title_reference(self, node: Node) -> None: m = _TARGET_RE.match(node.astext()) if m: label, target = m.groups() else: label = target = node.astext() # TODO: 'node.line' is None for some reason. # https://github.com/twisted/pydoctor/issues/237 lineno = 0 self.body.append(flatten(self._linker.link_xref(target, label, lineno))) raise SkipNode()
def test_module_docformat(capsys: CapSys) -> None: """ Test if Module.docformat effectively override System.options.docformat """ system = model.System() system.options.docformat = 'plaintext' mod = fromText(''' """ Link to pydoctor: U{pydoctor <https://github.com/twisted/pydoctor>}. """ __docformat__ = "epytext" ''', modname='test_epy', system=system) epytext_output = epydoc2stan.format_docstring(mod) captured = capsys.readouterr().out assert not captured mod = fromText(''' """ Link to pydoctor: `pydoctor <https://github.com/twisted/pydoctor>`_. """ __docformat__ = "restructuredtext en" ''', modname='test_rst', system=system) restructuredtext_output = epydoc2stan.format_docstring(mod) captured = capsys.readouterr().out assert not captured assert 'href="https://github.com/twisted/pydoctor"' in flatten( epytext_output) assert 'href="https://github.com/twisted/pydoctor"' in flatten( restructuredtext_output)
def visit_title_reference(self, node): m = _TARGET_RE.match(node.astext()) if m: text, target = m.groups() else: target = text = node.astext() label = tags.code(text) try: url = self._linker.resolve_identifier_xref(target) except LookupError: xref = label else: xref = tags.a(label, href=url) self.body.append(flatten(xref)) raise SkipNode()
def test_colorize_doctest_no_output(): src = ''' Test expecting no output: >>> None '''.lstrip() expected = ''' <pre class="py-doctest"> Test expecting no output: <span class="py-prompt"> >>> </span><span class="py-builtin">None</span> </pre> '''.strip() assert flatten(colorize_doctest(src)) == expected
def visit_title_reference(self, node: Node) -> None: m = _TARGET_RE.match(node.astext()) if m: text, target = m.groups() else: target = text = node.astext() label = tags.code(text) # TODO: 'node.line' is None for some reason. # https://github.com/twisted/pydoctor/issues/237 lineno = 0 try: url = self._linker.resolve_identifier_xref(target, lineno) except LookupError: xref = label else: xref = tags.a(label, href=url) self.body.append(flatten(xref)) raise SkipNode()
def test_colorize_doctest_exception(): src = ''' Test division by zero: >>> 1/0 Traceback (most recent call last): ZeroDivisionError: integer division or modulo by zero '''.lstrip() expected = ''' <pre class="py-doctest"> Test division by zero: <span class="py-prompt"> >>> </span>1/0 <span class="py-except"> Traceback (most recent call last):</span> <span class="py-except"> ZeroDivisionError: integer division or modulo by zero</span> </pre> '''.strip() assert flatten(colorize_doctest(src)) == expected
def test_colorize_doctest_more_string(): src = ''' Test multi-line string: >>> """A ... B ... C""" 'A\\nB\\nC' '''.lstrip() expected = ''' <pre class="py-doctest"> Test multi-line string: <span class="py-prompt"> >>> </span><span class="py-string">"""A</span> <span class="py-more"> ... </span><span class="py-string">B</span> <span class="py-more"> ... </span><span class="py-string">C"""</span> <span class="py-output"> 'A\\nB\\nC'</span> </pre> '''.strip() assert flatten(colorize_doctest(src)) == expected
def test_EpydocLinker_translate_identifier_xref_intersphinx_absolute_id(): """ Returns the link from Sphinx inventory based on a cross reference ID specified in absolute dotted path and with a custom pretty text for the URL. """ system = model.System() inventory = SphinxInventory(system.msg) inventory._links['base.module.other'] = ('http://tm.tld', 'some.html') system.intersphinx = inventory target = model.Module(system, 'ignore-name', 'ignore-docstring') sut = epydoc2stan._EpydocLinker(target) result = sut.translate_identifier_xref('base.module.other', 'base.module.pretty') expected = ( '<a href="http://tm.tld/some.html"><code>base.module.pretty</code></a>' ) assert expected == flatten(result)
def test_colorize_doctest_more_input(): src = ''' Test multi-line expression: >>> [chr(i + 65) ... for i in range(26) ... if i % 2 == 0] ['A', 'C', 'E', 'G', 'I', 'K', 'M', 'O', 'Q', 'S', 'U', 'W', 'Y'] '''.lstrip() expected = ''' <pre class="py-doctest"> Test multi-line expression: <span class="py-prompt"> >>> </span>[<span class="py-builtin">chr</span>(i + 65) <span class="py-more"> ... </span> <span class="py-keyword">for</span> i <span class="py-keyword">in</span> <span class="py-builtin">range</span>(26) <span class="py-more"> ... </span> <span class="py-keyword">if</span> i % 2 == 0] <span class="py-output"> ['A', 'C', 'E', 'G', 'I', 'K', 'M', 'O', 'Q', 'S', 'U', 'W', 'Y']</span> </pre> '''.strip() assert flatten(colorize_doctest(src)) == expected
def test_property_decorator(systemcls: Type[model.System]) -> None: """A function decorated with '@property' is documented as an attribute.""" mod = fromText(''' class C: @property def prop(self) -> str: """For sale.""" return 'seaside' @property def oldschool(self): """ @return: For rent. @rtype: string @see: U{https://example.com/} """ return 'downtown' ''', modname='test', systemcls=systemcls) C = mod.contents['C'] prop = C.contents['prop'] assert isinstance(prop, model.Attribute) assert prop.kind == 'Property' assert prop.docstring == """For sale.""" assert type2str(prop.annotation) == 'str' oldschool = C.contents['oldschool'] assert isinstance(oldschool, model.Attribute) assert oldschool.kind == 'Property' assert isinstance(oldschool.parsed_docstring, ParsedEpytextDocstring) assert unwrap(oldschool.parsed_docstring) == """For rent.""" assert flatten(format_summary(oldschool)) == '<span>For rent.</span>' assert isinstance(oldschool.parsed_type, ParsedEpytextDocstring) assert str(unwrap(oldschool.parsed_type)) == 'string' fields = oldschool.parsed_docstring.fields assert len(fields) == 1 assert fields[0].tag() == 'see'
def summary2html(obj: model.Documentable) -> str: stan = epydoc2stan.format_summary(obj) assert stan.tagName == 'span', stan return flatten(stan.children)
def rst2html(s: str) -> str: errors: List[ParseError] = [] parsed = parse_docstring(s, errors) assert not errors return flatten(parsed.to_stan(None))
def epytext2html(s): errors = [] parsed = parse_docstring(s, errors) assert not errors return flatten(parsed.to_stan(None))
def to_html( parsed_docstring: ParsedDocstring, linker: DocstringLinker = NotFoundLinker() ) -> str: return flatten(parsed_docstring.to_stan(linker))
def epytext2html(s: str, linker: DocstringLinker = NotFoundLinker()) -> str: errs: List[ParseError] = [] v = flatten(epytext.parse_docstring(s, errs).to_stan(linker)) if errs: raise errs[0] return (v or '').rstrip()
def docstring2html(docstring: model.Documentable) -> str: stan = epydoc2stan.format_docstring(docstring) return flatten(stan).replace('><', '>\n<')
def epytext2html(s: str, linker: DocstringLinker = NotFoundLinker()) -> str: errors: List[ParseError] = [] parsed = parse_docstring(s, errors) assert not errors return flatten(parsed.to_stan(linker))
def docstring2html(obj: model.Documentable) -> str: stan = epydoc2stan.format_docstring(obj) assert stan.tagName == 'div', stan return flatten(stan.children).replace('><', '>\n<')
def epytext2html(s): errs = [] v = flatten(epytext.parse_docstring(s, errs).to_stan(None)) if errs: raise errs[0] return (v or '').rstrip()
def get_summary(func): stan = epydoc2stan.doc2stan(mod.contents[func], summary=True) assert stan.tagName == 'span', stan return flatten(stan.children)
def to_html(parsed_docstring): return flatten(parsed_docstring.to_stan(None))
def get_summary(func: str) -> str: stan = epydoc2stan.format_summary(mod.contents[func]) assert stan.tagName == 'span', stan return flatten(stan.children)