epydoc-commits Mailing List for Python API documentation generation tool (Page 15)
Brought to you by:
edloper
You can subscribe to this list here.
2006 |
Jan
|
Feb
|
Mar
|
Apr
(77) |
May
|
Jun
(6) |
Jul
(8) |
Aug
(91) |
Sep
(67) |
Oct
(4) |
Nov
|
Dec
(1) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(17) |
Feb
(135) |
Mar
(25) |
Apr
|
May
(1) |
Jun
(1) |
Jul
(7) |
Aug
|
Sep
(62) |
Oct
(1) |
Nov
(3) |
Dec
|
2008 |
Jan
(40) |
Feb
(102) |
Mar
(5) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2009 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <ed...@us...> - 2007-02-11 16:53:57
|
Revision: 1462 http://svn.sourceforge.net/epydoc/?rev=1462&view=rev Author: edloper Date: 2007-02-11 08:53:49 -0800 (Sun, 11 Feb 2007) Log Message: ----------- - Added options to control return value:: --fail-on-error --fail-on-warning --fail-on-docstring-warning All three options cause epydoc to exit with status 1 if a message of the indicated level or higher is generated. This can be useful for e.g., incorperation into makefiles. (See sf bug 1558792) Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2007-02-11 16:02:10 UTC (rev 1461) +++ trunk/epydoc/src/epydoc/cli.py 2007-02-11 16:53:49 UTC (rev 1462) @@ -92,6 +92,7 @@ generation_group = OptionGroup(optparser, 'Generation options') output_group = OptionGroup(optparser, 'Output options') graph_group = OptionGroup(optparser, 'Graph options') + return_group = OptionGroup(optparser, 'Return value options') optparser.add_option( '--config', action='append', dest="configfiles", metavar='FILE', @@ -252,11 +253,29 @@ ("Run the hotshot profiler on epydoc itself. Output " "will be written to profile.out.")) + return_group.add_option( + "--fail-on-error", action="store_const", dest="fail_on", + const=log.ERROR, + help="Return a non-zero exit status, indicating failure, if any " + "errors are encountered.") + return_group.add_option( + "--fail-on-warning", action="store_const", dest="fail_on", + const=log.WARNING, + help="Return a non-zero exit status, indicating failure, if any " + "errors or warnings are encountered (not including docstring " + "warnings).") + return_group.add_option( + "--fail-on-docstring-warning", action="store_const", dest="fail_on", + const=log.DOCSTRING_WARNING, + help="Return a non-zero exit status, indicating failure, if any " + "errors or warnings are encountered (including docstring " + "warnings).") # Add the option groups. optparser.add_option_group(action_group) optparser.add_option_group(generation_group) optparser.add_option_group(output_group) optparser.add_option_group(graph_group) + optparser.add_option_group(return_group) # Set the option parser's defaults. optparser.set_defaults(action="html", show_frames=True, @@ -269,7 +288,7 @@ graphs=[], list_classes_separately=False, graph_font=None, graph_font_size=None, include_source_code=True, pstat_files=[], - simple_term=False) + simple_term=False, fail_on=None) # Parse the arguments. options, names = optparser.parse_args() @@ -417,6 +436,17 @@ options.pstat_files.extend(val.replace(',', ' ').split()) elif optname in ('simple-term', 'simple_term'): options.simple_term = _str_to_bool(val, optname) + elif optname in ('failon', 'fail-on', 'fail_on'): + if val.lower.strip() in ('error', 'errors'): + options.fail_on = log.ERROR + elif val.lower.strip() in ('warning', 'warnings'): + options.fail_on = log.WARNING + elif val.lower.strip() in ('docstring_warning', + 'docstring_warnings'): + options.fail_on = log.DOCSTRING_WARNING + else: + raise ValueError("%r expected one of: error, warning, " + "docstring_warning" % optname) else: raise ValueError('Unknown option %s' % optname) @@ -482,7 +512,8 @@ if options.action not in ('text', 'check', 'pickle'): if os.path.exists(options.target): if not os.path.isdir(options.target): - return log.error("%s is not a directory" % options.target) + log.error("%s is not a directory" % options.target) + sys.exit(1) # Set the default docformat from epydoc import docstringparser @@ -526,7 +557,10 @@ exclude_parse=options.exclude_parse) if docindex is None: - return # docbuilder already logged an error. + if log.ERROR in logger.reported_message_levels: + sys.exit(1) + else: + return # docbuilder already logged an error. # Load profile information, if it was given. if options.pstat_files: @@ -572,6 +606,13 @@ if options.verbosity >= 2 and logger is not None: logger.print_times() + # If we encountered any message types that we were requested to + # fail on, then exit with status 1. + if options.fail_on is not None: + max_reported_message_level = max(logger.reported_message_levels) + if max_reported_message_level >= options.fail_on: + sys.exit(1) + def write_html(docindex, options): from epydoc.docwriter.html import HTMLWriter html_writer = HTMLWriter(docindex, **options.__dict__) @@ -721,6 +762,8 @@ _profile() else: main(options, names) + except SystemExit: + raise except KeyboardInterrupt: print '\n\n' print >>sys.stderr, 'Keyboard interrupt.' @@ -733,7 +776,7 @@ print >>sys.stderr, ('\nUNEXPECTED ERROR:\n' '%s\n' % (str(e) or e.__class__.__name__)) print >>sys.stderr, 'Use --debug to see trace information.' - + def _profile(): # Hotshot profiler. if PROFILER == 'hotshot': @@ -867,6 +910,11 @@ # For per-task times: self._task_times = [] self._progress_header = None + + self.reported_message_levels = set() + """This set contains all the message levels (WARNING, ERROR, + etc) that have been reported. It is used by the options + --fail-on-warning etc to determine the return value.""" self.supressed_docstring_warning = 0 """This variable will be incremented once every time a @@ -932,6 +980,7 @@ return color+prefix+self.term.NORMAL+''.join(lines) def log(self, level, message): + self.reported_message_levels.add(level) if self._verbosity >= -2 and level >= log.ERROR: message = self._format(' Error: ', message, self.term.RED) elif self._verbosity >= -1 and level >= log.WARNING: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 16:02:12
|
Revision: 1461 http://svn.sourceforge.net/epydoc/?rev=1461&view=rev Author: edloper Date: 2007-02-11 08:02:10 -0800 (Sun, 11 Feb 2007) Log Message: ----------- - Added --simple-term option, which tells epydoc not to use any color or cursor control, even if the terminal appears to support it. Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2007-02-11 06:07:27 UTC (rev 1460) +++ trunk/epydoc/src/epydoc/cli.py 2007-02-11 16:02:10 UTC (rev 1461) @@ -106,6 +106,10 @@ optparser.add_option( # --debug "--debug", action="store_true", dest="debug", help="Show full tracebacks for internal errors.") + optparser.add_option( + "--simple-term", action="store_true", dest="simple_term", + help="Do not try to use color or cursor control when displaying " + "the progress bar, warnings, or errors.") # Add options -- Actions action_group.add_option( # --html @@ -264,7 +268,8 @@ debug=epydoc.DEBUG, profile=False, graphs=[], list_classes_separately=False, graph_font=None, graph_font_size=None, - include_source_code=True, pstat_files=[]) + include_source_code=True, pstat_files=[], + simple_term=False) # Parse the arguments. options, names = optparser.parse_args() @@ -410,6 +415,8 @@ options.include_source_code = _str_to_bool(val, optname) elif optname == 'pstat': options.pstat_files.extend(val.replace(',', ' ').split()) + elif optname in ('simple-term', 'simple_term'): + options.simple_term = _str_to_bool(val, optname) else: raise ValueError('Unknown option %s' % optname) @@ -436,6 +443,8 @@ # options.parse = False # Set up the logger + if options.simple_term: + TerminalController.FORCE_SIMPLE_TERM = True if options.action == 'text': logger = None # no logger for text output. elif options.verbosity > 1: @@ -797,9 +806,15 @@ _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split() _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split() + #: If this is set to true, then new TerminalControllers will + #: assume that the terminal is not capable of doing manipulation + #: of any kind. + FORCE_SIMPLE_TERM = False + def __init__(self, term_stream=sys.stdout): # If the stream isn't a tty, then assume it has no capabilities. if not term_stream.isatty(): return + if self.FORCE_SIMPLE_TERM: return # Curses isn't available on all platforms try: import curses @@ -843,7 +858,7 @@ return re.sub(r'\$<\d+>[/*]?', '', cap) class ConsoleLogger(log.Logger): - def __init__(self, verbosity): + def __init__(self, verbosity, progress_mode=None): self._verbosity = verbosity self._progress = None self._message_blocks = [] @@ -863,9 +878,11 @@ # Set the progress bar mode. if verbosity >= 2: self._progress_mode = 'list' elif verbosity >= 0: - if self.term.COLS < 15: + if progress_mode is not None: + self._progress_mode = progress_mode + elif self.term.COLS < 15: self._progress_mode = 'simple-bar' - if self.term.BOL and self.term.CLEAR_EOL and self.term.UP: + elif self.term.BOL and self.term.CLEAR_EOL and self.term.UP: self._progress_mode = 'multiline-bar' elif self.term.BOL and self.term.CLEAR_LINE: self._progress_mode = 'bar' @@ -1062,11 +1079,11 @@ print class UnifiedProgressConsoleLogger(ConsoleLogger): - def __init__(self, verbosity, stages): + def __init__(self, verbosity, stages, progress_mode=None): self.stage = 0 self.stages = stages self.task = None - ConsoleLogger.__init__(self, verbosity) + ConsoleLogger.__init__(self, verbosity, progress_mode) def progress(self, percent, message=''): #p = float(self.stage-1+percent)/self.stages This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 06:07:28
|
Revision: 1460 http://svn.sourceforge.net/epydoc/?rev=1460&view=rev Author: edloper Date: 2007-02-10 22:07:27 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Fixed SF bug 1562530, which causes nested literal braces to not get parsed correctly. Modified Paths: -------------- trunk/epydoc/src/epydoc/markup/epytext.py trunk/epydoc/src/epydoc/test/epytext.doctest Modified: trunk/epydoc/src/epydoc/markup/epytext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/epytext.py 2007-02-11 05:52:55 UTC (rev 1459) +++ trunk/epydoc/src/epydoc/markup/epytext.py 2007-02-11 06:07:27 UTC (rev 1460) @@ -1064,7 +1064,7 @@ # Special handling for literal braces elements: if stack[-1].tag == 'litbrace': - stack[-2].children = ['{'] + stack[-1].children + ['}'] + stack[-2].children[-1:] = ['{'] + stack[-1].children + ['}'] # Special handling for graphs: if stack[-1].tag == 'graph': Modified: trunk/epydoc/src/epydoc/test/epytext.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/epytext.doctest 2007-02-11 05:52:55 UTC (rev 1459) +++ trunk/epydoc/src/epydoc/test/epytext.doctest 2007-02-11 06:07:27 UTC (rev 1460) @@ -282,3 +282,27 @@ ... This is detached ... """) ('Other lines without period...', True) + +Literal Braces +============== +SF bug #1562530 reported some trouble with literal braces. These +tests make sure that braces are getting rendered as desired. + +>>> def epytext2html(s): +... errs = [] +... v = epytext.parse_docstring(s, errs).to_html(None) +... for err in errs: print err +... return (v or '').rstrip() + +>>> print epytext2html("{1:{2:3}}") + {1:{2:3}} +>>> print epytext2html("C{{1:{2:3}}}") +<code>{1:{2:3}}</code> +>>> print epytext2html("{1:C{{2:3}}}") +{1:<code>{2:3}</code>} +>>> print epytext2html("{{{}{}}{}}") + {{{}{}}{}} +>>> print epytext2html("{{E{lb}E{lb}E{lb}}}") + {{{{{}} + + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 05:52:57
|
Revision: 1459 http://svn.sourceforge.net/epydoc/?rev=1459&view=rev Author: edloper Date: 2007-02-10 21:52:55 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Explicitly specify that the stylesheet should be linked (not embedded). Modified Paths: -------------- trunk/epydoc/src/tools/rst2html.py Modified: trunk/epydoc/src/tools/rst2html.py =================================================================== --- trunk/epydoc/src/tools/rst2html.py 2007-02-11 05:52:27 UTC (rev 1458) +++ trunk/epydoc/src/tools/rst2html.py 2007-02-11 05:52:55 UTC (rev 1459) @@ -23,6 +23,7 @@ 'stylesheet_path': None, 'output_encoding': 'ascii', 'output_encoding_error_handler': 'xmlcharrefreplace', + 'embed_stylesheet': False, }) def __init__(self): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 05:52:31
|
Revision: 1458 http://svn.sourceforge.net/epydoc/?rev=1458&view=rev Author: edloper Date: 2007-02-10 21:52:27 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Replaced implementation of doctest-html target with a more makefile-like one (the old one use a shell script; and in the comments for SF bug #1655963, someone indicated that it wasn't working for them.) Modified Paths: -------------- trunk/epydoc/Makefile Modified: trunk/epydoc/Makefile =================================================================== --- trunk/epydoc/Makefile 2007-02-11 05:46:59 UTC (rev 1457) +++ trunk/epydoc/Makefile 2007-02-11 05:52:27 UTC (rev 1458) @@ -136,17 +136,14 @@ --name "Epydoc $(VERSION)" $(PY_SRC) -v --debug touch .api-pdf.up2date -doctest-html: .doctest-html.up2date -.doctest-html.up2date: $(DOCTESTS) - rm -rf $(HTML_DOCTEST) +# Convert doctest files to HTML, using rst2html. +DOCTEST_HTML_FILES := \ + $(DOCTESTS:src/epydoc/test/%.doctest=$(HTML_DOCTEST)/%.html) +doctest-html: doctest-html-mkdir $(DOCTEST_HTML_FILES) +doctest-html-mkdir: mkdir -p $(HTML_DOCTEST) - for doctest in $(DOCTESTS); do \ - out_file=$(HTML_DOCTEST)/`basename $$doctest .doctest`.html; \ - echo "$(RST2HTML) $$doctest $$out_file"; \ - if $(RST2HTML) $$doctest $$out_file; then true; \ - else exit 1; fi\ - done - touch .doctest-html.up2date +$(HTML_DOCTEST)/%.html: src/epydoc/test/%.doctest + $(RST2HTML) $< $@ examples: .examples.up2date .examples.up2date: $(EXAMPLES_SRC) $(PY_SRCFILES) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 05:47:00
|
Revision: 1457 http://svn.sourceforge.net/epydoc/?rev=1457&view=rev Author: edloper Date: 2007-02-10 21:46:59 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Fixed minor markup error Modified Paths: -------------- trunk/epydoc/src/epydoc/test/docbuilder.doctest Modified: trunk/epydoc/src/epydoc/test/docbuilder.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/docbuilder.doctest 2007-02-11 05:28:16 UTC (rev 1456) +++ trunk/epydoc/src/epydoc/test/docbuilder.doctest 2007-02-11 05:46:59 UTC (rev 1457) @@ -155,6 +155,7 @@ Exceptions can be put in the docstring class, and they are assigned to the constructor too. + >>> runbuilder(s=''' ... class Foo: ... """Foo(x, y) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 05:28:17
|
Revision: 1456 http://svn.sourceforge.net/epydoc/?rev=1456&view=rev Author: edloper Date: 2007-02-10 21:28:16 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Moved various test functions from doctest files (eg, runbuilder, runparser, etc) to a single epydoc.test.util module, so they can be shared between different doctest files. (E.g., the restructuredtext.doctest file needed to make use of the runbuilder function defined in docbuilder.doctest). - Moved all tests that depend on docutils to restructuredtext.doctest - Marked restructuredtext.doctest as requiring the docutils module Modified Paths: -------------- trunk/epydoc/src/epydoc/test/docbuilder.doctest trunk/epydoc/src/epydoc/test/docintrospecter.doctest trunk/epydoc/src/epydoc/test/docparser.doctest trunk/epydoc/src/epydoc/test/encoding.doctest trunk/epydoc/src/epydoc/test/restructuredtext.doctest Modified: trunk/epydoc/src/epydoc/test/docbuilder.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/docbuilder.doctest 2007-02-11 05:25:21 UTC (rev 1455) +++ trunk/epydoc/src/epydoc/test/docbuilder.doctest 2007-02-11 05:28:16 UTC (rev 1456) @@ -12,130 +12,38 @@ name of a variable in the module whose documentation should be built, instead of bilding docs for the whole module. - >>> import tempfile, re, os, os.path, textwrap, sys - >>> from epydoc.docbuilder import build_doc - >>> from epydoc.apidoc import ClassDoc, RoutineDoc - >>> from epydoc.markup import ParsedDocstring + >>> from epydoc.test.util import runbuilder - >>> def to_plain(docstring): - ... """Conver a parsed docstring into plain text""" - ... if isinstance(docstring, ParsedDocstring): - ... docstring = docstring.to_plaintext(None) - ... return docstring.rsplit() - - >>> def fun_to_plain(val_doc): - ... """Convert parsed docstrings in text from a RoutineDoc""" - ... for k, v in val_doc.arg_types.items(): - ... val_doc.arg_types[k] = to_plain(v) - ... for i, (k, v) in enumerate(val_doc.arg_descrs): - ... val_doc.arg_descrs[i] = (k, to_plain(v)) - - >>> def runbuilder(s, attribs='', build=None, exclude=''): - ... # Write it to a temp file. - ... tmp_dir = tempfile.mkdtemp() - ... out = open(os.path.join(tmp_dir, 'epydoc_test.py'), 'w') - ... out.write(textwrap.dedent(s)) - ... out.close() - ... # Build it. - ... val_doc = build_doc(os.path.join(tmp_dir, 'epydoc_test.py')) - ... if build: val_doc = val_doc.variables[build].value - ... # Display it. - ... if isinstance(val_doc, ClassDoc): - ... for val in val_doc.variables.values(): - ... if isinstance(val.value, RoutineDoc): - ... fun_to_plain(val.value) - ... s = val_doc.pp(include=attribs.split(),exclude=exclude.split()) - ... s = re.sub(r"(filename = ).*", r"\1...", s) - ... s = re.sub(r"(<module 'epydoc_test' from ).*", r'\1...', s) - ... s = re.sub(r"(<function \w+ at )0x\w+>", r"\1...>", s) - ... s = re.sub(r"(<\w+ object at )0x\w+>", r"\1...>", s) - ... print s - ... # Clean up. - ... os.unlink(os.path.join(tmp_dir, 'epydoc_test.py')) - ... try: os.unlink(os.path.join(tmp_dir, 'epydoc_test.pyc')) - ... except OSError: pass - ... os.rmdir(tmp_dir) - ... del sys.modules['epydoc_test'] - Docformat selection =================== The docstrings format can be selected using the ``__docformat__`` module -variable. +variable. In the second example below, where docformat='plaintext', +the string "@ivar x: ..." will not be treated as a field, since the +docstring format is plaintext. >>> runbuilder(s=''' - ... __docformat__ = 'restructuredtext' - ... + ... __docformat__ = 'epytext' ... class Foo: - ... """Testing defining_module - ... - ... :cvar `c`: class var in class docstring - ... :type `c`: str - ... """ - ... c = 'abc' - ... - ... def __init__(self): - ... #: A funny number - ... #: - ... #: :type: float - ... self.x = 108.0 - ... - ... y = property( - ... fget=lambda self: 42, - ... doc="""A property has no defining module - ... - ... :type: int - ... """) - ... - ... def f(self): - ... """A function has a defining module - ... - ... :rtype: int - ... """ - ... return 42 + ... """@ivar x: description...""" ... ''', - ... build='Foo', - ... attribs="variables name value type_descr return_type descr") + ... build='Foo', attribs='descr variables') ClassDoc for epydoc_test.Foo [0] - +- descr = u'Testing defining_module' + +- descr = None +- variables - +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] - | +- descr = None - | +- name = '__init__' - | +- type_descr = None - | +- value - | +- RoutineDoc for epydoc_test.Foo.__init__ [2] - | +- descr = None - | +- return_type = None - +- c => VariableDoc for epydoc_test.Foo.c [3] - | +- descr = u'class var in class docstring' - | +- name = 'c' - | +- type_descr = u'str' - | +- value - | +- GenericValueDoc [4] - | +- descr = None - +- f => VariableDoc for epydoc_test.Foo.f [5] - | +- descr = None - | +- name = 'f' - | +- type_descr = None - | +- value - | +- RoutineDoc for epydoc_test.Foo.f [6] - | +- descr = u'A function has a defining module' - | +- return_type = u'int' - +- x => VariableDoc for epydoc_test.Foo.x [7] - | +- descr = u'A funny number' - | +- name = u'x' - | +- type_descr = u'float' - | +- value = <UNKNOWN> - +- y => VariableDoc for epydoc_test.Foo.y [8] - +- descr = None - +- name = 'y' - +- type_descr = None - +- value - +- PropertyDoc for epydoc_test.Foo.y [9] - +- descr = u'A property has no defining module' - +- type_descr = u'int' + +- x => VariableDoc for epydoc_test.Foo.x [1] + +- descr = u'description...\n\n' + >>> runbuilder(s=''' + ... __docformat__ = 'plaintext' + ... class Foo: + ... """@var x: description...""" + ... ''', + ... build='Foo', attribs='descr variables') + ClassDoc for epydoc_test.Foo [0] + +- descr = u'@var x: description...\n' + +- variables = {} + Stuff from future doesn't appear as variable. >>> runbuilder(s=""" @@ -381,45 +289,3 @@ +- type_descr = u'date\n\n' +- value = <UNKNOWN> -Also reST consolidated fields are not a problem. - - >>> runbuilder(s=''' - ... __docformat__ = 'restructuredtext' - ... class Foo: - ... """This is the object docstring - ... - ... :Parameters: - ... `a` : string - ... init param. - ... - ... :Exceptions: - ... * `ValueError`: frobnication error - ... init param. - ... - ... :IVariables: - ... `a` : date - ... instance var. - ... """ - ... def __init__(self, a): - ... pass - ... ''', - ... build="Foo", - ... attribs="variables name value exception_descrs " - ... "posargs vararg kwarg type_descr arg_types arg_descrs") - ClassDoc for epydoc_test.Foo [0] - +- variables - +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] - | +- name = '__init__' - | +- type_descr = None - | +- value - | +- RoutineDoc for epydoc_test.Foo.__init__ [2] - | +- arg_descrs = [([u'a'], [u'init', u'param.'])] - | +- arg_types = {u'a': [u'string']} - | +- exception_descrs = [(DottedName(u'ValueError'), ... - | +- kwarg = None - | +- posargs = ['self', 'a'] - | +- vararg = None - +- a => VariableDoc for epydoc_test.Foo.a [3] - +- name = u'a' - +- type_descr = u'date' - +- value = <UNKNOWN> Modified: trunk/epydoc/src/epydoc/test/docintrospecter.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/docintrospecter.doctest 2007-02-11 05:25:21 UTC (rev 1455) +++ trunk/epydoc/src/epydoc/test/docintrospecter.doctest 2007-02-11 05:28:16 UTC (rev 1456) @@ -15,36 +15,7 @@ name of a variable in the module whose value should be introspected, instead of introspecting the whole module. - >>> import tempfile, re, os, os.path, textwrap, sys - >>> from epydoc.docintrospecter import introspect_docs - >>> def runintrospecter(s, attribs='', introspect=None, exclude=''): - ... # Write it to a temp file. - ... tmp_dir = tempfile.mkdtemp() - ... out = open(os.path.join(tmp_dir, 'epydoc_test.py'), 'w') - ... out.write(textwrap.dedent(s)) - ... out.close() - ... # Import it. - ... sys.path.insert(0, tmp_dir) - ... if introspect is None: - ... import epydoc_test as val - ... else: - ... exec("from epydoc_test import %s as val" % introspect) - ... del sys.path[0] - ... # Introspect it. - ... val_doc = introspect_docs(val) - ... # Display it. - ... s = val_doc.pp(include=attribs.split(),exclude=exclude.split()) - ... s = re.sub(r"(filename = ).*", r"\1...", s) - ... s = re.sub(r"(<module 'epydoc_test' from ).*", r'\1...', s) - ... s = re.sub(r"(<function \w+ at )0x\w+>", r"\1...>", s) - ... s = re.sub(r"(<\w+ object at )0x\w+>", r"\1...>", s) - ... print s - ... # Clean up. - ... os.unlink(os.path.join(tmp_dir, 'epydoc_test.py')) - ... try: os.unlink(os.path.join(tmp_dir, 'epydoc_test.pyc')) - ... except OSError: pass - ... os.rmdir(tmp_dir) - ... del sys.modules['epydoc_test'] + >>> from epydoc.test.util import runintrospecter Module Variables ================ Modified: trunk/epydoc/src/epydoc/test/docparser.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/docparser.doctest 2007-02-11 05:25:21 UTC (rev 1455) +++ trunk/epydoc/src/epydoc/test/docparser.doctest 2007-02-11 05:28:16 UTC (rev 1456) @@ -15,30 +15,7 @@ module that should be displayed (but the whole module will always be inspected; this just selects what to display). - >>> import tempfile, re, os, os.path, textwrap - >>> from epydoc.apidoc import ClassDoc - >>> from epydoc.docparser import parse_docs - >>> def runparser(s, attribs='', show=None, exclude=''): - ... # Write it to a temp file. - ... tmp_dir = tempfile.mkdtemp() - ... out = open(os.path.join(tmp_dir, 'test.py'), 'w') - ... out.write(textwrap.dedent(s)) - ... out.close() - ... # Parse it. - ... val_doc = parse_docs(out.name) - ... if show is not None: - ... for name in show.split('.'): - ... if isinstance(val_doc, ClassDoc): - ... val_doc = val_doc.local_variables[name].value - ... else: - ... val_doc = val_doc.variables[name].value - ... # Display it. - ... s = val_doc.pp(include=attribs.split(), exclude=exclude.split()) - ... s = re.sub(r"filename = .*", "filename = ...", s) - ... print s - ... # Clean up. - ... os.unlink(os.path.join(tmp_dir, 'test.py')) - ... os.rmdir(tmp_dir) + >>> from epydoc.test.util import runparser Module Variables from Assignment Statements =========================================== Modified: trunk/epydoc/src/epydoc/test/encoding.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/encoding.doctest 2007-02-11 05:25:21 UTC (rev 1455) +++ trunk/epydoc/src/epydoc/test/encoding.doctest 2007-02-11 05:28:16 UTC (rev 1456) @@ -2,7 +2,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Test Function ============= -The following function is used as an end-to-end test for unicode +The function `testencoding` is used as an end-to-end test for unicode encodings. It takes a given string, writes it to a python file, and processes that file's documentation. It then generates HTML output from the documentation, extracts all docstrings from the generated @@ -10,59 +10,9 @@ docstrings, it monkey-patches the HMTLwriter.docstring_to_html() method.) - >>> # Display warninings & errors: - >>> from epydoc import log - >>> log.register_logger(log.SimpleLogger()) + >>> from epydoc.test.util import print_warnings, testencoding + >>> print_warnings() - >>> # Other imports: - >>> import tempfile, os, re, textwrap, sys - >>> from epydoc.docbuilder import build_doc_index - >>> from epydoc.docwriter.html import HTMLWriter - - >>> # Monkey-patch the write function: - >>> def docstring_to_html(self, parsed_docstring, w=None, i=0): - ... s = parsed_docstring.to_html(None).strip() - ... s = s.encode('ascii', 'xmlcharrefreplace') - ... s = remove_surrogates(s) - ... print s - ... return '' - >>> HTMLWriter.docstring_to_html = docstring_to_html - - >>> # The actual test function: - >>> def test(s, introspect=True, parse=True, debug=False): - ... # Write s to a temporary file. - ... tmp_dir = tempfile.mkdtemp() - ... path = os.path.join(tmp_dir, 'enc_test.py') - ... out = open(path, 'w') - ... out.write(textwrap.dedent(s)) - ... out.close() - ... # Build docs for it - ... docindex = build_doc_index([path], introspect, parse) - ... if docindex is None: return - ... try: del sys.modules['enc_test'] - ... except: pass - ... # Write html output. - ... writer = HTMLWriter(docindex, mark_docstrings=True) - ... writer.write(tmp_dir) - ... for file in os.listdir(tmp_dir): - ... os.unlink(os.path.join(tmp_dir,file)) - ... os.rmdir(tmp_dir) - -The following is a helper function, used to convert two-character -surrogate sequences into single characters. This is needed because -some systems create surrogates but others don't. - - >>> def remove_surrogates(s): - ... pieces = re.split('(&#\d+;)', s) - ... for i in range(3, len(pieces)-1, 2): - ... if pieces[i-1] != '': continue - ... high,low = int(pieces[i-2][2:-1]), int(pieces[i][2:-1]) - ... if 0xd800 <= high <= 0xdbff and 0xdc00 <= low <= 0xdfff: - ... pieces[i-2] = '&#%d;' % (((high&0x3ff)<<10) + - ... (low&0x3ff) + 0x10000) - ... pieces[i] = '' - ... return ''.join(pieces) - Encoding Tests ============== This section tests the output for a variety of different encodings. @@ -72,27 +22,27 @@ Tests for several Microsoft codepges: - >>> test('''# -*- coding: cp874 -*- + >>> testencoding('''# -*- coding: cp874 -*- ... """abc ABC 123 \x80 \x85""" ... ''') abc ABC 123 € … - >>> test('''# -*- coding: cp1250 -*- + >>> testencoding('''# -*- coding: cp1250 -*- ... """abc ABC 123 \x80 \x82 \x84 \x85 \xff""" ... ''') abc ABC 123 € ‚ „ … ˙ - >>> test('''# -*- coding: cp1251 -*- + >>> testencoding('''# -*- coding: cp1251 -*- ... """abc ABC 123 \x80 \x81 \x82 \xff""" ... ''') abc ABC 123 Ђ Ѓ ‚ я - >>> test('''# -*- coding: cp1252 -*- + >>> testencoding('''# -*- coding: cp1252 -*- ... """abc ABC 123 \x80 \x82 \x83 \xff""" ... ''') abc ABC 123 € ‚ ƒ ÿ - >>> test('''# -*- coding: cp1253 -*- + >>> testencoding('''# -*- coding: cp1253 -*- ... """abc ABC 123 \x80 \x82 \x83 \xfe""" ... ''') abc ABC 123 € ‚ ƒ ώ @@ -115,21 +65,21 @@ >>> utf8_bom = '\xef\xbb\xbf' >>> # UTF-8 with a coding directive: - >>> test("# -*- coding: utf-8 -*-\n"+utf8_test) + >>> testencoding("# -*- coding: utf-8 -*-\n"+utf8_test) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> 0x10000-0x10ffff range: 𐀀 𐀁   >>> # UTF-8 with a BOM & a coding directive: - >>> test(utf8_bom+"# -*- coding: utf-8 -*-\n"+utf8_test) + >>> testencoding(utf8_bom+"# -*- coding: utf-8 -*-\n"+utf8_test) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> 0x10000-0x10ffff range: 𐀀 𐀁   >>> # UTF-8 with a BOM & no coding directive: - >>> test(utf8_bom+utf8_test) + >>> testencoding(utf8_bom+utf8_test) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> @@ -137,30 +87,30 @@ Tests for KOI8-R: - >>> test('''# -*- coding: koi8-r -*- + >>> testencoding('''# -*- coding: koi8-r -*- ... """abc ABC 123 \x80 \x82 \x83 \xff""" ... ''') abc ABC 123 ─ ┌ ┐ Ъ Tests for 'coding' directive on the second line: - >>> test('''\n# -*- coding: cp1252 -*- + >>> testencoding('''\n# -*- coding: cp1252 -*- ... """abc ABC 123 \x80 \x82 \x83 \xff""" ... ''') abc ABC 123 € ‚ ƒ ÿ - >>> test('''# comment on the first line.\n# -*- coding: cp1252 -*- + >>> testencoding('''# comment on the first line.\n# -*- coding: cp1252 -*- ... """abc ABC 123 \x80 \x82 \x83 \xff""" ... ''') abc ABC 123 € ‚ ƒ ÿ - >>> test("\n# -*- coding: utf-8 -*-\n"+utf8_test) + >>> testencoding("\n# -*- coding: utf-8 -*-\n"+utf8_test) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> 0x10000-0x10ffff range: 𐀀 𐀁   - >>> test("# comment\n# -*- coding: utf-8 -*-\n"+utf8_test) + >>> testencoding("# comment\n# -*- coding: utf-8 -*-\n"+utf8_test) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> @@ -168,7 +118,7 @@ Tests for shift-jis - >>> test('''# -*- coding: shift_jis -*- + >>> testencoding('''# -*- coding: shift_jis -*- ... """abc ABC 123 \xA1 \xA2 \xA3""" ... ''') abc ABC 123 。 「 」 @@ -177,12 +127,12 @@ ================ Make sure that we use the coding for both str and unicode docstrings. - >>> test('''# -*- coding: utf-8 -*- + >>> testencoding('''# -*- coding: utf-8 -*- ... """abc ABC 123 \xc2\x80 \xdf\xbf \xe0\xa0\x80""" ... ''') abc ABC 123 € ߿ ࠀ - >>> test('''# -*- coding: utf-8 -*- + >>> testencoding('''# -*- coding: utf-8 -*- ... u"""abc ABC 123 \xc2\x80 \xdf\xbf \xe0\xa0\x80""" ... ''') abc ABC 123 € ߿ ࠀ @@ -199,7 +149,7 @@ as latin-1. An example of this is a non-unicode docstring for properties: - >>> test('''# -*- coding: utf-8 -*- + >>> testencoding('''# -*- coding: utf-8 -*- ... p=property(doc="""\xc2\x80""") ... ''') # doctest: +ELLIPSIS <property object at ...>'s docstring is not a unicode string, but it contains non-ascii data -- treating it as latin-1. @@ -210,33 +160,33 @@ This section checks to make sure that both introspection & parsing are getting the right results. - >>> test("# -*- coding: utf-8 -*-\n"+utf8_test, introspect=False) + >>> testencoding("# -*- coding: utf-8 -*-\n"+utf8_test, introspect=False) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> 0x10000-0x10ffff range: 𐀀 𐀁   - >>> test(utf8_bom+"# -*- coding: utf-8 -*-\n"+utf8_test, introspect=False) + >>> testencoding(utf8_bom+"# -*- coding: utf-8 -*-\n"+utf8_test, introspect=False) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> 0x10000-0x10ffff range: 𐀀 𐀁   - >>> test(utf8_bom+utf8_test, introspect=False) + >>> testencoding(utf8_bom+utf8_test, introspect=False) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> 0x10000-0x10ffff range: 𐀀 𐀁   - >>> test("# -*- coding: utf-8 -*-\n"+utf8_test, parse=False) + >>> testencoding("# -*- coding: utf-8 -*-\n"+utf8_test, parse=False) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> 0x10000-0x10ffff range: 𐀀 𐀁   - >>> test(utf8_bom+"# -*- coding: utf-8 -*-\n"+utf8_test, parse=False) + >>> testencoding(utf8_bom+"# -*- coding: utf-8 -*-\n"+utf8_test, parse=False) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> 0x10000-0x10ffff range: 𐀀 𐀁   - >>> test(utf8_bom+utf8_test, parse=False) + >>> testencoding(utf8_bom+utf8_test, parse=False) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> @@ -246,7 +196,7 @@ ============== Make sure that docstrings are rendered correctly in different contexts. - >>> test('''# -*- coding: utf-8 -*- + >>> testencoding('''# -*- coding: utf-8 -*- ... """ ... @var x: abc ABC 123 \xc2\x80 \xdf\xbf \xe0\xa0\x80 ... @group \xc2\x80: x @@ -254,7 +204,7 @@ ... ''') abc ABC 123 € ߿ ࠀ - >>> test('''# -*- coding: utf-8 -*- + >>> testencoding('''# -*- coding: utf-8 -*- ... def f(x): ... """ ... abc ABC 123 \xc2\x80 \xdf\xbf \xe0\xa0\x80 @@ -274,7 +224,7 @@ abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ - >>> test('''# -*- coding: utf-8 -*- + >>> testencoding('''# -*- coding: utf-8 -*- ... class A: ... """ ... abc ABC 123 \xc2\x80 \xdf\xbf \xe0\xa0\x80 Modified: trunk/epydoc/src/epydoc/test/restructuredtext.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/restructuredtext.doctest 2007-02-11 05:25:21 UTC (rev 1455) +++ trunk/epydoc/src/epydoc/test/restructuredtext.doctest 2007-02-11 05:28:16 UTC (rev 1456) @@ -1,5 +1,6 @@ -Regression Testing for plaintext -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Regression Testing for restructuredtext +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:RequireModule: docutils Summary ======= @@ -108,3 +109,125 @@ <span class="py-keyword">def</span> <span class="py-defname">__init__</span>(self): <span class="py-keyword">pass</span></pre> <BLANKLINE> + +Consolidated Fields +=================== + + >>> from epydoc.test.util import runbuilder + + >>> runbuilder(s=''' + ... __docformat__ = 'restructuredtext' + ... class Foo: + ... """This is the object docstring + ... + ... :Parameters: + ... `a` : string + ... init param. + ... + ... :Exceptions: + ... * `ValueError`: frobnication error + ... init param. + ... + ... :IVariables: + ... `a` : date + ... instance var. + ... """ + ... def __init__(self, a): + ... pass + ... ''', + ... build="Foo", + ... attribs="variables name value exception_descrs " + ... "posargs vararg kwarg type_descr arg_types arg_descrs") + ClassDoc for epydoc_test.Foo [0] + +- variables + +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] + | +- name = '__init__' + | +- type_descr = None + | +- value + | +- RoutineDoc for epydoc_test.Foo.__init__ [2] + | +- arg_descrs = [([u'a'], [u'init', u'param.'])] + | +- arg_types = {u'a': [u'string']} + | +- exception_descrs = [(DottedName(u'ValueError'), ... + | +- kwarg = None + | +- posargs = ['self', 'a'] + | +- vararg = None + +- a => VariableDoc for epydoc_test.Foo.a [3] + +- name = u'a' + +- type_descr = u'date' + +- value = <UNKNOWN> + +Misc rst constructs +=================== + + >>> runbuilder(s=''' + ... __docformat__ = 'restructuredtext' + ... + ... class Foo: + ... """Testing defining_module + ... + ... :cvar `c`: class var in class docstring + ... :type `c`: str + ... """ + ... c = 'abc' + ... + ... def __init__(self): + ... #: A funny number + ... #: + ... #: :type: float + ... self.x = 108.0 + ... + ... y = property( + ... fget=lambda self: 42, + ... doc="""A property has no defining module + ... + ... :type: int + ... """) + ... + ... def f(self): + ... """A function has a defining module + ... + ... :rtype: int + ... """ + ... return 42 + ... ''', + ... build='Foo', + ... attribs="variables name value type_descr return_type descr") + ClassDoc for epydoc_test.Foo [0] + +- descr = u'Testing defining_module' + +- variables + +- __init__ => VariableDoc for epydoc_test.Foo.__init__ [1] + | +- descr = None + | +- name = '__init__' + | +- type_descr = None + | +- value + | +- RoutineDoc for epydoc_test.Foo.__init__ [2] + | +- descr = None + | +- return_type = None + +- c => VariableDoc for epydoc_test.Foo.c [3] + | +- descr = u'class var in class docstring' + | +- name = 'c' + | +- type_descr = u'str' + | +- value + | +- GenericValueDoc [4] + | +- descr = None + +- f => VariableDoc for epydoc_test.Foo.f [5] + | +- descr = None + | +- name = 'f' + | +- type_descr = None + | +- value + | +- RoutineDoc for epydoc_test.Foo.f [6] + | +- descr = u'A function has a defining module' + | +- return_type = u'int' + +- x => VariableDoc for epydoc_test.Foo.x [7] + | +- descr = u'A funny number' + | +- name = u'x' + | +- type_descr = u'float' + | +- value = <UNKNOWN> + +- y => VariableDoc for epydoc_test.Foo.y [8] + +- descr = None + +- name = 'y' + +- type_descr = None + +- value + +- PropertyDoc for epydoc_test.Foo.y [9] + +- descr = u'A property has no defining module' + +- type_descr = u'int' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 05:25:30
|
Revision: 1455 http://svn.sourceforge.net/epydoc/?rev=1455&view=rev Author: edloper Date: 2007-02-10 21:25:21 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Added support for adding ':RequireModule:' fields to doctest test files, which assert that the tests shouldn't be run unless that module is available. Used by restructuredtext.doctest to prevent the tests from being run if the docutils module is not installed. Modified Paths: -------------- trunk/epydoc/src/epydoc/test/__init__.py Modified: trunk/epydoc/src/epydoc/test/__init__.py =================================================================== --- trunk/epydoc/src/epydoc/test/__init__.py 2007-02-11 05:22:31 UTC (rev 1454) +++ trunk/epydoc/src/epydoc/test/__init__.py 2007-02-11 05:25:21 UTC (rev 1455) @@ -11,7 +11,7 @@ """ __docformat__ = 'epytext en' -import unittest, doctest, epydoc, os, os.path +import unittest, doctest, epydoc, os, os.path, re def main(): # Turn on debugging. @@ -26,11 +26,35 @@ testdir = os.path.join(os.path.split(__file__)[0]) if testdir == '': testdir = '.' for filename in os.listdir(testdir): - if filename.endswith('.doctest'): + if (filename.endswith('.doctest') and + check_requirements(os.path.join(testdir, filename))): tests.append(doctest.DocFileSuite(filename, optionflags=options)) # Run all test cases. unittest.TextTestRunner(verbosity=2).run(unittest.TestSuite(tests)) +def check_requirements(filename): + """ + Search for strings of the form: + + [Require: <module>] + + If any are found, then try importing the module named <module>. + If the import fails, then return False. If all required modules + are found, return True. (This includes the case where no + requirements are listed.) + """ + s = open(filename).read() + for m in re.finditer('(?mi)^[ ]*\:RequireModule:[ ]+(\w+)[ ]*$', s): + module = m.group(1) + try: + __import__(module) + except ImportError: + print ('Skipping %r (required module %r not found)' % + (os.path.split(filename)[-1], module)) + return False + return True + + if __name__=='__main__': main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 05:22:32
|
Revision: 1454 http://svn.sourceforge.net/epydoc/?rev=1454&view=rev Author: edloper Date: 2007-02-10 21:22:31 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Moved various test functions from doctest files (eg, runbuilder, runparser, etc) to a single epydoc.test.util module, so they can be shared between different doctest files. (E.g., the restructuredtext.doctest file needed to make use of the runbuilder function defined in docbuilder.doctest). Added Paths: ----------- trunk/epydoc/src/epydoc/test/util.py Added: trunk/epydoc/src/epydoc/test/util.py =================================================================== --- trunk/epydoc/src/epydoc/test/util.py (rev 0) +++ trunk/epydoc/src/epydoc/test/util.py 2007-02-11 05:22:31 UTC (rev 1454) @@ -0,0 +1,218 @@ +# +# epydoc -- Utility functions used by regression tests (*.doctest) +# Edward Loper +# +# Created [01/30/01 05:18 PM] +# $Id: html.py 1420 2007-01-28 14:19:30Z dvarrazzo $ +# + +""" +Utility functions used by the regression tests (C{*.doctest}). +""" +__docformat__ = 'epytext en' + +import tempfile, re, os, os.path, textwrap, sys +from epydoc.docbuilder import build_doc, build_doc_index +from epydoc.docparser import parse_docs +from epydoc.docintrospecter import introspect_docs +from epydoc.apidoc import ClassDoc, RoutineDoc +from epydoc.markup import ParsedDocstring +from epydoc.docwriter.html import HTMLWriter + +###################################################################### +#{ Test Functions +###################################################################### + +def runbuilder(s, attribs='', build=None, exclude=''): + """ + This test function takes a string containing the contents of a + module. It writes the string contents to a file, imports the file + as a module, and uses build_doc to build documentation, and pretty + prints the resulting ModuleDoc object. The C{attribs} argument + specifies which attributes of the C{APIDoc}s should be displayed. + The C{build} argument gives the name of a variable in the module + whose documentation should be built, instead of bilding docs for + the whole module. + """ + # Write it to a temp file. + tmp_dir = tempfile.mkdtemp() + out = open(os.path.join(tmp_dir, 'epydoc_test.py'), 'w') + out.write(textwrap.dedent(s)) + out.close() + # Build it. + val_doc = build_doc(os.path.join(tmp_dir, 'epydoc_test.py')) + if build: val_doc = val_doc.variables[build].value + # Display it. + if isinstance(val_doc, ClassDoc): + for val in val_doc.variables.values(): + if isinstance(val.value, RoutineDoc): + fun_to_plain(val.value) + s = val_doc.pp(include=attribs.split(),exclude=exclude.split()) + s = re.sub(r"(filename = ).*", r"\1...", s) + s = re.sub(r"(<module 'epydoc_test' from ).*", r'\1...', s) + s = re.sub(r"(<function \w+ at )0x\w+>", r"\1...>", s) + s = re.sub(r"(<\w+ object at )0x\w+>", r"\1...>", s) + print s + # Clean up. + os.unlink(os.path.join(tmp_dir, 'epydoc_test.py')) + try: os.unlink(os.path.join(tmp_dir, 'epydoc_test.pyc')) + except OSError: pass + os.rmdir(tmp_dir) + del sys.modules['epydoc_test'] + +def runparser(s, attribs='', show=None, exclude=''): + """ + This test function takes a string containing the contents of a + module, and writes it to a file, uses `parse_docs` to parse it, + and pretty prints the resulting ModuleDoc object. The `attribs` + argument specifies which attributes of the `APIDoc`s should be + displayed. The `show` argument, if specifies, gives the name of + the object in the module that should be displayed (but the whole + module will always be inspected; this just selects what to + display). + """ + # Write it to a temp file. + tmp_dir = tempfile.mkdtemp() + out = open(os.path.join(tmp_dir, 'test.py'), 'w') + out.write(textwrap.dedent(s)) + out.close() + # Parse it. + val_doc = parse_docs(out.name) + if show is not None: + for name in show.split('.'): + if isinstance(val_doc, ClassDoc): + val_doc = val_doc.local_variables[name].value + else: + val_doc = val_doc.variables[name].value + # Display it. + s = val_doc.pp(include=attribs.split(), exclude=exclude.split()) + s = re.sub(r"filename = .*", "filename = ...", s) + print s + # Clean up. + os.unlink(os.path.join(tmp_dir, 'test.py')) + os.rmdir(tmp_dir) + +def runintrospecter(s, attribs='', introspect=None, exclude=''): + """ + This test function takes a string containing the contents of a + module. It writes the string contents to a file, imports the file + as a module, and uses C{introspect_docs} to introspect it, and + pretty prints the resulting ModuleDoc object. The C{attribs} + argument specifies which attributes of the C{APIDoc}s should be + displayed. The C{introspect} argument gives the name of a variable + in the module whose value should be introspected, instead of + introspecting the whole module. + """ + # Write it to a temp file. + tmp_dir = tempfile.mkdtemp() + out = open(os.path.join(tmp_dir, 'epydoc_test.py'), 'w') + out.write(textwrap.dedent(s)) + out.close() + # Import it. + sys.path.insert(0, tmp_dir) + if introspect is None: + import epydoc_test as val + else: + exec("from epydoc_test import %s as val" % introspect) + del sys.path[0] + # Introspect it. + val_doc = introspect_docs(val) + # Display it. + s = val_doc.pp(include=attribs.split(),exclude=exclude.split()) + s = re.sub(r"(filename = ).*", r"\1...", s) + s = re.sub(r"(<module 'epydoc_test' from ).*", r'\1...', s) + s = re.sub(r"(<function \w+ at )0x\w+>", r"\1...>", s) + s = re.sub(r"(<\w+ object at )0x\w+>", r"\1...>", s) + print s + # Clean up. + os.unlink(os.path.join(tmp_dir, 'epydoc_test.py')) + try: os.unlink(os.path.join(tmp_dir, 'epydoc_test.pyc')) + except OSError: pass + os.rmdir(tmp_dir) + del sys.modules['epydoc_test'] + +def print_warnings(): + """ + Register a logger that will print warnings & errors. + """ + from epydoc import log + log.register_logger(log.SimpleLogger()) + +def testencoding(s, introspect=True, parse=True, debug=False): + """ + An end-to-end test for unicode encodings. This function takes a + given string, writes it to a python file, and processes that + file's documentation. It then generates HTML output from the + documentation, extracts all docstrings from the generated HTML + output, and displays them. (In order to extract & display all + docstrings, it monkey-patches the HMTLwriter.docstring_to_html() + method.)""" + # Monkey-patch docstring_to_html + original_docstring_to_html = HTMLWriter.docstring_to_html + HTMLWriter.docstring_to_html = print_docstring_as_html + + # Write s to a temporary file. + tmp_dir = tempfile.mkdtemp() + path = os.path.join(tmp_dir, 'enc_test.py') + out = open(path, 'w') + out.write(textwrap.dedent(s)) + out.close() + # Build docs for it + docindex = build_doc_index([path], introspect, parse) + if docindex is None: return + try: del sys.modules['enc_test'] + except: pass + # Write html output. + writer = HTMLWriter(docindex, mark_docstrings=True) + writer.write(tmp_dir) + for file in os.listdir(tmp_dir): + os.unlink(os.path.join(tmp_dir,file)) + os.rmdir(tmp_dir) + + # Restore the HTMLWriter class to its original state. + HTMLWriter.docstring_to_html = original_docstring_to_html + +###################################################################### +#{ Helper Functions +###################################################################### + +def to_plain(docstring): + """Conver a parsed docstring into plain text""" + if isinstance(docstring, ParsedDocstring): + docstring = docstring.to_plaintext(None) + return docstring.rsplit() + +def fun_to_plain(val_doc): + """Convert parsed docstrings in text from a RoutineDoc""" + for k, v in val_doc.arg_types.items(): + val_doc.arg_types[k] = to_plain(v) + for i, (k, v) in enumerate(val_doc.arg_descrs): + val_doc.arg_descrs[i] = (k, to_plain(v)) + +def print_docstring_as_html(self, parsed_docstring, *varargs, **kwargs): + """ + Convert the given parsed_docstring to HTML and print it. Ignore + any other arguments. This function is used by L{testencoding} to + monkey-patch the HTMLWriter class's docstring_to_html() method. + """ + s = parsed_docstring.to_html(None).strip() + s = s.encode('ascii', 'xmlcharrefreplace') + s = remove_surrogates(s) + print s + return '' + +def remove_surrogates(s): + """ + The following is a helper function, used to convert two-character + surrogate sequences into single characters. This is needed + because some systems create surrogates but others don't. + """ + pieces = re.split('(&#\d+;)', s) + for i in range(3, len(pieces)-1, 2): + if pieces[i-1] != '': continue + high,low = int(pieces[i-2][2:-1]), int(pieces[i][2:-1]) + if 0xd800 <= high <= 0xdbff and 0xdc00 <= low <= 0xdfff: + pieces[i-2] = '&#%d;' % (((high&0x3ff)<<10) + + (low&0x3ff) + 0x10000) + pieces[i] = '' + return ''.join(pieces) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 04:44:42
|
Revision: 1452 http://svn.sourceforge.net/epydoc/?rev=1452&view=rev Author: edloper Date: 2007-02-10 20:23:35 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Acutally *use* the remove_surrogates helper function that's defined when printing output. (This is needed because some systems create surrogates but others don't.) Modified Paths: -------------- trunk/epydoc/src/epydoc/test/encoding.doctest Modified: trunk/epydoc/src/epydoc/test/encoding.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/encoding.doctest 2007-02-11 04:11:41 UTC (rev 1451) +++ trunk/epydoc/src/epydoc/test/encoding.doctest 2007-02-11 04:23:35 UTC (rev 1452) @@ -22,7 +22,9 @@ >>> # Monkey-patch the write function: >>> def docstring_to_html(self, parsed_docstring, w=None, i=0): ... s = parsed_docstring.to_html(None).strip() - ... print s.encode('ascii', 'xmlcharrefreplace') + ... s = s.encode('ascii', 'xmlcharrefreplace') + ... s = remove_surrogates(s) + ... print s ... return '' >>> HTMLWriter.docstring_to_html = docstring_to_html This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 04:34:54
|
Revision: 1453 http://svn.sourceforge.net/epydoc/?rev=1453&view=rev Author: edloper Date: 2007-02-10 20:34:52 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Changed the 'python' code directive to be implemented via a function rather than a class. Even though classes are the officially preferred mechanism for defining directives in docutils 0.5, they are not backwards compatible with docutils 0.3.7, which is still fairly widely used. The new version is compatible with docutils 0.3.7+. Modified Paths: -------------- trunk/epydoc/src/epydoc/markup/restructuredtext.py Modified: trunk/epydoc/src/epydoc/markup/restructuredtext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/restructuredtext.py 2007-02-11 04:23:35 UTC (rev 1452) +++ trunk/epydoc/src/epydoc/markup/restructuredtext.py 2007-02-11 04:34:52 UTC (rev 1453) @@ -77,7 +77,7 @@ from docutils.nodes import NodeVisitor, Text, SkipChildren from docutils.nodes import SkipNode, TreeCopyVisitor from docutils.frontend import OptionParser -from docutils.parsers.rst import directives, Directive +from docutils.parsers.rst import directives import docutils.nodes import docutils.transforms.frontmatter import docutils.transforms @@ -628,22 +628,29 @@ raise SkipNode() -class PythonCodeDirective(Directive): +def python_code_directive(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + """ + A custom restructuredtext directive which can be used to display + syntax-highlighted Python code blocks. This directive takes no + arguments, and the body should contain only Python code. This + directive can be used instead of doctest blocks when it is + inconvenient to list prompts on each line, or when you would + prefer that the output not contain prompts (e.g., to make + copy/paste easier). + """ required_arguments = 0 optional_arguments = 0 - has_content = True - def run(self): - self.assert_has_content() - text = '\n'.join(self.content) + text = '\n'.join(content) + node = docutils.nodes.doctest_block(text, text, codeblock=True) + return [ node ] + +python_code_directive.arguments = (0, 0, 0) +python_code_directive.content = True - #node = docutils.nodes.doctest_block(rawsource=text) - #self.state.nested_parse(self.content, self.content_offset, node) - node = docutils.nodes.doctest_block(text, text, codeblock=True) - return [ node ] +directives.register_directive('python', python_code_directive) -directives.register_directive('python', PythonCodeDirective) - ###################################################################### #{ Graph Generation Directives ###################################################################### This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 04:11:42
|
Revision: 1451 http://svn.sourceforge.net/epydoc/?rev=1451&view=rev Author: edloper Date: 2007-02-10 20:11:41 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Changed tests to use "pickle" as an example module rather than "re", since in Python <=2.4, re.match returned an object named 'sre.match', but in Python >=2.5, it is now named "re.match" (since the sre module was deprecated). This was causing tests to fail when run with Python 2.5. Modified Paths: -------------- trunk/epydoc/src/epydoc/test/docbuilder.doctest trunk/epydoc/src/epydoc/test/docintrospecter.doctest Modified: trunk/epydoc/src/epydoc/test/docbuilder.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/docbuilder.doctest 2007-02-11 04:04:28 UTC (rev 1450) +++ trunk/epydoc/src/epydoc/test/docbuilder.doctest 2007-02-11 04:11:41 UTC (rev 1451) @@ -140,14 +140,14 @@ >>> runbuilder(s=""" ... from __future__ import division - ... from re import match + ... from pickle import dump ... """, ... attribs='variables value') ModuleDoc for epydoc_test [0] +- variables - +- match => VariableDoc for epydoc_test.match [1] + +- dump => VariableDoc for epydoc_test.dump [1] +- value - +- ValueDoc for sre.match [2] + +- ValueDoc for pickle.dump [2] Specifying constructor signature in class docstring Modified: trunk/epydoc/src/epydoc/test/docintrospecter.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/docintrospecter.doctest 2007-02-11 04:04:28 UTC (rev 1450) +++ trunk/epydoc/src/epydoc/test/docintrospecter.doctest 2007-02-11 04:11:41 UTC (rev 1451) @@ -148,9 +148,9 @@ or not, so it sets `is_imported` to `UNKNOWN` when it can't decide: >>> runintrospecter(s=""" - ... from re import match # definitely imported - ... from re import error # definitely imported - ... from re import MULTILINE # might be imported + ... from pickle import dump # definitely imported + ... from pickle import Pickler # definitely imported + ... from pickle import HIGHEST_PROTOCOL # might be imported ... class A: pass # definitely not imported ... def f(x): pass # definitely not imported ... """, attribs="variables is_imported") @@ -158,14 +158,14 @@ +- variables +- A => VariableDoc for epydoc_test.A [1] | +- is_imported = False - +- MULTILINE => VariableDoc for epydoc_test.MULTILINE [2] + +- HIGHEST_PROTOCOL => VariableDoc for epydoc_test.HIGHEST_PROTOCOL [2] | +- is_imported = <UNKNOWN> - +- error => VariableDoc for epydoc_test.error [3] + +- Pickler => VariableDoc for epydoc_test.Pickler [3] | +- is_imported = True - +- f => VariableDoc for epydoc_test.f [4] - | +- is_imported = False - +- match => VariableDoc for epydoc_test.match [5] - +- is_imported = True + +- dump => VariableDoc for epydoc_test.dump [4] + | +- is_imported = True + +- f => VariableDoc for epydoc_test.f [5] + +- is_imported = False Variable Docstrings =================== @@ -504,32 +504,32 @@ ======= >>> runintrospecter(s=""" - ... import re - ... from re import match + ... import pickle + ... from pickle import dump ... """, ... attribs='variables value is_imported') ModuleDoc for epydoc_test [0] +- variables - +- match => VariableDoc for epydoc_test.match [1] + +- dump => VariableDoc for epydoc_test.dump [1] | +- is_imported = True | +- value - | +- ValueDoc for sre.match [2] - +- re => VariableDoc for epydoc_test.re [3] + | +- ValueDoc for pickle.dump [2] + +- pickle => VariableDoc for epydoc_test.pickle [3] +- is_imported = True +- value - +- ModuleDoc for re [4] + +- ModuleDoc for pickle [4] +- variables = {} >>> runintrospecter(s=""" ... from __future__ import division - ... from re import match + ... from pickle import dump ... """, ... attribs='variables value') ModuleDoc for epydoc_test [0] +- variables - +- match => VariableDoc for epydoc_test.match [1] + +- dump => VariableDoc for epydoc_test.dump [1] +- value - +- ValueDoc for sre.match [2] + +- ValueDoc for pickle.dump [2] Unicode ======= This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 04:04:29
|
Revision: 1450 http://svn.sourceforge.net/epydoc/?rev=1450&view=rev Author: edloper Date: 2007-02-10 20:04:28 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Fixed SF bug 1657050, which was caused because the introspector decided not to introspect values that it knew were imported; but it then turned out that it should have introspected them, because they were explicitly listed in __all__. The patch changes the docintrospector to introspect all values listed in __all__. Modified Paths: -------------- trunk/epydoc/src/epydoc/docintrospecter.py trunk/epydoc/src/epydoc/test/docintrospecter.doctest Modified: trunk/epydoc/src/epydoc/docintrospecter.py =================================================================== --- trunk/epydoc/src/epydoc/docintrospecter.py 2007-02-11 03:18:26 UTC (rev 1449) +++ trunk/epydoc/src/epydoc/docintrospecter.py 2007-02-11 04:04:28 UTC (rev 1450) @@ -240,6 +240,14 @@ if module_doc.package not in (None, UNKNOWN): module_doc.package.submodules.append(module_doc) + # Look up the module's __all__ attribute (public names). + public_names = None + if hasattr(module, '__all__'): + try: + public_names = set([str(name) for name in module.__all__]) + except KeyboardInterrupt: raise + except: pass + # Record the module's variables. module_doc.variables = {} for child_name in dir(module): @@ -249,7 +257,10 @@ # Create a VariableDoc for the child, and introspect its # value if it's defined in this module. container = get_containing_module(child) - if container is not None and container == module_doc.canonical_name: + if ((container is not None and + container == module_doc.canonical_name) or + (public_names is not None and + child_name in public_names)): # Local variable. child_val_doc = introspect_docs(child, context=module_doc, module_name=dotted_name) @@ -278,22 +289,18 @@ container=module_doc, docs_extracted_by='introspecter') + # If the module's __all__ attribute is set, use it to set the + # variables public/private status and imported status. + if public_names is not None: + if child_name in public_names: + child_var_doc.is_public = True + if not isinstance(child_var_doc, ModuleDoc): + child_var_doc.is_imported = False + else: + child_var_doc.is_public = False + module_doc.variables[child_name] = child_var_doc - # Record the module's __all__ attribute (public names). - if hasattr(module, '__all__'): - try: - public_names = set([str(name) for name in module.__all__]) - for name, var_doc in module_doc.variables.items(): - if name in public_names: - var_doc.is_public = True - if not isinstance(var_doc, ModuleDoc): - var_doc.is_imported = False - else: - var_doc.is_public = False - except KeyboardInterrupt: raise - except: pass - return module_doc #//////////////////////////////////////////////////////////// Modified: trunk/epydoc/src/epydoc/test/docintrospecter.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/docintrospecter.doctest 2007-02-11 03:18:26 UTC (rev 1449) +++ trunk/epydoc/src/epydoc/test/docintrospecter.doctest 2007-02-11 04:04:28 UTC (rev 1450) @@ -614,3 +614,24 @@ +- name = 'b' +- value +- ClassDoc for epydoc_test.B [1] (defined above) + +Closed Bugs +=========== + +SF Bug [ 1657050 ] Builtins not resolved in "os" +------------------------------------------------ +If a variable is listed in __all__, then we need to introspect it, +even if we know for certain that it's imported. Before this bug +was fixed, the following test generated a generic 'ValueDoc' value +instead of a 'RoutineDoc' value, because it didn't introspect the +value of getcwd. + + >>> x = runintrospecter(s=""" + ... __all__ = ['getcwd'] + ... from os import getcwd + ... """, attribs='variables value') + ModuleDoc for epydoc_test [0] + +- variables + +- getcwd => VariableDoc for epydoc_test.getcwd [1] + +- value + +- RoutineDoc [2] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-11 03:18:28
|
Revision: 1449 http://svn.sourceforge.net/epydoc/?rev=1449&view=rev Author: edloper Date: 2007-02-10 19:18:26 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Fixed SF bug 1657057, caused by using <a /> instead of <a></a> Modified Paths: -------------- trunk/epydoc/src/epydoc/docwriter/html_colorize.py Modified: trunk/epydoc/src/epydoc/docwriter/html_colorize.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_colorize.py 2007-02-11 00:05:34 UTC (rev 1448) +++ trunk/epydoc/src/epydoc/docwriter/html_colorize.py 2007-02-11 03:18:26 UTC (rev 1449) @@ -709,7 +709,7 @@ def lineno_to_html(self): template = '%%%ds' % self.linenum_size n = template % self.lineno - return '<a name="L%s" /><tt class="py-lineno">%s</tt>' \ + return '<a name="L%s"></a><tt class="py-lineno">%s</tt>' \ % (self.lineno, n) def colorize(self): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-02-11 00:05:36
|
Revision: 1448 http://svn.sourceforge.net/epydoc/?rev=1448&view=rev Author: dvarrazzo Date: 2007-02-10 16:05:34 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - if find() fails, also look for classes name defined in each module and return them if not ambiguous. Modified Paths: -------------- trunk/epydoc/src/epydoc/apidoc.py Modified: trunk/epydoc/src/epydoc/apidoc.py =================================================================== --- trunk/epydoc/src/epydoc/apidoc.py 2007-02-10 22:19:35 UTC (rev 1447) +++ trunk/epydoc/src/epydoc/apidoc.py 2007-02-11 00:05:34 UTC (rev 1448) @@ -1669,8 +1669,31 @@ # Initialize the root items list. We sort them by length in # ascending order. (This ensures that variables will shadow # submodules when appropriate.) - self.root = sorted(root, key=lambda d:len(d.canonical_name)) + # When the elements name is the same, list in alphabetical order: + # this is needed by the check for duplicates below. + self.root = sorted(root, + key=lambda d: (len(d.canonical_name), d.canonical_name)) + """The list of C{ValueDoc}s to document. + @type: C{list}""" + # Drop duplicated modules + # [xx] maybe what causes duplicates should be fixed instead. + # If fixed, adjust the sort here above: sorting by names will not + # be required anymore + i = 1 + while i < len(self.root): + if self.root[i-1] is self.root[i]: + del self.root[i] + else: + i += 1 + + self.mlclasses = self._get_module_classes(self.root) + """A mapping from class names to L{ClassDoc}. Contains + classes defined at module level for modules in L{root} + and which can be used as fallback by L{find()} if looking + in containing namespaces fails. + @type: C{dict} from C{str} to L{ClassDoc} or C{list}""" + self.callers = None """A dictionary mapping from C{RoutineDoc}s in this index to lists of C{RoutineDoc}s for the routine's callers. @@ -1789,6 +1812,7 @@ look for the remaining part of the name using C{find} - Builtins - Parameter attributes + - Classes at module level (if the name is not ambiguous) @type name: C{str} or L{DottedName} @type context: L{APIDoc} @@ -1837,6 +1861,57 @@ if all_args is not UNKNOWN and name[0] in all_args: return None + # Is this an object directly contained by any module? + doc = self.mlclasses.get(name[-1]) + if isinstance(doc, APIDoc): + return doc + elif isinstance(doc, list): + log.warning("%s is an ambiguous name: it may be %s" % ( + name[-1], + ", ".join([ "'%s'" % d.canonical_name for d in doc ]))) + + # Drop this item so that the warning is reported only once. + # fail() will fail anyway. + del self.mlclasses[name[-1]] + + def _get_module_classes(self, docs): + """ + Gather all the classes defined in a list of modules. + + Very often people refers to classes only by class name, + even if they are not imported in the namespace. Linking + to such classes will fail if we look for them only in nested + namespaces. Allow them to retrieve only by name. + + @param docs: containers of the objects to collect + @type docs: C{list} of C{APIDoc} + @return: mapping from objects name to the object(s) with that name + @rtype: C{dict} from C{str} to L{ClassDoc} or C{list} + """ + classes = {} + for doc in docs: + if not isinstance(doc, ModuleDoc): + continue + + for var in doc.variables.values(): + if not isinstance(var.value, ClassDoc): + continue + + val = var.value + if val in (None, UNKNOWN) or val.defining_module is not doc: + continue + + name = val.canonical_name[-1] + vals = classes.get(name) + if vals is None: + classes[name] = val + elif not isinstance(vals, list): + classes[name] = [ vals, val ] + else: + vals.append(val) + + return classes + #//////////////////////////////////////////////////////////// # etc #//////////////////////////////////////////////////////////// This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-02-10 22:19:37
|
Revision: 1447 http://svn.sourceforge.net/epydoc/?rev=1447&view=rev Author: dvarrazzo Date: 2007-02-10 14:19:35 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Added 'python' directive to reporesent colourized Python code using reST markup. Modified Paths: -------------- trunk/epydoc/src/epydoc/markup/restructuredtext.py trunk/epydoc/src/epydoc/test/restructuredtext.doctest Modified: trunk/epydoc/src/epydoc/markup/restructuredtext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/restructuredtext.py 2007-02-10 20:34:07 UTC (rev 1446) +++ trunk/epydoc/src/epydoc/markup/restructuredtext.py 2007-02-10 22:19:35 UTC (rev 1447) @@ -77,7 +77,7 @@ from docutils.nodes import NodeVisitor, Text, SkipChildren from docutils.nodes import SkipNode, TreeCopyVisitor from docutils.frontend import OptionParser -from docutils.parsers.rst import directives +from docutils.parsers.rst import directives, Directive import docutils.nodes import docutils.transforms.frontmatter import docutils.transforms @@ -87,7 +87,8 @@ from epydoc.markup import * from epydoc.apidoc import ModuleDoc, ClassDoc from epydoc.docwriter.dotgraph import * -from epydoc.markup.doctest import doctest_to_html, doctest_to_latex +from epydoc.markup.doctest import doctest_to_html, doctest_to_latex, \ + HTMLDoctestColorizer #: A dictionary whose keys are the "consolidated fields" that are #: recognized by epydoc; and whose values are the corresponding epydoc @@ -619,9 +620,30 @@ raise SkipNode() def visit_doctest_block(self, node): - self.body.append(doctest_to_html(str(node[0]))) + pysrc = str(node[0]) + if node.get('codeblock'): + self.body.append(HTMLDoctestColorizer().colorize_codeblock(pysrc)) + else: + self.body.append(doctest_to_html(str(node[0]))) raise SkipNode() + +class PythonCodeDirective(Directive): + required_arguments = 0 + optional_arguments = 0 + has_content = True + + def run(self): + self.assert_has_content() + text = '\n'.join(self.content) + + #node = docutils.nodes.doctest_block(rawsource=text) + #self.state.nested_parse(self.content, self.content_offset, node) + node = docutils.nodes.doctest_block(text, text, codeblock=True) + return [ node ] + +directives.register_directive('python', PythonCodeDirective) + ###################################################################### #{ Graph Generation Directives ###################################################################### Modified: trunk/epydoc/src/epydoc/test/restructuredtext.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/restructuredtext.doctest 2007-02-10 20:34:07 UTC (rev 1446) +++ trunk/epydoc/src/epydoc/test/restructuredtext.doctest 2007-02-10 22:19:35 UTC (rev 1447) @@ -75,3 +75,36 @@ ... Other stuff after a tag. ... """) (u'This is the first line.', True) + +Python code +=========== +reStructuredText markup defines a ``python`` directive to represent a block +as colorized Python code. + +>>> err = [] +>>> p = restructuredtext.parse_docstring( +... """A test module +... +... .. python:: +... +... # This is some Python code +... def foo(): +... pass +... +... class Foo: +... def __init__(self): +... pass +... """, err) +>>> err +[] +>>> print p.to_html(None) +<p>A test module</p> +<pre class="py-doctest"> +<span class="py-comment"># This is some Python code</span> +<span class="py-keyword">def</span> <span class="py-defname">foo</span>(): + <span class="py-keyword">pass</span> +<BLANKLINE> +<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-keyword">pass</span></pre> +<BLANKLINE> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-02-10 20:34:08
|
Revision: 1446 http://svn.sourceforge.net/epydoc/?rev=1446&view=rev Author: dvarrazzo Date: 2007-02-10 12:34:07 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Still more relaxed regexpr to identify valid dotted names, to allow names such 'badguy.00_evilinside'. See SF bug #1649347. Modified Paths: -------------- trunk/epydoc/src/epydoc/apidoc.py Modified: trunk/epydoc/src/epydoc/apidoc.py =================================================================== --- trunk/epydoc/src/epydoc/apidoc.py 2007-02-10 19:55:33 UTC (rev 1445) +++ trunk/epydoc/src/epydoc/apidoc.py 2007-02-10 20:34:07 UTC (rev 1446) @@ -63,9 +63,11 @@ """ UNREACHABLE = "??" _IDENTIFIER_RE = re.compile("""(?x) - (%s | # UNREACHABLE marker, or... - script-\w+ | # Script name, or ... - [a-zA-Z_]\w*'?) # Identifier. (' used for shadowing submodules) + (%s | # UNREACHABLE marker, or.. + (script-)? # Prefix: script (not a module) + \w+ # Identifier (yes, identifiers starting with a + # digit are allowed. See SF bug #1649347) + '?) # Suffix: submodule that is shadowed by a var (-\d+)? # Suffix: unreachable vals with the same name $""" % re.escape(UNREACHABLE)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-02-10 19:55:35
|
Revision: 1445 http://svn.sourceforge.net/epydoc/?rev=1445&view=rev Author: dvarrazzo Date: 2007-02-10 11:55:33 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Test updated after extra the boxes have been dropped from HTML output Modified Paths: -------------- trunk/epydoc/src/epydoc/test/encoding.doctest Modified: trunk/epydoc/src/epydoc/test/encoding.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/encoding.doctest 2007-02-10 19:26:54 UTC (rev 1444) +++ trunk/epydoc/src/epydoc/test/encoding.doctest 2007-02-10 19:55:33 UTC (rev 1445) @@ -202,7 +202,6 @@ ... ''') # doctest: +ELLIPSIS <property object at ...>'s docstring is not a unicode string, but it contains non-ascii data -- treating it as latin-1. € - € Introspection/Parsing Tests =========================== @@ -252,7 +251,6 @@ ... """ ... ''') abc ABC 123 € ߿ ࠀ - abc ABC 123 € ߿ ࠀ >>> test('''# -*- coding: utf-8 -*- ... def f(x): @@ -291,10 +289,6 @@ abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ - abc ABC 123 € ߿ ࠀ - abc ABC 123 € ߿ ࠀ - abc ABC 123 € ߿ ࠀ - abc ABC 123 € ߿ ࠀ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-02-10 19:26:57
|
Revision: 1444 http://svn.sourceforge.net/epydoc/?rev=1444&view=rev Author: dvarrazzo Date: 2007-02-10 11:26:54 -0800 (Sat, 10 Feb 2007) Log Message: ----------- - Added regression tests for sumarization for each markup. - Added APIDoc.is_detailed() method, with implementation for relevant subclasses. - APIDoc.pyval_repr() now always return the best representation for the object; single writers don't have to choose between parsed or introspected representation. - Added APIDoc.summary_pyval_repr() method to return a short version of the Python value. - select_variables() method can filter out (or in, if it cares) objects requiring extra details. - Summary lines in HTML output can be not linked to a detail box. If so, they gain an anchor to permit being referred in place of the detail box. - Added a link to source in summary items, which can be used for object whose details box is missing. - Classes, modules and variables names in the summary rendered in monotype font as function names. Modified Paths: -------------- trunk/epydoc/src/epydoc/apidoc.py trunk/epydoc/src/epydoc/docstringparser.py trunk/epydoc/src/epydoc/docwriter/dotgraph.py trunk/epydoc/src/epydoc/docwriter/html.py trunk/epydoc/src/epydoc/docwriter/html_css.py trunk/epydoc/src/epydoc/docwriter/latex.py trunk/epydoc/src/epydoc/docwriter/plaintext.py trunk/epydoc/src/epydoc/markup/__init__.py trunk/epydoc/src/epydoc/markup/epytext.py trunk/epydoc/src/epydoc/markup/javadoc.py trunk/epydoc/src/epydoc/markup/plaintext.py trunk/epydoc/src/epydoc/markup/restructuredtext.py trunk/epydoc/src/epydoc/test/epytext.doctest Added Paths: ----------- trunk/epydoc/src/epydoc/test/javadoc.doctest trunk/epydoc/src/epydoc/test/plaintext.doctest trunk/epydoc/src/epydoc/test/restructuredtext.doctest Modified: trunk/epydoc/src/epydoc/apidoc.py =================================================================== --- trunk/epydoc/src/epydoc/apidoc.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/apidoc.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -341,6 +341,11 @@ its docstring. @type: L{ParsedDocstring<epydoc.markup.ParsedDocstring>}""" + other_docs = UNKNOWN + """@ivar: A flag indicating if the entire L{docstring} body (except tags + if any) is entirely included in the L{summary}. + @type: C{bool}""" + metadata = UNKNOWN """@ivar: Metadata about the documented item, extracted from fields in its docstring. I{Currently} this is encoded as a list of tuples @@ -446,7 +451,20 @@ name_cmp = cmp(self.canonical_name, other.canonical_name) if name_cmp == 0: return -1 else: return name_cmp - + + def is_detailed(self): + """ + Does this object deserve a box with extra details? + + @return: True if the object needs extra details, else False. + @rtype: C{bool} + """ + if self.other_docs is True: + return True + + if self.metadata is not UNKNOWN: + return bool(self.metadata) + __mergeset = None """The set of all C{APIDoc} objects that have been merged with this C{APIDoc} (using L{merge_and_overwrite()}). Each C{APIDoc} @@ -655,6 +673,12 @@ else: return [self.value] + def is_detailed(self): + if (self.value in (None, UNKNOWN)): + return super(VariableDoc, self).is_detailed() + else: + return self.value.is_detailed() + ###################################################################### # Value Documentation Objects ###################################################################### @@ -699,6 +723,9 @@ reflect the actual value (e.g., if the value was modified after the initial assignment). @type: C{unicode}""" + + summary_linelen = 75 + """@cvar: The maximum length of a row to fit in a summary.""" #} end of "value representation" group #{ Context @@ -737,12 +764,8 @@ def __repr__(self): if self.canonical_name is not UNKNOWN: return '<%s %s>' % (self.__class__.__name__, self.canonical_name) - elif self.pyval_repr() is not UNKNOWN: + else: return '<%s %s>' % (self.__class__.__name__, self.pyval_repr()) - elif self.parse_repr is not UNKNOWN: - return '<%s %s>' % (self.__class__.__name__, self.parse_repr) - else: - return '<%s>' % self.__class__.__name__ def __setstate__(self, state): self.__dict__ = state @@ -766,11 +789,69 @@ # Return the pickle state. return self.__pickle_state + UNKNOWN_REPR = "??" + """@cvar: The string representation of an unknown value.""" + def pyval_repr(self): - if not hasattr(self, '_pyval_repr'): - self._pyval_repr = self._get_pyval_repr() - return self._pyval_repr - + """Return a string representation of the python value. + + The string representation may include data from introspection, parsing + and is authoritative as "the best way to represent a Python value." + + @return: A nice string representation. Never C{None} nor L{UNKNOWN} + @rtype: C{str} + + @todo: String representation can be made better here. + """ + if hasattr(self, '_pyval_repr'): + return self._pyval_repr + + rv = self._get_pyval_repr() + if rv is UNKNOWN: + rv = self.parse_repr + + if rv is UNKNOWN: + rv = self.UNKNOWN_REPR + + assert isinstance(rv, basestring) + self._pyval_repr = rv + return rv + + def summary_pyval_repr(self, max_len=None): + """Return a short version of L{pyval_repr}, fitting on a single line. + + Notice that L{GenericValueDoc.is_detailed()} uses this function to + return an answer leavling C{max_len} to the default value. So, if + a writer is to decide whether to emit a complete representation or + limit itself to the summary, it should call this function leaving + C{max_len} to its default value too, if it wants to generate consistent + results. + + @param max_len: The maximum length allowed. If None, use + L{summary_linelen} + + @return: the short representation and a boolean value stating if there + is further value to represent after such representation or not. + + @rtype: C{(str, bool)} + """ + ro = self.pyval_repr() + lo = False + + # Reduce to a single line + if "\n" in ro: + ro = ro.split("\n",1)[0] + lo = True + + # Truncate a long line + if max_len is None: + max_len = self.summary_linelen + if len(ro) > max_len: + ro = ro[:max_len-3]+'...' + lo = True + + return (ro, lo) + def _get_pyval_repr(self): """ Return a string representation of this value based on its pyval; @@ -801,6 +882,9 @@ """ canonical_name = None + def is_detailed(self): + return self.summary_pyval_repr()[1] + class NamespaceDoc(ValueDoc): """ API documentation information about a singe Python namespace @@ -857,6 +941,9 @@ APIDoc.__init__(self, **kwargs) assert self.variables is not UNKNOWN + def is_detailed(self): + return True + def apidoc_links(self, **filters): variables = filters.get('variables', True) imports = filters.get('imports', True) @@ -1038,7 +1125,7 @@ self.submodule_groups = self._init_grouping(elts) def select_variables(self, group=None, value_type=None, public=None, - imported=None): + imported=None, detailed=None): """ Return a specified subset of this module's L{sorted_variables} list. If C{value_type} is given, then only return variables @@ -1065,6 +1152,11 @@ always the special group name C{''}, which is used for variables that do not belong to any group. @type group: C{string} + + @param detailed: If True (False), return only the variables + deserving (not deserving) a detailed informative box. + If C{None}, don't care. + @type detailed: C{bool} """ if (self.sorted_variables is UNKNOWN or self.variable_groups is UNKNOWN): @@ -1087,6 +1179,12 @@ elif imported is False: var_list = [v for v in var_list if v.is_imported is not True] + # Detailed filter + if detailed is True: + var_list = [v for v in var_list if v.is_detailed() is True] + elif detailed is False: + var_list = [v for v in var_list if v.is_detailed() is not True] + # [xx] Modules are not currently included in any of these # value types. if value_type is None: @@ -1211,8 +1309,8 @@ for seq in nonemptyseqs: # remove cand if seq[0] == cand: del seq[0] - def select_variables(self, group=None, value_type=None, - inherited=None, public=None, imported=None): + def select_variables(self, group=None, value_type=None, inherited=None, + public=None, imported=None, detailed=None): """ Return a specified subset of this class's L{sorted_variables} list. If C{value_type} is given, then only return variables @@ -1257,6 +1355,11 @@ @param inherited: If C{None}, then return both inherited and local variables; if C{True}, then return only inherited variables; if C{False}, then return only local variables. + + @param detailed: If True (False), return only the variables + deserving (not deserving) a detailed informative box. + If C{None}, don't care. + @type detailed: C{bool} """ if (self.sorted_variables is UNKNOWN or self.variable_groups is UNKNOWN): @@ -1284,7 +1387,13 @@ var_list = [v for v in var_list if v.is_imported is True] elif imported is False: var_list = [v for v in var_list if v.is_imported is not True] - + + # Detailed filter + if detailed is True: + var_list = [v for v in var_list if v.is_detailed() is True] + elif detailed is False: + var_list = [v for v in var_list if v.is_detailed() is not True] + if value_type is None: return var_list elif value_type == 'method': @@ -1399,6 +1508,29 @@ @type: C{list}""" #} end of "information extracted from docstrings" group + def is_detailed(self): + if super(RoutineDoc, self).is_detailed(): + return True + + if self.arg_descrs not in (None, UNKNOWN) and self.arg_descrs: + return True + + if self.arg_types not in (None, UNKNOWN) and self.arg_types: + return True + + if self.return_descr not in (None, UNKNOWN): + return True + + if self.exception_descrs not in (None, UNKNOWN) and self.exception_descrs: + return True + + if (self.decorators not in (None, UNKNOWN) + and [ d for d in self.decorators + if d not in ('classmethod', 'staticmethod') ]): + return True + + return False + def all_args(self): """ @return: A list of the names of all arguments (positional, @@ -1460,6 +1592,19 @@ if self.fdel not in (None, UNKNOWN): val_docs.append(self.fdel) return val_docs + def is_detailed(self): + if super(PropertyDoc, self).is_detailed(): + return True + + if self.fget not in (None, UNKNOWN) and self.fget.pyval is not None: + return True + if self.fset not in (None, UNKNOWN) and self.fset.pyval is not None: + return True + if self.fdel not in (None, UNKNOWN) and self.fdel.pyval is not None: + return True + + return False + ###################################################################### ## Index ###################################################################### Modified: trunk/epydoc/src/epydoc/docstringparser.py =================================================================== --- trunk/epydoc/src/epydoc/docstringparser.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/docstringparser.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -235,13 +235,15 @@ # Extract a summary if api_doc.summary is None and api_doc.descr is not None: - api_doc.summary = api_doc.descr.summary() + api_doc.summary, api_doc.other_docs = api_doc.descr.summary() # If the summary is empty, but the return field is not, then use # the return field to generate a summary description. if (isinstance(api_doc, RoutineDoc) and api_doc.summary is None and api_doc.return_descr is not None): - api_doc.summary = RETURN_PDS + api_doc.return_descr.summary() + s, o = api_doc.return_descr.summary() + api_doc.summary = RETURN_PDS + s + api_doc.other_docs = o # [XX] Make sure we don't have types/param descrs for unknown # vars/params? @@ -653,7 +655,7 @@ _check(api_doc, tag, arg, expect_arg=False) api_doc.is_instvar = False api_doc.descr = markup.ConcatenatedDocstring(api_doc.descr, descr) - api_doc.summary = descr.summary() + api_doc.summary, api_doc.other_docs = descr.summary() # Otherwise, @cvar should be used in a class. else: @@ -671,7 +673,7 @@ # require that there be no other descr? api_doc.is_instvar = True api_doc.descr = markup.ConcatenatedDocstring(api_doc.descr, descr) - api_doc.summary = descr.summary() + api_doc.summary, api_doc.other_docs = descr.summary() # Otherwise, @ivar should be used in a class. else: @@ -768,7 +770,7 @@ raise ValueError(REDEFINED % ('description for '+ident)) var_doc.descr = descr if var_doc.summary in (None, UNKNOWN): - var_doc.summary = var_doc.descr.summary() + var_doc.summary, var_doc.other_docs = var_doc.descr.summary() def set_var_type(api_doc, ident, descr): if ident not in api_doc.variables: Modified: trunk/epydoc/src/epydoc/docwriter/dotgraph.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/dotgraph.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/docwriter/dotgraph.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -693,14 +693,9 @@ """ if default is None: return '%s' % name - elif default.parse_repr is not UNKNOWN: - return '%s=%s' % (name, default.parse_repr) else: - pyval_repr = default.pyval_repr() - if pyval_repr is not UNKNOWN: - return '%s=%s' % (name, pyval_repr) - else: - return '%s=??' % name + pyval_repr = default.summary_pyval_repr()[0] + return '%s=%s' % (name, pyval_repr) def _qualifier_cell(self, key_label, port): return self._QUALIFIER_CELL % (port, self.bgcolor, key_label) Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -400,7 +400,7 @@ if not isinstance(d, GenericValueDoc)] for doc in valdocs: if isinstance(doc, NamespaceDoc): - # add any vars with generic vlaues; but don't include + # add any vars with generic values; but don't include # inherited vars. self.indexed_docs += [d for d in doc.variables.values() if isinstance(d.value, GenericValueDoc) @@ -509,6 +509,11 @@ self._mkdir(directory) self._directory = directory + # Set the default value for L{ValueDoc.summary_linelen} so that + # L{ValueDoc.summary_pyval_repr()} return value is consistent with + # L{ValueDoc.is_detailed()} + ValueDoc.summary_linelen = self._variable_summary_linelen + # Write the CSS file. self._files_written += 1 log.progress(self._files_written/self._num_files, 'epydoc.css') @@ -1898,6 +1903,8 @@ @param container: The API documentation for the class or module whose summary table we're writing. """ + link = None # link to the source code + # If it's a private variable, then mark its <tr>. if var_doc.is_public: tr_class = '' else: tr_class = ' class="private"' @@ -1907,24 +1914,18 @@ if isinstance(var_doc.value, RoutineDoc): typ = self.return_type(var_doc, indent=6) description = self.function_signature(var_doc, True, True) + link = self.pysrc_link(var_doc.value) else: typ = self.type_descr(var_doc, indent=6) - description = self.href(var_doc) + description = self.summary_name(var_doc, link_name=True) if isinstance(var_doc.value, GenericValueDoc): - pyval_repr = var_doc.value.pyval_repr() - if pyval_repr is not UNKNOWN: - val_repr = pyval_repr - else: - val_repr = var_doc.value.parse_repr - if val_repr is not UNKNOWN: - val_repr = ' '.join(val_repr.strip().split()) - maxlen = self._variable_summary_linelen - if len(val_repr) > maxlen: - val_repr = val_repr[:maxlen-3]+'...' - val_repr = plaintext_to_html(val_repr) - tooltip = self.variable_tooltip(var_doc) - description += (' = <code%s>%s</code>' % - (tooltip, val_repr)) + # The summary max length has been chosen setting + # L{ValueDoc.summary_linelen} when L{write()} was called + val_repr = var_doc.value.summary_pyval_repr()[0] + val_repr = plaintext_to_html(val_repr) + tooltip = self.variable_tooltip(var_doc) + description += (' = <code%s>%s</code>' % + (tooltip, val_repr)) # Add the summary to the description (if there is one). summary = self.summary(var_doc, indent=6) @@ -1936,11 +1937,11 @@ self.href(var_doc.container) + ")</em>") # Write the summary line. - self._write_summary_line(out, typ, description, tr_class) + self._write_summary_line(out, typ, description, tr_class, link) _write_summary_line = compile_template( """ - _write_summary_line(self, out, typ, description, tr_class) + _write_summary_line(self, out, typ, description, tr_class, link) """, # /------------------------- Template -------------------------\ ''' @@ -1948,7 +1949,17 @@ <td width="15%" align="right" valign="top" class="summary"> <span class="summary-type">$typ or " "$</span> </td><td class="summary"> - $description$ + >>> if link is not None: + <table width="100%" cellpadding="0" cellspacing="0" border="0"> + <tr> + <td>$description$</td> + <td align="right" valign="top">$link$</td> + </tr> + </table> + >>> #endif + >>> if link is None: + $description$ + >>> #endif </td> </tr> ''') @@ -1963,11 +1974,13 @@ if isinstance(doc, ClassDoc): var_docs = doc.select_variables(value_type=value_type, imported=False, inherited=False, - public=self._public_filter) + public=self._public_filter, + detailed=True) else: var_docs = doc.select_variables(value_type=value_type, imported=False, - public=self._public_filter) + public=self._public_filter, + detailed=True) if not var_docs: return # Write a header @@ -2273,15 +2286,8 @@ def variable_tooltip(self, var_doc): if var_doc.value in (None, UNKNOWN): return '' - else: - pyval_repr = var_doc.value.pyval_repr() - if pyval_repr is not UNKNOWN: - s = pyval_repr - elif var_doc.value.parse_repr is not UNKNOWN: - s = var_doc.value.parse_repr - else: - return '' - + + s = var_doc.value.pyval_repr() if len(s) > self._variable_tooltip_linelen: s = s[:self._variable_tooltip_linelen-3]+'...' return ' title="%s"' % plaintext_to_html(s) @@ -2290,15 +2296,8 @@ if val_doc is UNKNOWN: return '' if val_doc.pyval is not UNKNOWN: return self.pprint_pyval(val_doc.pyval) - elif val_doc.pyval_repr() is not UNKNOWN: - s = plaintext_to_html(val_doc.pyval_repr()) - elif val_doc.parse_repr is not UNKNOWN: - s = plaintext_to_html(val_doc.parse_repr) elif isinstance(val_doc, GenericValueDoc): - # This *should* never happen -- GenericValueDoc's should always - # have a pyval_repr or a parse_repr. - log.debug('pprint_value() got GenericValueDoc w/ UNKNOWN repr') - return '' + s = plaintext_to_html(val_doc.pyval_repr()) else: s = self.href(val_doc) return self._linewrap_html(s, self._variable_linelen, @@ -2537,15 +2536,12 @@ '</span>(...)</span>') % (css_class, css_class, api_doc.name)) # Get the function's name. - if link_name: - name = self.href(api_doc, css_class=css_class+'-name') - else: - name = ('<span class="%s-name">%s</span>' % - (css_class, api_doc.name)) + name = self.summary_name(api_doc, css_class=css_class+'-name', + link_name=link_name) else: func_doc = api_doc name = self.href(api_doc, css_class=css_class+'-name') - + if func_doc.posargs == UNKNOWN: args = ['...'] else: @@ -2564,6 +2560,13 @@ return ('<span class="%s">%s(%s)</span>' % (css_class, name, ',\n '.join(args))) + def summary_name(self, api_doc, css_class='summary-name', link_name=False): + if link_name and api_doc.is_detailed(): + return self.href(api_doc, css_class=css_class) + else: + return '<a name="%s" /><span class="%s">%s</span>' % \ + (api_doc.name, css_class, api_doc.name) + # [xx] tuple args??? def func_arg(self, name, default, css_class): name = self._arg_name(name) @@ -2573,12 +2576,8 @@ s += ('=<span class="%s-default">%s</span>' % (css_class, plaintext_to_html(default.parse_repr))) else: - pyval_repr = default.pyval_repr() - if pyval_repr is not UNKNOWN: - s += ('=<span class="%s-default">%s</span>' % - (css_class, plaintext_to_html(pyval_repr))) - else: - s += '=<span class="%s-default">??</span>' % css_class + s += ('=<span class="%s-default">%s</span>' % + (css_class, plaintext_to_html(default.pyval_repr()))) return s def _arg_name(self, arg): Modified: trunk/epydoc/src/epydoc/docwriter/html_css.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -187,6 +187,10 @@ .summary-sig-arg { color: $summary_sig_arg; } .summary-sig-default { color: $summary_sig_default; } +/* To render variables, classes etc. like functions */ +.summary-name { color: $summary_sig_name; font-weight: bold; + font-family: monospace; } + /* Variable values * - In the 'variable details' sections, each varaible's value is * listed in a 'pre.variable' box. The width of this box is Modified: trunk/epydoc/src/epydoc/docwriter/latex.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/latex.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/docwriter/latex.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -727,12 +727,7 @@ def func_arg(self, name, default): s = '\\textit{%s}' % plaintext_to_latex(self._arg_name(name)) if default is not None: - if default.parse_repr is not UNKNOWN: - s += '=\\texttt{%s}' % plaintext_to_latex(default.parse_repr) - elif default.pyval_repr() is not UNKNOWN: - s += '=\\texttt{%s}' % plaintext_to_latex(default.pyval_repr()) - else: - s += '=\\texttt{??}' + s += '=\\texttt{%s}' % default.summary_pyval_repr()[0] return s def _arg_name(self, arg): @@ -806,8 +801,7 @@ has_descr = var_doc.descr not in (None, UNKNOWN) has_type = var_doc.type_descr not in (None, UNKNOWN) has_repr = (var_doc.value not in (None, UNKNOWN) and - (var_doc.value.parse_repr is not UNKNOWN or - var_doc.value.pyval_repr() is not UNKNOWN)) + var_doc.value.pyval_repr() != var_doc.value.UNKNOWN_REPR) if has_descr or has_type: out('\\raggedright ') if has_descr: @@ -816,10 +810,7 @@ if has_repr: out('\\textbf{Value:} \n') pyval_repr = var_doc.value.pyval_repr() - if pyval_repr is not UNKNOWN: - out(self._pprint_var_value(pyval_repr, 80)) - elif var_doc.value.parse_repr is not UNKNOWN: - out(self._pprint_var_value(var_doc.value.parse_repr, 80)) + out(self._pprint_var_value(pyval_repr, 80)) if has_type: ptype = self.docstring_to_latex(var_doc.type_descr, 12).strip() out('%s\\textit{(type=%s)}' % (' '*12, ptype)) Modified: trunk/epydoc/src/epydoc/docwriter/plaintext.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/plaintext.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/docwriter/plaintext.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -137,16 +137,8 @@ var_doc.value.canonical_name not in (None, UNKNOWN)): out(' = %s' % var_doc.value.canonical_name) elif var_doc.value not in (UNKNOWN, None): - pyval_repr = var_doc.value.pyval_repr() - if pyval_repr is not UNKNOWN: - val_repr = pyval_repr.expandtabs() - else: - val_repr = var_doc.value.parse_repr - if val_repr is not UNKNOWN: - if len(val_repr)+len(name) > 75: - val_repr = '%s...' % val_repr[:75-len(name)-3] - if '\n' in val_repr: val_repr = '%s...' % (val_repr.split()[0]) - out(' = %s' % val_repr) + val_repr = var_doc.value.summary_pyval_repr(max_len=len(name)-75)[0] + out(' = %s' % val_repr.expandtabs()) out('\n') if not verbose: return prefix += ' ' # indent the body. @@ -206,14 +198,8 @@ def fmt_arg(self, name, default): if default is None: return '%s' % name - elif default.parse_repr is not UNKNOWN: - return '%s=%s' % (name, default.parse_repr) else: - pyval_repr = default.pyval_repr() - if pyval_repr is not UNKNOWN: - return '%s=%s' % (name, pyval_repr) - else: - return '%s=??' % name + return '%s=%s' % (name, default.summary_pyval_repr()[0]) def write_list(self, out, heading, doc, value_type=None, imported=False, inherited=False, prefix='', noindent=False, Modified: trunk/epydoc/src/epydoc/markup/__init__.py =================================================================== --- trunk/epydoc/src/epydoc/markup/__init__.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/markup/__init__.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -258,12 +258,14 @@ def summary(self): """ - @return: A short summary of this docstring. Typically, the - summary consists of the first sentence of the docstring. - @rtype: L{ParsedDocstring} + @return: A pair consisting of a short summary of this docstring and a + boolean value indicating whether there is further documentation + in addition to the summary. Typically, the summary consists of the + first sentence of the docstring. + @rtype: (L{ParsedDocstring}, C{bool}) """ # Default behavior: - return self + return self, False def concatenate(self, other): """ Modified: trunk/epydoc/src/epydoc/markup/epytext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/epytext.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/markup/epytext.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -1952,7 +1952,7 @@ return childstr def summary(self): - if self._tree is None: return self + if self._tree is None: return self, False tree = self._tree doc = Element('epytext') @@ -1974,8 +1974,16 @@ variables[0].children.append(str) # If we didn't find a paragraph, return an empty epytext. - if len(variables) == 0: return ParsedEpytextDocstring(doc) + if len(variables) == 0: return ParsedEpytextDocstring(doc), False + # Is there anything else, excluding tags, after the first variable? + long_docs = False + for var in variables[1:]: + if isinstance(var, Element) and var.tag == 'fieldlist': + continue + long_docs = True + break + # Extract the first sentence. parachildren = variables[0].children para = Element('para') @@ -1985,10 +1993,15 @@ m = re.match(r'(\s*[\w\W]*?\.)(\s|$)', parachild) if m: para.children.append(m.group(1)) - return ParsedEpytextDocstring(doc) + long_docs |= parachild is not parachildren[-1] + if not long_docs: + other = parachild[m.end():] + if other and not other.isspace(): + long_docs = True + return ParsedEpytextDocstring(doc), long_docs para.children.append(parachild) - return ParsedEpytextDocstring(doc) + return ParsedEpytextDocstring(doc), long_docs def split_fields(self, errors=None): if self._tree is None: return (self, ()) Modified: trunk/epydoc/src/epydoc/markup/javadoc.py =================================================================== --- trunk/epydoc/src/epydoc/markup/javadoc.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/markup/javadoc.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -221,12 +221,26 @@ # Jeff's hack to get summary working def summary(self): - m = re.match(r'(\s*[\w\W]*?\.)(\s|$)', self._docstring) + # Drop tags + doc = "\n".join([ row for row in self._docstring.split('\n') + if not row.lstrip().startswith('@') ]) + + m = re.match(r'(\s*[\w\W]*?\.)(\s|$)', doc) if m: - return ParsedJavadocDocstring(m.group(1)) + other = doc[m.end():] + return (ParsedJavadocDocstring(m.group(1)), + other != '' and not other.isspace()) + else: - summary = self._docstring.split('\n', 1)[0]+'...' - return ParsedJavadocDocstring(summary) + parts = doc.strip('\n').split('\n', 1) + if len(parts) == 1: + summary = parts[0] + other = False + else: + summary = parts[0] + '...' + other = True + + return ParsedJavadocDocstring(summary), other # def concatenate(self, other): # if not isinstance(other, ParsedJavadocDocstring): Modified: trunk/epydoc/src/epydoc/markup/plaintext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/plaintext.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/markup/plaintext.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -53,10 +53,19 @@ def summary(self): m = re.match(r'(\s*[\w\W]*?\.)(\s|$)', self._text) if m: - return ParsedPlaintextDocstring(m.group(1), verbatim=0) + other = self._text[m.end():] + return (ParsedPlaintextDocstring(m.group(1), verbatim=0), + other != '' and not other.isspace()) else: - summary = self._text.split('\n', 1)[0]+'...' - return ParsedPlaintextDocstring(summary, verbatim=0) + parts = self._text.strip('\n').split('\n', 1) + if len(parts) == 1: + summary = parts[0] + other = False + else: + summary = parts[0] + '...' + other = True + + return ParsedPlaintextDocstring(summary, verbatim=0), other # def concatenate(self, other): # if not isinstance(other, ParsedPlaintextDocstring): Modified: trunk/epydoc/src/epydoc/markup/restructuredtext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/restructuredtext.py 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/markup/restructuredtext.py 2007-02-10 19:26:54 UTC (rev 1444) @@ -174,7 +174,7 @@ visitor = _SummaryExtractor(self._document) try: self._document.walk(visitor) except docutils.nodes.NodeFound: pass - return visitor.summary + return visitor.summary, bool(visitor.other_docs) # def concatenate(self, other): # result = self._document.copy() @@ -278,12 +278,16 @@ def __init__(self, document): NodeVisitor.__init__(self, document) self.summary = None + self.other_docs = None def visit_document(self, node): self.summary = None def visit_paragraph(self, node): - if self.summary is not None: return + if self.summary is not None: + # found a paragraph after the first one + self.other_docs = True + raise docutils.nodes.NodeFound('Found summary') summary_pieces = [] @@ -293,6 +297,9 @@ m = re.match(r'(\s*[\w\W]*?\.)(\s|$)', child.data) if m: summary_pieces.append(docutils.nodes.Text(m.group(1))) + other = child.data[m.end():] + if other and not other.isspace(): + self.other_docs = True break summary_pieces.append(child) @@ -301,8 +308,10 @@ summary_doc[:] = [summary_para] summary_para[:] = summary_pieces self.summary = ParsedRstDocstring(summary_doc) - raise docutils.nodes.NodeFound('Found summary') + def visit_field(self, node): + raise SkipNode + def unknown_visit(self, node): 'Ignore all unknown nodes' Modified: trunk/epydoc/src/epydoc/test/epytext.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/epytext.doctest 2007-02-08 04:17:45 UTC (rev 1443) +++ trunk/epydoc/src/epydoc/test/epytext.doctest 2007-02-10 19:26:54 UTC (rev 1444) @@ -25,10 +25,10 @@ >>> print testparse(""" ... this is one paragraph. - ... + ... ... This is ... another. - ... + ... ... This is a third""") <para>this is one paragraph.</para> <para>This is another.</para> @@ -38,7 +38,7 @@ >>> print testparse(""" ... This is a paragraph. - ... + ... ... @foo: This is a field.""") <para>This is a paragraph.</para> <fieldlist><field><tag>foo</tag> @@ -79,7 +79,7 @@ >>> print testparse(""" ... This is a paragraph. - ... + ... ... - This is a list item.""") Traceback (most recent call last): StructuringError: Line 4: Lists must be indented. @@ -102,7 +102,7 @@ ... This is a paragraph. ... - This is a list item. ... Hello. - ... + ... ... - Sublist item""") Traceback (most recent call last): StructuringError: Line 6: Lists must be indented. @@ -137,9 +137,9 @@ >>> print testparse(""" ... This is a paragraph. - ... + ... ... - This is a list item. - ... + ... ... This is a paragraph""") <para>This is a paragraph.</para> <ulist><li><para>This is a list item.</para></li></ulist> @@ -147,7 +147,7 @@ >>> print testparse(""" ... This is a paragraph. - ... + ... ... - This is a list item. ... This is a paragraph""") <para>This is a paragraph.</para> @@ -186,7 +186,7 @@ ... checkparse('%s\n%s' % (li1, p), ONELIST+PARA) ... checkparse('%s\n%s\n%s' % (p, li1, p), ... PARA+ONELIST+PARA) - ... + ... ... for li2 in (LI1, LI2, LI3, LI4): ... checkparse('%s\n%s' % (li1, li2), TWOLIST) ... checkparse('%s\n%s\n%s' % (p, li1, li2), PARA+TWOLIST) @@ -223,3 +223,62 @@ ... checkparse(nl1+indent+LI, ONELIST) ... for nl2 in ('\n', '\n\n'): ... checkparse(nl1+indent+LI+nl2+indent+LI, TWOLIST) + +Summary +======= +The implementation of the summaization function works as expected. + +>>> from epydoc.markup import epytext +>>> def getsummary(s): +... p = epytext.parse_docstring(s, []) +... s, o = p.summary() +... s = s.to_plaintext(None).strip() +... return s, o + +Let's not lose anything! + +>>> getsummary("Single line") +('Single line', False) + +>>> getsummary("Single line.") +('Single line.', False) + +>>> getsummary(""" +... Single line C{with} period. +... """) +('Single line with period.', False) + +>>> getsummary(""" +... Single line C{with }period. +... +... @type: Also with a tag. +... """) +('Single line with period.', False) + +>>> getsummary(""" +... Other lines C{with} period. +... This is attached +... """) +('Other lines with period.', True) + +>>> getsummary(""" +... Other lines C{with} period. +... +... This is detached +... +... @type: Also with a tag. +... """) +('Other lines with period.', True) + +>>> getsummary(""" +... Other lines without period +... This is attached +... """) +('Other lines without period This is attached', False) + +>>> getsummary(""" +... Other lines without period +... +... This is detached +... """) +('Other lines without period...', True) Added: trunk/epydoc/src/epydoc/test/javadoc.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/javadoc.doctest (rev 0) +++ trunk/epydoc/src/epydoc/test/javadoc.doctest 2007-02-10 19:26:54 UTC (rev 1444) @@ -0,0 +1,68 @@ +Regression Testing for plaintext +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Summary +======= +The implementation of the summaization function works as expected. + +>>> from epydoc.markup import javadoc +>>> def getsummary(s): +... p = javadoc.parse_docstring(s, []) +... s, o = p.summary() +... s = s.to_plaintext(None).strip() +... return s, o + +#Let's not lose anything! + +>>> getsummary("Single line") +('Single line', False) + +>>> getsummary("Single line.") +('Single line.', False) + +>>> getsummary(""" +... Single line <i>with</i> period. +... """) +('Single line <i>with</i> period.', False) + +>>> getsummary(""" +... Single line <i>with</i> period. +... +... @type Also with a tag. +... """) +('Single line <i>with</i> period.', False) + +>>> getsummary(""" +... Other lines <i>with</i> period. +... This is attached +... """) +('Other lines <i>with</i> period.', True) + +>>> getsummary(""" +... Other lines <i>with</i> period. +... +... This is detached +... +... @type Also with a tag. +... """) +('Other lines <i>with</i> period.', True) + +>>> getsummary(""" +... Other lines without period +... This is attached +... """) +('Other lines without period...', True) + +>>> getsummary(""" +... Other lines without period +... +... This is detached +... """) +('Other lines without period...', True) + +>>> getsummary(""" +... Single line <i>without</i> period +... +... @type Also with a tag. +... """) +('Single line <i>without</i> period', False) Added: trunk/epydoc/src/epydoc/test/plaintext.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/plaintext.doctest (rev 0) +++ trunk/epydoc/src/epydoc/test/plaintext.doctest 2007-02-10 19:26:54 UTC (rev 1444) @@ -0,0 +1,52 @@ +Regression Testing for plaintext +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Summary +======= +The implementation of the summaization function works as expected. + +>>> from epydoc.markup import plaintext +>>> def getsummary(s): +... p = plaintext.parse_docstring(s, []) +... s, o = p.summary() +... s = s.to_plaintext(None).strip() +... return s, o + +Let's not lose anything! + +>>> getsummary("Single line") +('Single line', False) + +>>> getsummary("Single line.") +('Single line.', False) + +>>> getsummary(""" +... Single line with period. +... """) +('Single line with period.', False) + +>>> getsummary(""" +... Other lines with period. +... This is attached +... """) +('Other lines with period.', True) + +>>> getsummary(""" +... Other lines with period. +... +... This is detached +... """) +('Other lines with period.', True) + +>>> getsummary(""" +... Other lines without period +... This is attached +... """) +('Other lines without period...', True) + +>>> getsummary(""" +... Other lines without period +... +... This is detached +... """) +('Other lines without period...', True) Added: trunk/epydoc/src/epydoc/test/restructuredtext.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/restructuredtext.doctest (rev 0) +++ trunk/epydoc/src/epydoc/test/restructuredtext.doctest 2007-02-10 19:26:54 UTC (rev 1444) @@ -0,0 +1,77 @@ +Regression Testing for plaintext +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Summary +======= +The implementation of the summaization function works as expected. + +>>> from epydoc.markup import restructuredtext +>>> def getsummary(s): +... p = restructuredtext.parse_docstring(s, []) +... s, o = p.summary() +... s = s.to_plaintext(None).strip() +... return s, o + +#Let's not lose anything! + +>>> getsummary("Single line") +(u'Single line', False) + +>>> getsummary("Single line.") +(u'Single line.', False) + +>>> getsummary(""" +... Single line *with* period. +... """) +(u'Single line with period.', False) + +>>> getsummary(""" +... Single line `with` period. +... +... :type: Also with a tag. +... """) +(u'Single line with period.', False) + +>>> getsummary(""" +... Other lines **with** period. +... This is attached +... """) +(u'Other lines with period.', True) + +>>> getsummary(""" +... Other lines *with* period. +... +... This is detached +... +... :type: Also with a tag. +... """) +(u'Other lines with period.', True) + +>>> getsummary(""" +... Other lines without period +... This is attached +... """) +(u'Other lines without period\nThis is attached', False) + +>>> getsummary(""" +... Other lines without period +... +... This is detached +... """) +(u'Other lines without period...', True) + +>>> getsummary(""" +... Single line *without* period +... +... :type: Also with a tag. +... """) +(u'Single line without period', False) + +>>> getsummary(""" +... This is the first line. +... +... :type: Also with a tag. +... +... Other stuff after a tag. +... """) +(u'This is the first line.', True) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-08 04:17:46
|
Revision: 1443 http://svn.sourceforge.net/epydoc/?rev=1443&view=rev Author: edloper Date: 2007-02-07 20:17:45 -0800 (Wed, 07 Feb 2007) Log Message: ----------- - Fixed a bug that generated an extra '</tt>' tag under some conditions. (an 'if' was replaced by an 'elif') Modified Paths: -------------- trunk/epydoc/src/epydoc/docwriter/html_colorize.py Modified: trunk/epydoc/src/epydoc/docwriter/html_colorize.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_colorize.py 2007-02-07 07:34:49 UTC (rev 1442) +++ trunk/epydoc/src/epydoc/docwriter/html_colorize.py 2007-02-08 04:17:45 UTC (rev 1443) @@ -1022,7 +1022,7 @@ raise if onclick: s += "</a></tt>" - if url: s += '</a>' + elif url: s += '</a>' elif css_class_html or tooltip_html: s += '</tt>' if self.ADD_DEF_BLOCKS: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-07 07:34:51
|
Revision: 1442 http://svn.sourceforge.net/epydoc/?rev=1442&view=rev Author: edloper Date: 2007-02-06 23:34:49 -0800 (Tue, 06 Feb 2007) Log Message: ----------- - Finished an update to the html_css file that was started a while ago but never finished. Now colors can be set from the template using a dictionary. Modified Paths: -------------- trunk/epydoc/src/epydoc/docwriter/html_css.py Modified: trunk/epydoc/src/epydoc/docwriter/html_css.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-02-07 07:30:25 UTC (rev 1441) +++ trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-02-07 07:34:49 UTC (rev 1442) @@ -59,9 +59,9 @@ * either class='epydoc' or class='toc' (CSS styles for both * defined below). */ -body { background: #ffffff; color: #000000; } -a:link { color: #0000ff; } -a:visited { color: #204080; } +body { background: $body_bg; color: $body_fg; } +a:link { color: $body_link; } +a:visited { color: $body_visited_link; } dt { font-weight: bold; } h1 { font-size: +140%; font-style: italic; font-weight: bold; } @@ -86,14 +86,14 @@ h3.epydoc { font-size: +115%; font-weight: bold; } td h3.epydoc { font-size: +115%; font-weight: bold; margin-bottom: 0; } -table.navbar { background: #a0c0ff; color: #000000; - border: 2px groove #c0d0d0; } -table.navbar table { color: #000000; } -th.navbar-select { background: #70b0ff; - color: #000000; } +table.navbar { background: $navbar_bg; color: $navbar_fg; + border: $navbar_border; } +table.navbar table { color: $navbar_fg; } +th.navbar-select { background: $navbar_select_bg; + color: $navbar_select_fg; } table.navbar a { text-decoration: none; } -table.navbar a:link { color: #0000ff; } -table.navbar a:visited { color: #204080; } +table.navbar a:link { color: $navbar_link; } +table.navbar a:visited { color: $navbar_visited_link; } span.breadcrumbs { font-size: 85%; font-weight: bold; } span.options { font-size: 70%; } span.codelink { font-size: 85%; } @@ -107,16 +107,16 @@ * - Summary tables that contain user-defined groups mark those * groups using 'group header' rows. */ -td.table-header { background: #70b0ff; color: #000000; - border: 1px solid #608090; } -td.table-header table { color: #000000; } -td.table-header table a:link { color: #0000ff; } -td.table-header table a:visited { color: #204080; } +td.table-header { background: $table_hdr_bg; color: $table_hdr_fg; + border: $table_border; } +td.table-header table { color: $table_hdr_fg; } +td.table-header table a:link { color: $table_hdr_link; } +td.table-header table a:visited { color: $table_hdr_visited_link; } span.table-header { font-size: 120%; font-weight: bold; } -th.group-header { background: #c0e0f8; color: #000000; +th.group-header { background: $group_hdr_bg; color: $group_hdr_fg; text-align: left; font-style: italic; font-size: 115%; - border: 1px solid #608090; } + border: $table_border; } /* Summary Tables (functions, variables, etc) * - Each object is described by a single row of the table with @@ -127,12 +127,12 @@ * defined above, under 'Table Headers' */ table.summary { border-collapse: collapse; - background: #e8f0f8; color: #000000; - border: 1px solid #608090; } -td.summary { border: 1px solid #608090; } + background: $table_bg; color: $table_fg; + border: $table_border; } +td.summary { border: $table_border; } code.summary-type { font-size: 85%; } -table.summary a:link { color: #0000ff; } -table.summary a:visited { color: #204080; } +table.summary a:link { color: $table_link; } +table.summary a:visited { color: $table_visited_link; } /* Details Tables (functions, variables, etc) @@ -142,12 +142,12 @@ * is defined above, under 'Table Headers'). */ table.details { border-collapse: collapse; - background: #e8f0f8; color: #000000; - border: 1px solid #608090; + background: $table_bg; color: $table_fg; + border: $table_border; margin: .2em 0 0 0; } -table.details table { color: #000000; } -table.details a:link { color: #0000ff; } -table.details a:visited { color: #204080; } +table.details table { color: $table_fg; } +table.details a:link { color: $table_link; } +table.details a:visited { color: $table_visited_link; } /* Index tables (identifier index, term index, etc) * - link-index is used for indices containing lists of links @@ -158,34 +158,34 @@ * extracted from fields (namely, the bug index & todo index). */ table.link-index { border-collapse: collapse; - background: #e8f0f8; color: #000000; - border: 1px solid #608090; } + background: $table_bg; color: $table_fg; + border: $table_border; } td.link-index { border-width: 0px; } -table.link-index a:link { color: #0000ff; } -table.link-index a:visited { color: #204080; } +table.link-index a:link { color: $table_link; } +table.link-index a:visited { color: $table_visited_link; } span.index-where { font-size: 70%; } table.metadata-index { border-collapse: collapse; - background: #e8f0f8; color: #000000; - border: 1px solid #608090; + background: $table_bg; color: $table_fg; + border: $table_border; margin: .2em 0 0 0; } td.metadata-index { border-width: 1px; border-style: solid; } -table.metadata-index a:link { color: #0000ff; } -table.metadata-index a:visited { color: #204080; } +table.metadata-index a:link { color: $table_link; } +table.metadata-index a:visited { color: $table_visited_link; } /* Function signatures * - sig* is used for the signature in the details section. * - .summary-sig* is used for the signature in the summary * table, and when listing property accessor functions. * */ -.sig-name { color: #006080; } -.sig-arg { color: #008060; } -.sig-default { color: #602000; } +.sig-name { color: $sig_name; } +.sig-arg { color: $sig_arg; } +.sig-default { color: $sig_default; } .summary-sig { font-family: monospace; } -.summary-sig-name { color: #006080; font-weight: bold; } -a.summary-sig-name:link { color: #006080; font-weight: bold; } -a.summary-sig-name:visited { color: #006080; font-weight: bold; } -.summary-sig-arg { color: #006040; } -.summary-sig-default { color: #501800; } +.summary-sig-name { color: $summary_sig_name; font-weight: bold; } +a.summary-sig-name:link { color: $summary_sig_name; font-weight: bold; } +a.summary-sig-name:visited { color: $summary_sig_name; font-weight: bold; } +.summary-sig-arg { color: $summary_sig_arg; } +.summary-sig-default { color: $summary_sig_default; } /* Variable values * - In the 'variable details' sections, each varaible's value is @@ -201,16 +201,16 @@ * the re* CSS classes. */ pre.variable { padding: .5em; margin: 0; - background: #dce4ec; color: #000000; - border: 1px solid #708890; } -.variable-linewrap { color: #604000; font-weight: bold; } -.variable-ellipsis { color: #604000; font-weight: bold; } -.variable-quote { color: #604000; font-weight: bold; } -.re { color: #000000; } -.re-char { color: #006030; } -.re-op { color: #600000; } -.re-group { color: #003060; } -.re-ref { color: #404040; } + background: $variable_bg; color: $variable_fg; + border: $variable_border; } +.variable-linewrap { color: $variable_linewrap; font-weight: bold; } +.variable-ellipsis { color: $variable_ellipsis; font-weight: bold; } +.variable-quote { color: $variable_quote; font-weight: bold; } +.re { color: $re; } +.re-char { color: $re_char; } +.re-op { color: $re_op; } +.re-group { color: $re_group; } +.re-ref { color: $re_ref; } /* Base tree * - Used by class pages to display the base class hierarchy. @@ -249,36 +249,38 @@ * etc.) */ pre.py-doctest { padding: .5em; margin: 1em; - background: #e8f0f8; color: #000000; - border: 1px solid #708890; } -table pre.py-doctest { background: #dce4ec; - color: #000000; } -pre.py-src { border: 2px solid #000000; - background: #f0f0f0; color: #000000; } -.py-line { border-left: 2px solid #000000; + background: $doctest_bg; color: $doctest_fg; + border: $doctest_border; } +table pre.py-doctest { background: $doctest_in_table_bg; + color: $doctest_in_table_fg; } +pre.py-src { border: $pysrc_border; + background: $pysrc_bg; color: $pysrc_fg; } +.py-line { border-left: $pysrc_sep_border; margin-left: .2em; padding-left: .4em; } .py-lineno { font-style: italic; font-size: 90%; padding-left: .5em; } a.py-toggle { text-decoration: none; } -div.py-highlight-hdr { border-top: 2px solid #000000; - border-bottom: 2px solid #000000; - background: #d8e8e8; } -div.py-highlight { border-bottom: 2px solid #000000; - background: #d0e0e0; } -.py-prompt { color: #005050; font-weight: bold;} -.py-string { color: #006030; } -.py-comment { color: #003060; } -.py-keyword { color: #600000; } -.py-output { color: #404040; } -.py-name { color: #000050; } -.py-name:link { color: #000050; } -.py-name:visited { color: #000050; } -.py-number { color: #005000; } -.py-def-name { color: #000060; font-weight: bold; } -.py-base-class { color: #000060; } -.py-param { color: #000060; } -.py-docstring { color: #006030; } -.py-decorator { color: #804020; } +div.py-highlight-hdr { border-top: $pysrc_border; + border-bottom: $pysrc_border; + background: $pysrc_highlight_hdr_bg; } +div.py-highlight { border-bottom: $pysrc_border; + background: $pysrc_highlight_bg; } +.py-prompt { color: $py_prompt; font-weight: bold;} +.py-more { color: $py_more; font-weight: bold;} +.py-string { color: $py_string; } +.py-comment { color: $py_comment; } +.py-keyword { color: $py_keyword; } +.py-output { color: $py_output; } +.py-name { color: $py_name; } +.py-name:link { color: $py_name; } +.py-name:visited { color: $py_name; } +.py-number { color: $py_number; } +.py-defname { color: $py_def_name; font-weight: bold; } +.py-def-name { color: $py_def_name; font-weight: bold; } +.py-base-class { color: $py_base_class; } +.py-param { color: $py_param; } +.py-docstring { color: $py_docstring; } +.py-decorator { color: $py_decorator; } /* Use this if you don't want links to names underlined: */ /*a.py-name { text-decoration: none; }*/ @@ -289,7 +291,7 @@ * clickable). */ img.graph-without-title { border: none; } -img.graph-with-title { border: 1px solid #000000; } +img.graph-with-title { border: $graph_border; } span.graph-title { font-weight: bold; } span.graph-caption { } @@ -396,6 +398,7 @@ pysrc_highlight_hdr_bg = '#d8e8e8', pysrc_highlight_bg = '#d0e0e0', py_prompt = '#005050', + py_more = '#005050', py_string = '#006030', py_comment = '#003060', py_keyword = '#600000', @@ -445,7 +448,6 @@ _WHITE = _set_colors(TEMPLATE, _WHITE_COLORS) _BLUE = _set_colors(TEMPLATE, _BLUE_COLORS) -_WHITE = _BLUE # Black-on-green _GREEN = _COLOR_RE.sub(_darken_darks, _COLOR_RE.sub(r'#\1\3\2', _BLUE)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-07 07:30:27
|
Revision: 1441 http://svn.sourceforge.net/epydoc/?rev=1441&view=rev Author: edloper Date: 2007-02-06 23:30:25 -0800 (Tue, 06 Feb 2007) Log Message: ----------- - Added \pysrcdefname command (necessary after previous checkin to markup/doctest.py) Modified Paths: -------------- trunk/epydoc/src/epydoc/docwriter/latex.py Modified: trunk/epydoc/src/epydoc/docwriter/latex.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/latex.py 2007-02-07 06:37:21 UTC (rev 1440) +++ trunk/epydoc/src/epydoc/docwriter/latex.py 2007-02-07 07:30:25 UTC (rev 1441) @@ -55,6 +55,7 @@ "\\definecolor{py@inputcolour}{rgb}{0,0,0}", "\\definecolor{py@outputcolour}{rgb}{0,0,1}", "\\definecolor{py@exceptcolour}{rgb}{1,0,0}", + "\\definecolor{py@defnamecolour}{rgb}{1,0.5,0.5}", "\\definecolor{py@builtincolour}{rgb}{0.58039,0,0.58039}", "\\definecolor{py@identifiercolour}{rgb}{0,0,0}", "\\definecolor{py@linenumcolour}{rgb}{0.4,0.4,0.4}", @@ -71,6 +72,8 @@ "{\\small\\textbf{#1}}}", "\\newcommand{\\pysrcstring}[1]{\\textcolor{py@stringcolour}" "{\\small\\textbf{#1}}}", + "\\newcommand{\\pysrcdefname}[1]{\\textcolor{py@defnamecolour}" + "{\\small\\textbf{#1}}}", "\\newcommand{\\pysrcother}[1]{\\small\\textbf{#1}}", "% Comments", "\\newcommand{\\pysrccomment}[1]{\\textcolor{py@commentcolour}" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-07 06:37:26
|
Revision: 1440 http://svn.sourceforge.net/epydoc/?rev=1440&view=rev Author: edloper Date: 2007-02-06 22:37:21 -0800 (Tue, 06 Feb 2007) Log Message: ----------- - Improved/refactored version of doctest colorizer. Modified Paths: -------------- trunk/epydoc/src/epydoc/markup/doctest.py Modified: trunk/epydoc/src/epydoc/markup/doctest.py =================================================================== --- trunk/epydoc/src/epydoc/markup/doctest.py 2007-02-07 06:21:26 UTC (rev 1439) +++ trunk/epydoc/src/epydoc/markup/doctest.py 2007-02-07 06:37:21 UTC (rev 1440) @@ -19,176 +19,292 @@ import re from epydoc.util import plaintext_to_html, plaintext_to_latex +__all__ = ['doctest_to_html', 'doctest_to_latex', + 'DoctestColorizer', 'XMLDoctestColorizer', + 'HTMLDoctestColorizer', 'LaTeXDoctestColorizer'] + def doctest_to_html(s): """ Perform syntax highlighting on the given doctest string, and return the resulting HTML code. This code consists of a C{<pre>} block with class=py-doctest. Syntax highlighting is performed - using the following css classes: 'py-prompt', 'py-keyword', - 'py-string', 'py-comment', and 'py-output'. + using the following css classes: + + - C{py-prompt} -- the Python PS1 prompt (>>>) + - C{py-more} -- the Python PS2 prompt (...) + - C{py-keyword} -- a Python keyword (for, if, etc.) + - C{py-builtin} -- a Python builtin name (abs, dir, etc.) + - C{py-string} -- a string literal + - C{py-comment} -- a comment + - C{py-except} -- an exception traceback (up to the next >>>) + - C{py-output} -- the output from a doctest block. + - C{py-defname} -- the name of a function or class defined by + a C{def} or C{class} statement. """ - return ('<pre class="py-doctest">\n%s\n</pre>\n' % - colorize_doctest(s, _tag_span_html).strip()) + return HTMLDoctestColorizer().colorize_doctest(s) def doctest_to_latex(s): """ Perform syntax highlighting on the given doctest string, and return the resulting LaTeX code. This code consists of an - C{alltt} environment. Syntax highlighting is performed using five - new latex commands, which must be defined externally: - '\pysrcprompt', '\pysrckeyword', '\pysrcstring', '\pysrccomment', - and '\pysrcoutput'. + C{alltt} environment. Syntax highlighting is performed using + the following new latex commands, which must be defined externally: + - C{\pysrcprompt} -- the Python PS1 prompt (>>>) + - C{\pysrcmore} -- the Python PS2 prompt (...) + - C{\pysrckeyword} -- a Python keyword (for, if, etc.) + - C{\pysrcbuiltin} -- a Python builtin name (abs, dir, etc.) + - C{\pysrcstring} -- a string literal + - C{\pysrccomment} -- a comment + - C{\pysrcexcept} -- an exception traceback (up to the next >>>) + - C{\pysrcoutput} -- the output from a doctest block. + - C{\pysrcdefname} -- the name of a function or class defined by + a C{def} or C{class} statement. """ - return ('\\begin{alltt}\n%s\n\\end{alltt}\n' % - colorize_doctest(s, _tag_span_latex).strip()) + return LaTeXDoctestColorizer().colorize_doctest(s) -def _tag_span_html(s, tag): - return '<span class="py-%s">%s</span>' % (tag, plaintext_to_html(s)) +class DoctestColorizer: + """ + An abstract base class for performing syntax highlighting on + doctest blocks and other bits of Python code. Subclasses should + provide definitions for: -def _tag_span_latex(s, tag): - return '\\pysrc%s{%s}' % (tag, plaintext_to_latex(s)) + - The L{markup()} method, which takes a substring and a tag, and + returns a colorized version of the substring. + - The L{PREFIX} and L{SUFFIX} variables, which will be added + to the beginning and end of the strings returned by + L{colorize_codeblock} and L{colorize_doctest}. + """ -# Regular expressions for colorize_doctestblock -# set of keywords as listed in the Python Language Reference 2.4.1 -# added 'as' as well since IDLE already colorizes it as a keyword. -# The documentation states that 'None' will become a keyword -# eventually, but IDLE currently handles that as a builtin. -_KEYWORDS = """ -and del for is raise -assert elif from lambda return -break else global not try -class except if or while -continue exec import pass yield -def finally in print -as -""".split() -_KEYWORD = '|'.join([r'\b%s\b' % _KW for _KW in _KEYWORDS]) + #: A string that is added to the beginning of the strings + #: returned by L{colorize_codeblock} and L{colorize_doctest}. + #: Typically, this string begins a preformatted area. + PREFIX = None -_BUILTINS = [_BI for _BI in dir(__builtins__) if not _BI.startswith('__')] -_BUILTIN = '|'.join([r'\b%s\b' % _BI for _BI in _BUILTINS]) + #: A string that is added to the end of the strings + #: returned by L{colorize_codeblock} and L{colorize_doctest}. + #: Typically, this string ends a preformatted area. + SUFFIX = None -_STRING = '|'.join([r'("""("""|.*?((?!").)"""))', r'("("|.*?((?!").)"))', - r"('''('''|.*?[^\\']'''))", r"('('|.*?[^\\']'))"]) -_COMMENT = '(#.*?$)' -_PROMPT1 = r'^\s*>>>(?:\s|$)' -_PROMPT2 = r'^\s*\.\.\.(?:\s|$)' + #: A list of the names of all Python keywords. ('as' is included + #: even though it is technically not a keyword.) + _KEYWORDS = ("and del for is raise" + "assert elif from lambda return" + "break else global not try" + "class except if or while" + "continue exec import pass yield" + "def finally in print as").split() -PROMPT_RE = re.compile('(%s|%s)' % (_PROMPT1, _PROMPT2), - re.MULTILINE | re.DOTALL) -PROMPT2_RE = re.compile('(%s)' % _PROMPT2, re.MULTILINE | re.DOTALL) -'''The regular expression used to find Python prompts (">>>" and -"...") in doctest blocks.''' + #: A list of all Python builtins. + _BUILTINS = [_BI for _BI in dir(__builtins__) + if not _BI.startswith('__')] -EXCEPT_RE = re.compile(r'(.*)(^Traceback \(most recent call last\):.*)', - re.DOTALL | re.MULTILINE) + #: A regexp group that matches keywords. + _KEYWORD_GRP = '|'.join([r'\b%s\b' % _KW for _KW in _KEYWORDS]) -DOCTEST_DIRECTIVE_RE = re.compile(r'#\s*doctest:.*') + #: A regexp group that matches Python builtins. + _BUILTIN_GRP = (r'(?<!\.)(?:%s)' % '|'.join([r'\b%s\b' % _BI + for _BI in _BUILTINS])) -DOCTEST_RE = re.compile(r"""(?P<STRING>%s)|(?P<COMMENT>%s)|""" - r"""(?P<KEYWORD>(%s))|(?P<BUILTIN>(%s))|""" - r"""(?P<PROMPT1>%s)|(?P<PROMPT2>%s)|.+?""" % - (_STRING, _COMMENT, _KEYWORD, _BUILTIN, _PROMPT1, _PROMPT2), - re.MULTILINE | re.DOTALL) -'''The regular expression used by L{_doctest_sub} to colorize doctest -blocks.''' + #: A regexp group that matches Python strings. + _STRING_GRP = '|'.join( + [r'("""("""|.*?((?!").)"""))', r'("("|.*?((?!").)"))', + r"('''('''|.*?[^\\']'''))", r"('('|.*?[^\\']'))"]) -def colorize_doctest(s, markup_func, inline=False, strip_directives=False): - """ - Colorize the given doctest string C{s} using C{markup_func()}. - C{markup_func()} should be a function that takes a substring and a - tag, and returns a colorized version of the substring. E.g.: + #: A regexp group that matches Python comments. + _COMMENT_GRP = '(#.*?$)' - >>> def html_markup_func(s, tag): - ... return '<span class="%s">%s</span>' % (tag, s) + #: A regexp group that matches Python ">>>" prompts. + _PROMPT1_GRP = r'^[ \t]*>>>(?:[ \t]|$)' + + #: A regexp group that matches Python "..." prompts. + _PROMPT2_GRP = r'^[ \t]*\.\.\.(?:[ \t]|$)' - The tags that will be passed to the markup function are: - - C{prompt} -- the Python PS1 prompt (>>>) - - C{more} -- the Python PS2 prompt (...) - - C{keyword} -- a Python keyword (for, if, etc.) - - C{builtin} -- a Python builtin name (abs, dir, etc.) - - C{string} -- a string literal - - C{comment} -- a comment - - C{except} -- an exception traceback (up to the next >>>) - - C{output} -- the output from a doctest block. - - C{other} -- anything else (does *not* include output.) - """ - pysrc = [] # the source code part of a docstest block (lines) - pyout = [] # the output part of a doctest block (lines) - result = [] - out = result.append + #: A regexp group that matches function and class definitions. + _DEFINE_GRP = r'\b(?:def|class)[ \t]+\w+' - if strip_directives: - s = DOCTEST_DIRECTIVE_RE.sub('', s) + #: A regexp that matches Python prompts + PROMPT_RE = re.compile('(%s|%s)' % (_PROMPT1_GRP, _PROMPT2_GRP), + re.MULTILINE | re.DOTALL) - def subfunc(match): + #: A regexp that matches Python "..." prompts. + PROMPT2_RE = re.compile('(%s)' % _PROMPT2_GRP, + re.MULTILINE | re.DOTALL) + + #: A regexp that matches doctest exception blocks. + EXCEPT_RE = re.compile(r'^[ \t]*Traceback \(most recent call last\):.*', + re.DOTALL | re.MULTILINE) + + #: A regexp that matches doctest directives. + DOCTEST_DIRECTIVE_RE = re.compile(r'#[ \t]*doctest:.*') + + #: A regexp that matches all of the regions of a doctest block + #: that should be colored. + DOCTEST_RE = re.compile( + r'(.*?)((?P<STRING>%s)|(?P<COMMENT>%s)|(?P<DEFINE>%s)|' + r'(?P<KEYWORD>%s)|(?P<BUILTIN>%s)|' + r'(?P<PROMPT1>%s)|(?P<PROMPT2>%s)|(?P<EOS>\Z))' % ( + _STRING_GRP, _COMMENT_GRP, _DEFINE_GRP, _KEYWORD_GRP, _BUILTIN_GRP, + _PROMPT1_GRP, _PROMPT2_GRP), re.MULTILINE | re.DOTALL) + + #: This regular expression is used to find doctest examples in a + #: string. This is copied from the standard Python doctest.py + #: module (after the refactoring in Python 2.4+). + DOCTEST_EXAMPLE_RE = re.compile(r''' + # Source consists of a PS1 line followed by zero or more PS2 lines. + (?P<source> + (?:^(?P<indent> [ ]*) >>> .*) # PS1 line + (?:\n [ ]* \.\.\. .*)* # PS2 lines + \n?) + # Want consists of any non-blank lines that do not start with PS1. + (?P<want> (?:(?![ ]*$) # Not a blank line + (?![ ]*>>>) # Not a line starting with PS1 + .*$\n? # But any other line + )*) + ''', re.MULTILINE | re.VERBOSE) + + def colorize_inline(self, s): + """ + Colorize a string containing Python code. Do not add the + L{PREFIX} and L{SUFFIX} strings to the returned value. This + method is intended for generating syntax-highlighted strings + that are appropriate for inclusion as inline expressions. + """ + return self.DOCTEST_RE.sub(self.subfunc, s) + + def colorize_codeblock(self, s): + """ + Colorize a string containing only Python code. This method + differs from L{colorize_doctest} in that it will not search + for doctest prompts when deciding how to colorize the string. + """ + body = self.DOCTEST_RE.sub(self.subfunc, s) + return self.PREFIX + body + self.SUFFIX + + def colorize_doctest(self, s, strip_directives=False): + """ + Colorize a string containing one or more doctest examples. + """ + output = [] + charno = 0 + for m in self.DOCTEST_EXAMPLE_RE.finditer(s): + # Parse the doctest example: + pysrc, want = m.group('source', 'want') + # Pre-example text: + output.append(s[charno:m.start()]) + # Example source code: + output.append(self.DOCTEST_RE.sub(self.subfunc, pysrc)) + # Example output: + if want: + if self.EXCEPT_RE.match(want): + output += [self.markup(line, 'except')+'\n' + for line in want.split('\n')] + else: + output += [self.markup(line, 'output')+'\n' + for line in want.split('\n')] + # Update charno + charno = m.end() + # Add any remaining post-example text. + output.append(s[charno:]) + + return self.PREFIX + ''.join(output) + self.SUFFIX + + def subfunc(self, match): + other, text = match.group(1, 2) + #print 'M %20r %20r' % (other, text) # <- for debugging + if other: + other = '\n'.join([self.markup(line, 'other') + for line in other.split('\n')]) + if match.group('PROMPT1'): - return markup_func(match.group(), 'prompt') - if match.group('PROMPT2'): - return markup_func(match.group(), 'more') - if match.group('KEYWORD'): - return markup_func(match.group(), 'keyword') - if match.group('BUILTIN'): - return markup_func(match.group(), 'builtin') - if match.group('COMMENT'): - return markup_func(match.group(), 'comment') - if match.group('STRING') and '\n' not in match.group(): - return markup_func(match.group(), 'string') + return other + self.markup(text, 'prompt') + elif match.group('PROMPT2'): + return other + self.markup(text, 'more') + elif match.group('KEYWORD'): + return other + self.markup(text, 'keyword') + elif match.group('BUILTIN'): + return other + self.markup(text, 'builtin') + elif match.group('COMMENT'): + return other + self.markup(text, 'comment') + elif match.group('STRING') and '\n' not in text: + return other + self.markup(text, 'string') elif match.group('STRING'): # It's a multiline string; colorize the string & prompt # portion of each line. - pieces = [markup_func(s, ['string','more'][i%2]) - for i, s in enumerate(PROMPT2_RE.split(match.group()))] - return ''.join(pieces) + pieces = [] + for line in text.split('\n'): + if self.PROMPT2_RE.match(line): + if len(line) > 4: + pieces.append(self.markup(line[:4], 'more') + + self.markup(line[4:], 'string')) + else: + pieces.append(self.markup(line[:4], 'more')) + elif line: + pieces.append(self.markup(line, 'string')) + else: + pieces.append('') + return other + '\n'.join(pieces) + elif match.group('DEFINE'): + m = re.match('(?P<def>\w+)(?P<space>\s+)(?P<name>\w+)', text) + return other + (self.markup(m.group('def'), 'keyword') + + self.markup(m.group('space'), 'other') + + self.markup(m.group('name'), 'defname')) + elif match.group('EOS') is not None: + return other else: - return markup_func(match.group(), 'other') + assert 0, 'Unexpected match!' - if inline: - pysrc = DOCTEST_RE.sub(subfunc, s) - return pysrc.strip() + def markup(self, s, tag): + """ + Apply syntax highlighting to a single substring from a doctest + block. C{s} is the substring, and C{tag} is the tag that + should be applied to the substring. C{tag} will be one of the + following strings: + + - C{prompt} -- the Python PS1 prompt (>>>) + - C{more} -- the Python PS2 prompt (...) + - C{keyword} -- a Python keyword (for, if, etc.) + - C{builtin} -- a Python builtin name (abs, dir, etc.) + - C{string} -- a string literal + - C{comment} -- a comment + - C{except} -- an exception traceback (up to the next >>>) + - C{output} -- the output from a doctest block. + - C{defname} -- the name of a function or class defined by + a C{def} or C{class} statement. + - C{other} -- anything else (does *not* include output.) + """ + raise AssertionError("Abstract method") - # need to add a third state here for correctly formatting exceptions +class XMLDoctestColorizer(DoctestColorizer): + """ + A subclass of DoctestColorizer that generates XML-like output. + This class is mainly intended to be used for testing purposes. + """ + PREFIX = '<colorized>\n' + SUFFIX = '</colorized>\n' + def markup(self, s, tag): + s = s.replace('&', '&').replace('<', '<').replace('>', '>') + if tag == 'other': return s + else: return '<%s>%s</%s>' % (tag, s, tag) - for line in s.split('\n')+['\n']: - if PROMPT_RE.match(line): - pysrc.append(line) - if pyout: - pyout = '\n'.join(pyout).strip() - m = EXCEPT_RE.match(pyout) - if m: - pyout, pyexc = m.group(1).strip(), m.group(2).strip() - if pyout: - print ('Warning: doctest does not allow for mixed ' - 'output and exceptions!') - result.append(markup_func(pyout, 'output')) - result.append(markup_func(pyexc, 'except')) - else: - result.append(markup_func(pyout, 'output')) - pyout = [] +class HTMLDoctestColorizer(DoctestColorizer): + """A subclass of DoctestColorizer that generates HTML output.""" + PREFIX = '<pre class="py-doctest">\n' + SUFFIX = '</pre>\n' + def markup(self, s, tag): + if tag == 'other': + return plaintext_to_html(s) else: - pyout.append(line) - if pysrc: - pysrc = DOCTEST_RE.sub(subfunc, '\n'.join(pysrc)) - result.append(pysrc.strip()) - #result.append(markup_func(pysrc.strip(), 'python')) - pysrc = [] + return ('<span class="py-%s">%s</span>' % + (tag, plaintext_to_html(s))) - remainder = '\n'.join(pyout).strip() - if remainder: - result.append(markup_func(remainder, 'output')) - result = '\n'.join(result) +class LaTeXDoctestColorizer(DoctestColorizer): + """A subclass of DoctestColorizer that generates LaTeX output.""" + PREFIX = '\\begin{alltt}\n' + SUFFIX = '\\end{alltt}\n' + def markup(self, s, tag): + if tag == 'other': + return plaintext_to_latex(s) + else: + return '\\pysrc%s{%s}' % (tag, plaintext_to_latex(s)) - # Merge adjacent spans w/ the same class. I.e, convert: - # <span class="x">foo</span><span class="x">foo</span> - # to: - # <span class="x">foofoo</span> - prev_span_class = [None] - def subfunc(match): - if match.group(2) == prev_span_class[0]: - prev_span_class[0] = match.group(2) - return match.group(1) or '' - else: - prev_span_class[0] = match.group(2) - return match.group() - result = re.sub(r'</span>(\n?)<span class="([^"]+)">', subfunc, result) - return result This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-07 06:21:34
|
Revision: 1439 http://svn.sourceforge.net/epydoc/?rev=1439&view=rev Author: edloper Date: 2007-02-06 22:21:26 -0800 (Tue, 06 Feb 2007) Log Message: ----------- Fixed bug where function summaries generated from return value fields would have incorrect capitalization (eg "Returns An apple") by adding a colon to make it "Returns: An apple". (sf bug #1551471) Modified Paths: -------------- trunk/epydoc/src/epydoc/docstringparser.py Modified: trunk/epydoc/src/epydoc/docstringparser.py =================================================================== --- trunk/epydoc/src/epydoc/docstringparser.py 2007-02-06 13:40:13 UTC (rev 1438) +++ trunk/epydoc/src/epydoc/docstringparser.py 2007-02-07 06:21:26 UTC (rev 1439) @@ -437,7 +437,7 @@ # End the message block. log.end_block() -RETURN_PDS = markup.parse('Returns', markup='epytext') +RETURN_PDS = markup.parse('Returns:', markup='epytext') """A ParsedDocstring containing the text 'Returns'. This is used to construct summary descriptions for routines that have empty C{descr}, but non-empty C{return_descr}.""" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-02-06 13:40:22
|
Revision: 1438 http://svn.sourceforge.net/epydoc/?rev=1438&view=rev Author: dvarrazzo Date: 2007-02-06 05:40:13 -0800 (Tue, 06 Feb 2007) Log Message: ----------- - Added an anchor for each source code line The anchor has the form "Ln" where n is the line number without leading 0's. Modified Paths: -------------- trunk/epydoc/src/epydoc/docwriter/html_colorize.py Modified: trunk/epydoc/src/epydoc/docwriter/html_colorize.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_colorize.py 2007-02-05 02:37:15 UTC (rev 1437) +++ trunk/epydoc/src/epydoc/docwriter/html_colorize.py 2007-02-06 13:40:13 UTC (rev 1438) @@ -709,7 +709,8 @@ def lineno_to_html(self): template = '%%%ds' % self.linenum_size n = template % self.lineno - return '<tt class="py-lineno">%s</tt>' % n + return '<a name="L%s" /><tt class="py-lineno">%s</tt>' \ + % (self.lineno, n) def colorize(self): """ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |