blob: f0461447b8f55a944609964d7ea022725987d882 [file] [log] [blame]
# $Id: __init__.py 5618 2008-07-28 08:37:32Z strank $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
"""
This package contains the Python Source Reader modules.
"""
__docformat__ = 'reStructuredText'
import sys
import docutils.readers
from docutils.readers.python import moduleparser
from docutils import parsers
from docutils import nodes
from docutils.readers.python import pynodes
from docutils import readers
class Reader(docutils.readers.Reader):
config_section = 'python reader'
config_section_dependencies = ('readers',)
default_parser = 'restructuredtext'
def parse(self):
"""Parse `self.input` into a document tree."""
self.document = document = self.new_document()
module_section = moduleparser.parse_module(self.input,
self.source.source_path)
module_section.walk(DocformatVisitor(self.document))
visitor = DocstringFormattingVisitor(
document=document,
default_parser=self.default_parser)
module_section.walk(visitor)
self.document.append(module_section)
class DocformatVisitor(nodes.SparseNodeVisitor):
"""
This sets docformat attributes in a module. Wherever an assignment
to __docformat__ is found, we look for the enclosing scope -- a class,
a module, or a function -- and set the docformat attribute there.
We can't do this during the DocstringFormattingVisitor walking,
because __docformat__ may appear below a docstring in that format
(typically below the module docstring).
"""
def visit_attribute(self, node):
assert isinstance(node[0], pynodes.object_name)
name = node[0][0].data
if name != '__docformat__':
return
value = None
for child in children:
if isinstance(child, pynodes.expression_value):
value = child[0].data
break
assert value.startswith("'") or value.startswith('"'), "__docformat__ must be assigned a string literal (not %s); line: %s" % (value, node['lineno'])
name = name[1:-1]
looking_in = node.parent
while not isinstance(looking_in, (pynodes.module_section,
pynodes.function_section,
pynodes.class_section)):
looking_in = looking_in.parent
looking_in['docformat'] = name
class DocstringFormattingVisitor(nodes.SparseNodeVisitor):
def __init__(self, document, default_parser):
self.document = document
self.default_parser = default_parser
self.parsers = {}
def visit_docstring(self, node):
text = node[0].data
docformat = self.find_docformat(node)
del node[0]
node['docformat'] = docformat
parser = self.get_parser(docformat)
parser.parse(text, self.document)
for child in self.document.children:
node.append(child)
self.document.current_source = self.document.current_line = None
del self.document[:]
def get_parser(self, parser_name):
"""
Get a parser based on its name. We reuse parsers during this
visitation, so parser instances are cached.
"""
parser_name = parsers._parser_aliases.get(parser_name, parser_name)
if parser_name not in self.parsers:
cls = parsers.get_parser_class(parser_name)
self.parsers[parser_name] = cls()
return self.parsers[parser_name]
def find_docformat(self, node):
"""
Find the __docformat__ closest to this node (i.e., look in the
class or module)
"""
while node:
if node.get('docformat'):
return node['docformat']
node = node.parent
return self.default_parser
if __name__ == '__main__':
try:
import locale
locale.setlocale(locale.LC_ALL, '')
except:
pass
from docutils.core import publish_cmdline, default_description
description = ('Generates pseudo-XML from Python modules '
'(for testing purposes). ' + default_description)
publish_cmdline(description=description,
reader=Reader())