summaryrefslogtreecommitdiff
path: root/sandbox/tibs/pysource/pysource.py
blob: a62c96ebbdb617e6d91d0ba9441f1f177d8f1495 (plain)
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#! /usr/bin/env python
"""A simple command line interface for the pysource package

This will become more interesting later on...
"""

import os
import sys
import getopt

import docutils.nodes
import docutils.utils

# Local modules
import utils
import visit
import html

import transform

__docformat__ = "reST"


# ----------------------------------------------------------------------
def rest_document(filename):
    """Return an reST document.
    """

    from docutils.parsers.rst import Parser

    file = open(filename)
    try:
        text = file.read()
    finally:
        file.close()

    parser = Parser()
    docroot = docutils.utils.new_document()
    parser.parse(text,docroot)
    return docroot


# ----------------------------------------------------------------------
# I don't much like the Unix command line style (I always thought the
# VMS approach was much more flexible and sensible), but it *does* seem
# to be what people expect these days...

options = [
    # long option, short, description
    ("verbose",    "v",   "Report on progress in more detail"),
    ("quiet",      "q",   "Suppress normal progress messages"),
    ("text",       "t",   "The input file is a plain (text) reST file"),
    ("show",       "s",   "Output basic information about the input"),
    ("ast",        "a",   "Output a representation of the AST"),
    ("xml",        "x",   "Output an XML representation of the input"),
    ("html",       "h",   "Output an HTML representation of the input [default]"),
    ("pretty",     "p",   "Output a 'pretty' representation of the input"),
    ("doctest",    "d",   "Treat a reST file as doctest input."),
    ("help",       "h",   "Show 'help' information"),
    ("new",        "n",   "Use David Goodger's HTML Writer (sort of)"),
    ("stdout",     "",    "Write output to stdout, instead of a file"),
    ]

def print_usage():
    docstring = visit.Docstring(main.__doc__)
    docstring.show(sys.stdout)
    print
    print "    <switches> are:"
    print
    for longopt, shortopt, description in options:
        if shortopt:
            print "      -%s, --%-9s %s"%(shortopt,longopt,description)
        else:
            print "          --%-9s %s"%(longopt,description)

def main():
    """The command line interface to docutil's Python documentation extractor.

    Usage: ``pysource.py <switches> <inpath> [<outfile>]``

        <inpath> is the path to a package or module.

        <outfile> is the path to the output file. If it's not given, then
        output will be written to a file with the same name as the input
        file, but defaulting to the current directory, and with extension
        derived from the type of output:

        - show   -> ``.show``
        - ast    -> ``.ast``
        - xml    -> ``.xml``
        - html   -> ``.html``
        - pretty -> ``.pretty``

        (unless --stdout is requested). The default is --html.

        Note that progress messages (and ``verb`` information) are written
        to ``sys.stderr``.
    """

    if len(sys.argv) <= 1:
        print "Not enough arguments"
        print_usage()
        return

    shortopts = ''.join([option[1] for option in options])
    longopts = [option[0] for option in options]
    try:
        opts, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
    except getopt.GetoptError,detail:
        print "Problem with options:",detail
        print_usage()
        return

    verbose = 0
    quiet   = 0
    input_format = "python"
    output_format = "html"
    want_docutilstree = 1
    new_writer = 0
    write_stdout = 0

    for opt, arg in opts:
        if opt in ["-?","--help"]:
            print_usage()
            return
        elif opt in ["-n","--new"]:
            new_writer = 1
            output_format = "html"
            print >>sys.stderr, "Using new HTML Writer"
        elif opt in ["-v","--verbose"]:
            verbose = 1
        elif opt in ["-q","--quiet"]:
            quiet = 1
        elif opt in ["-t","--text"]:
            input_format = "text"
        elif opt in ["-s","--show"]:
            output_format = "show"
            want_docutilstree = 0
        elif opt in ["-a","--ast"]:
            output_format = "ast"
            want_docutilstree = 0
        elif opt in ["-x","--xml"]:
            output_format = "xml"
        elif opt in ["-h","--html"]:
            output_format = "html"
        elif opt in ["-d","--doctest"]:
            output_format = "doctest"
        elif opt in ["-p","--pretty"]:
            output_format = "pretty"
        elif opt == "--stdout":
            write_stdout = 1
        else:
            raise getopt.GetoptError, "getopt should have saved us!"

    if len(args) == 0 or len(args) > 2:
        print "Please specify an input and an (optional) output"
        print_usage()
        return

    if input_format == "text" and \
       output_format not in ["xml","html","pretty","doctest"]:
        print "--text only supports --xml, --html, --pretty or --doctest"
        print_usage()
        return

    if input_format == "text" and output_format == "doctest" \
       and len(args) == 2:
        print "--doctest does not accept an output file"
        # Should it?
        print_usage()
        return

    if write_stdout and len(args) == 2:
        print "It doesn't make sense to specify --stdout and an output file"
        print_usage()
        return

    filename = args[0]
    if len(args) == 2:
        if not quiet:
            print >>sys.stderr, "... Output will go to",args[1]
        outstream = open(args[1],"w")
    elif write_stdout:
        if not quiet:
            print >>sys.stderr, "... Output will go to standard output"
        outstream = sys.stdout
    else:
        head,tail = os.path.split(filename)
        base,ext  = os.path.splitext(tail)
        outname = "%s.%s"%(base,output_format)
        if not quiet:
            print >>sys.stderr, "... Output will go to",outname
        outstream = open(outname,"w")

    try:
        if output_format == "doctest":
            from doctest import Tester
            if not quiet: print >>sys.stderr, "*** Doctesting the document"
            t = Tester(globs={},verbose=verbose)
            (fail,total) = t.runstring(open(filename).read(),filename)
            if not quiet and not verbose:
                print >>sys.stderr, "*** ",
                if fail:
                    print "%d of"%fail,
                if total == 1:
                    print "1 example",
                else:
                    print "%d examples"%total,
                if fail:
                    print "failed"
                else:
                    print "passed"
        elif input_format == "text":
            if not quiet: print >>sys.stderr, "*** Making the document"
            document = rest_document(filename)
        else:
            if os.path.isdir(filename):
                print >>sys.stderr, "*** Parsing the Python package",filename
                thing = visit.Package(None, filename)
            else:
                print >>sys.stderr, "*** Parsing the Python file",filename
                thing = visit.Module(None, filename)

            if want_docutilstree:
                if not quiet:
                    print >>sys.stderr, "*** Making the document"
                with_groups = not new_writer
                process = transform.Process(with_groups)
                document = process(thing)

        if output_format == "show":
            thing.show(outstream)
        elif output_format == "ast":
            thing.show_ast(outstream)
            print
        elif output_format == "pretty":
            outstream.write(document.pformat(indent="  "))
        elif output_format == "xml":
            if not quiet: print >>sys.stderr, "*** Producing a DOM tree"
            domtree = document.asdom()
            if not quiet: print >>sys.stderr, "    Writing XML"
            domtree.writexml(outstream,indent="", addindent="  ",newl="\n")
        elif output_format == "html":
            if not quiet: print >>sys.stderr, "*** Writing HTML"
            if new_writer:
                from docutils.writers.html4css1 import Writer
                writer = Writer()
                writer.write(document,outstream)
            elif input_format == "text":
                writer = html.Writer()
                writer(document,outstream)
            else:
                writer = html.PythonWriter()
                writer(document,outstream)
    finally:
        if outstream != sys.stdout:
            outstream.close()


# ----------------------------------------------------------------------
if __name__ == "__main__":
    main()