1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
# Author: David Goodger
# Contact: goodger@users.sourceforge.net
# Revision: $Revision$
# Date: $Date$
# Copyright: This module has been placed in the public domain.
"""
This package contains the Python Source Reader modules.
It requires Python 2.2 or higher (`moduleparser` depends on the
`compiler` and `tokenize` 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 not self.parsers.has_key(parser_name):
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())
|