Thread: [Epydoc-commits] SF.net SVN: epydoc: [1460] trunk/epydoc/src/epydoc (Page 2)
Brought to you by:
edloper
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-12 05:26:30
|
Revision: 1463 http://svn.sourceforge.net/epydoc/?rev=1463&view=rev Author: edloper Date: 2007-02-11 21:26:28 -0800 (Sun, 11 Feb 2007) Log Message: ----------- - Added a new module for colorizing python values. This abstracts away from the code that's currently in the html writer, and should make it easier to use the same colorization code for other docwriters. The new code should do a better job of pretty-printing values than the current html writer code. I also fixed a couple minor bugs in the regexp colorizer along the way. Note, though, that this code hasn't been plugged into epydoc in any way yet. I.e., docwriter/html.py still needs to be modified to actually *use* this new code. Added Paths: ----------- trunk/epydoc/src/epydoc/markup/pyval_repr.py trunk/epydoc/src/epydoc/test/pyval_repr.doctest Added: trunk/epydoc/src/epydoc/markup/pyval_repr.py =================================================================== --- trunk/epydoc/src/epydoc/markup/pyval_repr.py (rev 0) +++ trunk/epydoc/src/epydoc/markup/pyval_repr.py 2007-02-12 05:26:28 UTC (rev 1463) @@ -0,0 +1,478 @@ +# epydoc -- Marked-up Representations for Python Values +# +# Copyright (C) 2005 Edward Loper +# Author: Edward Loper <ed...@lo...> +# URL: <http://epydoc.sf.net> +# +# $Id: apidoc.py 1448 2007-02-11 00:05:34Z dvarrazzo $ + +""" +Syntax highlighter for Python values. Currently provides special +colorization support for: + + - lists, tuples, sets, frozensets, dicts + - numbers + - strings + - compiled regexps + +The highlighter also takes care of line-wrapping, and automatically +stops generating repr output as soon as it has exceeded the specified +number of lines (which should make it faster than pprint for large +values). It does I{not} bother to do automatic cycle detection, +because maxlines is typically around 5, so it's really not worth it. +""" + +# Implementation note: we use exact tests for classes (list, etc) +# rather than using isinstance, because subclasses might override +# __repr__. + +import types, re +import epydoc.apidoc +from epydoc.util import decode_with_backslashreplace +from epydoc.compat import * +import sre_parse, sre_constants + +def is_re_pattern(pyval): + return type(pyval).__name__ == 'SRE_Pattern' + +class _ColorizerState: + """ + An object uesd to keep track of the current state of the pyval + colorizer. The L{mark()}/L{restore()} methods can be used to set + a backup point, and restore back to that backup point. This is + used by several colorization methods that first try colorizing + their object on a single line (setting linebreakok=False); and + then fall back on a multi-line output if that fails. + """ + def __init__(self): + self.result = [] + self.charpos = 0 + self.lineno = 1 + self.linebreakok = True + + def mark(self): + return (len(self.result), self.charpos, self.lineno, self.linebreakok) + + def restore(self, mark): + n, self.charpos, self.lineno, self.linebreakok = mark + del self.result[n:] + +class _Maxlines(Exception): + """A control-flow exception that is raised when PyvalColorizer + exeeds the maximum number of allowed lines.""" + +class _Linebreak(Exception): + """A control-flow exception that is raised when PyvalColorizer + generates a string containing a newline, but the state object's + linebreakok variable is False.""" + + +class PyvalColorizer: + """ + Syntax highlighter for Python values. + """ + + def __init__(self, linelen=75, maxlines=5, sort=True): + self.linelen = linelen + self.maxlines = maxlines + self.sort = sort + + #//////////////////////////////////////////////////////////// + # Subclassing Hooks + #//////////////////////////////////////////////////////////// + + PREFIX = None + """A string sequence that should be added to the beginning of all + colorized pyval outputs.""" + + SUFFIX = None + """A string sequence that should be added to the beginning of all + colorized pyval outputs.""" + + NEWLINE = '\n' + """The string sequence that should be generated to encode newlines.""" + + LINEWRAP = None + """The string sequence that should be generated when linewrapping a + string that is too long to fit on a single line. (The + NEWLINE sequence will be added immediately after this sequence)""" + + ELLIPSIS = None + """The string sequence that should be generated when omitting the + rest of the repr because maxlines has been exceeded.""" + + def markup(self, s, tag=None): + """ + Apply syntax highlighting to a single substring from a Python + value representation. 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: + + - (list under construction) + """ + + #//////////////////////////////////////////////////////////// + # Colorization Tags + #//////////////////////////////////////////////////////////// + + GROUP_TAG = 'val-group' # e.g., "[" and "]" + COMMA_TAG = 'val-op' # The "," that separates elements + COLON_TAG = 'val-op' # The ":" in dictionaries + CONST_TAG = None # None, True, False + NUMBER_TAG = None # ints, floats, etc + QUOTE_TAG = 'val-quote' # Quotes around strings. + STRING_TAG = 'val-string' # Body of string literals + + RE_CHAR_TAG = None + RE_GROUP_TAG = 're-group' + RE_REF_TAG = 're-ref' + RE_OP_TAG = 're-op' + RE_FLAGS_TAG = 're-flags' + + #//////////////////////////////////////////////////////////// + # Entry Point + #//////////////////////////////////////////////////////////// + + def colorize(self, pyval): + # Create an object to keep track of the colorization. + state = _ColorizerState() + # Add the prefix string. + state.result.append(self.PREFIX) + # Colorize the value. If we reach maxlines, then add on an + # ellipsis marker and call it a day. + try: + self._colorize(pyval, state) + except _Maxlines: + state.result.append(self.ELLIPSIS) + # Add on the suffix string. + state.result.append(self.SUFFIX) + # Put it all together. + return ''.join(state.result) + + def _colorize(self, pyval, state): + pyval_type = type(pyval) + + if pyval is None or pyval is True or pyval is False: + self._output(str(pyval), self.CONST_TAG, state) + elif pyval_type in (int, float, long, types.ComplexType): + self._output(str(pyval), self.NUMBER_TAG, state) + elif pyval_type is str: + self._colorize_str(pyval, state, '', 'string-escape') + elif pyval_type is unicode: + self._colorize_str(pyval, state, 'u', 'unicode-escape') + elif pyval_type is list: + self._multiline(self._colorize_iter, pyval, state, '[', ']') + elif pyval_type is tuple: + self._multiline(self._colorize_iter, pyval, state, '(', ')') + elif pyval_type is set: + if self.sort: pyval = sorted(pyval) + self._multiline(self._colorize_iter, pyval, state, + 'set([', '])') + elif pyval_type is frozenset: + if self.sort: pyval = sorted(pyval) + self._multiline(self._colorize_iter, pyval, state, + 'frozenset([', '])') + elif pyval_type is dict: + items = pyval.items() + if self.sort: items = sorted(items) + self._multiline(self._colorize_dict, items, state, '{', '}') + elif is_re_pattern(pyval): + self._colorize_re(pyval, state) + else: + self._output(repr(pyval), None, state) + + #//////////////////////////////////////////////////////////// + # Object Colorization Functions + #//////////////////////////////////////////////////////////// + + def _multiline(self, func, pyval, state, *args): + """ + Helper for container-type colorizers. First, try calling + C{func(pyval, state, *args)} with linebreakok set to false; + and if that fails, then try again with it set to true. + """ + linebreakok = state.linebreakok + mark = state.mark() + + try: + state.linebreakok = False + func(pyval, state, *args) + state.linebreakok = linebreakok + + except _Linebreak: + if not linebreakok: + raise + state.restore(mark) + func(pyval, state, *args) + + def _colorize_iter(self, pyval, state, prefix, suffix): + self._output(prefix, self.GROUP_TAG, state) + indent = state.charpos + for i, elt in enumerate(pyval): + if i>=1: + if state.linebreakok: + self._output(',', self.COMMA_TAG, state) + self._output('\n'+' '*indent, None, state) + else: + self._output(', ', self.COMMA_TAG, state) + self._colorize(elt, state) + self._output(suffix, self.GROUP_TAG, state) + + def _colorize_dict(self, items, state, prefix, suffix): + self._output(prefix, self.GROUP_TAG, state) + indent = state.charpos + for i, (key, val) in enumerate(items): + if i>=1: + if state.linebreakok: + self._output(',', self.COMMA_TAG, state) + self._output('\n'+' '*indent, None, state) + else: + self._output(', ', self.COMMA_TAG, state) + self._colorize(key, state) + self._output(': ', self.COLON_TAG, state) + self._colorize(val, state) + self._output(suffix, self.GROUP_TAG, state) + + def _colorize_str(self, pyval, state, prefix, encoding): + # Decide which quote to use. + if '\n' in pyval: quote = "'''" + else: quote = "'" + # Open quote. + self._output(prefix+quote, self.QUOTE_TAG, state) + # Body + for i, line in enumerate(pyval.split('\n')): + if i>0: self._output('\n', None, state) + self._output(line.encode(encoding), self.STRING_TAG, state) + # Close quote. + self._output(quote, self.QUOTE_TAG, state) + + def _colorize_re(self, pyval, state): + # Extract the flag & pattern from the regexp. + pat, flags = pyval.pattern, pyval.flags + # If the pattern is a string, decode it to unicode. + if isinstance(pat, str): + pat = decode_with_backslashreplace(pat) + # Parse the regexp pattern. + tree = sre_parse.parse(pat, flags) + groups = dict([(num,name) for (name,num) in + tree.pattern.groupdict.items()]) + # Colorize it! + self._colorize_re_flags(tree.pattern.flags, state) + self._colorize_re_tree(tree, state, True, groups) + + def _colorize_re_flags(self, flags, state): + if flags: + flags = [c for (c,n) in sorted(sre_parse.FLAGS.items()) + if (n&flags)] + flags = '(?%s)' % ''.join(flags) + self._output(flags, self.RE_FLAGS_TAG, state) + + def _colorize_re_tree(self, tree, state, noparen, groups): + assert noparen in (True, False) + if len(tree) > 1 and not noparen: + self._output('(', self.RE_GROUP_TAG, state) + for elt in tree: + op = elt[0] + args = elt[1] + + if op == sre_constants.LITERAL: + c = unichr(args) + # Add any appropriate escaping. + if c in '.^$\\*+?{}[]|()': c = '\\'+c + elif c == '\t': c = '\\t' + elif c == '\r': c = '\\r' + elif c == '\n': c = '\\n' + elif c == '\f': c = '\\f' + elif c == '\v': c = '\\v' + elif ord(c) > 0xffff: c = r'\U%08x' % ord(c) + elif ord(c) > 0xff: c = r'\u%04x' % ord(c) + elif ord(c)<32 or ord(c)>=127: c = r'\x%02x' % ord(c) + self._output(c, self.RE_CHAR_TAG, state) + + elif op == sre_constants.ANY: + self._output('.', self.RE_CHAR_TAG, state) + + elif op == sre_constants.BRANCH: + if args[0] is not None: + raise ValueError('Branch expected None arg but got %s' + % args[0]) + for i, item in enumerate(args[1]): + if i > 0: + self._output('|', self.RE_OP_TAG, state) + self._colorize_re_tree(item, state, True, groups) + + elif op == sre_constants.IN: + if (len(args) == 1 and args[0][0] == sre_constants.CATEGORY): + self._colorize_re_tree(args, state, False, groups) + else: + self._output('[', self.RE_GROUP_TAG, state) + self._colorize_re_tree(args, state, True, groups) + self._output(']', self.RE_GROUP_TAG, state) + + elif op == sre_constants.CATEGORY: + if args == sre_constants.CATEGORY_DIGIT: val = r'\d' + elif args == sre_constants.CATEGORY_NOT_DIGIT: val = r'\D' + elif args == sre_constants.CATEGORY_SPACE: val = r'\s' + elif args == sre_constants.CATEGORY_NOT_SPACE: val = r'\S' + elif args == sre_constants.CATEGORY_WORD: val = r'\w' + elif args == sre_constants.CATEGORY_NOT_WORD: val = r'\W' + else: raise ValueError('Unknown category %s' % args) + self._output(val, self.RE_CHAR_TAG, state) + + elif op == sre_constants.AT: + if args == sre_constants.AT_BEGINNING_STRING: val = r'\A' + elif args == sre_constants.AT_BEGINNING: val = r'^' + elif args == sre_constants.AT_END: val = r'$' + elif args == sre_constants.AT_BOUNDARY: val = r'\b' + elif args == sre_constants.AT_NON_BOUNDARY: val = r'\B' + elif args == sre_constants.AT_END_STRING: val = r'\Z' + else: raise ValueError('Unknown position %s' % args) + self._output(val, self.RE_CHAR_TAG, state) + + elif op in (sre_constants.MAX_REPEAT, sre_constants.MIN_REPEAT): + minrpt = args[0] + maxrpt = args[1] + if maxrpt == sre_constants.MAXREPEAT: + if minrpt == 0: val = '*' + elif minrpt == 1: val = '+' + else: val = '{%d,}' % (minrpt) + elif minrpt == 0: + if maxrpt == 1: val = '?' + else: val = '{,%d}' % (maxrpt) + elif minrpt == maxrpt: + val = '{%d}' % (maxrpt) + else: + val = '{%d,%d}' % (minrpt, maxrpt) + if op == sre_constants.MIN_REPEAT: + val += '?' + + self._colorize_re_tree(args[2], state, False, groups) + self._output(val, self.RE_OP_TAG, state) + + elif op == sre_constants.SUBPATTERN: + if args[0] is None: + self._output('(?:', self.RE_GROUP_TAG, state) + elif args[0] in groups: + self._output('(?P<', self.RE_GROUP_TAG, state) + self._output(groups[args[0]], self.RE_REF_TAG, state) + self._output('>', self.RE_GROUP_TAG, state) + elif isinstance(args[0], (int, long)): + # This is cheating: + self._output('(', self.RE_GROUP_TAG, state) + else: + self._output('(?P<', self.RE_GROUP_TAG, state) + self._output(args[0], self.RE_REF_TAG, state) + self._output('>', self.RE_GROUP_TAG, state) + self._colorize_re_tree(args[1], state, True, groups) + self._output(')', self.RE_GROUP_TAG, state) + + elif op == sre_constants.GROUPREF: + self._output('\\%d' % args, self.RE_REF_TAG, state) + + elif op == sre_constants.RANGE: + self._colorize_re_tree( ((sre_constants.LITERAL, args[0]),), + state, False, groups ) + self._output('-', self.RE_OP_TAG, state) + self._colorize_re_tree( ((sre_constants.LITERAL, args[1]),), + state, False, groups ) + + elif op == sre_constants.NEGATE: + self._output('^', self.RE_OP_TAG, state) + + elif op == sre_constants.ASSERT: + if args[0] > 0: + self._output('(?=', self.RE_GROUP_TAG, state) + else: + self._output('(?<=', self.RE_GROUP_TAG, state) + self._colorize_re_tree(args[1], state, True, groups) + self._output(')', self.RE_GROUP_TAG, state) + + elif op == sre_constants.ASSERT_NOT: + if args[0] > 0: + self._output('(?!', self.RE_GROUP_TAG, state) + else: + self._output('(?<!', self.RE_GROUP_TAG, state) + self._colorize_re_tree(args[1], state, True, groups) + self._output(')', self.RE_GROUP_TAG, state) + + elif op == sre_constants.NOT_LITERAL: + self._output('[^', self.RE_GROUP_TAG, state) + self._colorize_re_tree( ((sre_constants.LITERAL, args),), + state, False, groups ) + self._output(']', self.RE_GROUP_TAG, state) + else: + log.error("Error colorizing regexp: unknown elt %r" % elt) + if len(tree) > 1 and not noparen: + self._output(')', self.RE_GROUP_TAG, state) + + #//////////////////////////////////////////////////////////// + # Output function + #//////////////////////////////////////////////////////////// + + def _output(self, s, tag, state): + """ + Add the string `s` to the result list, tagging its contents + with tag `tag`. Any lines that go beyond `self.linelen` will + be line-wrapped. If the total number of lines exceeds + `self.maxlines`, then raise a `_Maxlines` exception. + """ + if '\n' in s and not state.linebreakok: + raise _Linebreak() + + # Split the string into segments. The first segment is the + # content to add to the current line, and the remaining + # segments are new lines. + segments = s.split('\n') + + for i, segment in enumerate(segments): + # If this isn't the first segment, then add a newline to + # split it from the previous segment. + if i > 0: + if not state.linebreakok: + raise _Linebreak() + state.result.append(self.NEWLINE) + state.lineno += 1 + state.charpos = 0 + if state.lineno > self.maxlines: + raise _Maxlines() + + # If the segment fits on the current line, then just call + # markup to tag it, and store the result. + if state.charpos + len(segment) <= self.linelen: + state.result.append(self.markup(segment, tag)) + state.charpos += len(segment) + + # If the segment doesn't fit on the current line, then + # line-wrap it, and insert the remainder of the line into + # the segments list that we're iterating over. + else: + split = self.linelen-state.charpos + state.result += [self.markup(segment[:split], tag), + self.LINEWRAP] + segments.insert(i+1, segment[split:]) + +class HTMLPyvalColorizer(PyvalColorizer): + NEWLINE = '\n' + PREFIX = SUFFIX = '' + LINEWRAP = (r'<span class="variable-linewrap">' + '<img src="crarr.png" alt="\" /></span>') + ELLIPSIS = r'<span class="variable-ellipsis">...</span>' + def markup(self, s, tag=None): + s = s.replace('&', '&').replace('<', '<').replace('>', '>') + if tag: + return '<span class="variable-%s">%s</span>' % (tag, s) + else: + return s + +class XMLPyvalColorizer(PyvalColorizer): + NEWLINE = '\n' + PREFIX = '<pyval>' + SUFFIX = '</pyval>' + LINEWRAP = '<linewrap />' + ELLIPSIS = '<ellipsis />' + def markup(self, s, tag=None): + s = s.replace('&', '&').replace('<', '<').replace('>', '>') + if tag: + return '<%s>%s</%s>' % (tag, s, tag) + else: + return s Added: trunk/epydoc/src/epydoc/test/pyval_repr.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/pyval_repr.doctest (rev 0) +++ trunk/epydoc/src/epydoc/test/pyval_repr.doctest 2007-02-12 05:26:28 UTC (rev 1463) @@ -0,0 +1,194 @@ +Regression Testing for epydoc.markup.pyval_repr +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + >>> from epydoc.markup.pyval_repr import * + >>> colorizer = XMLPyvalColorizer(linelen=40) + >>> def color(s): print colorizer.colorize(s) + + +Simple Types +============ +Integers, floats, None, and complex numbers get printed using str, +with no syntax highlighting: + + >>> color(10) + <pyval>10</pyval> + >>> color(1./4) + <pyval>0.25</pyval> + >>> color(None) + <pyval>None</pyval> + >>> color(100) + <pyval>100</pyval> + +Long ints will get wrapped if they're big enough: + + >>> color(10000000) + <pyval>10000000</pyval> + >>> color(10**90) + <pyval>1000000000000000000000000000000000000000<linewrap /> + 0000000000000000000000000000000000000000<linewrap /> + 00000000000</pyval> + +Strings +======= +Strings have their quotation marks tagged as 'quote'. Characters are +escaped using the 'string-escape' encoding. + + >>> color(''.join(chr(i) for i in range(256))) + <pyval><val-quote>'''</val-quote><val-string>\x00\x01\x02\x03\x04\x05\x06\x07\x08\</val-string><linewrap /> + <val-string>t</val-string> + <val-string>\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x</val-string><linewrap /> + <val-string>15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x</val-string><linewrap /> + <val-string>1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCD</val-string><linewrap /> + <ellipsis /></pyval> + +Currently, the "'" quote is always used, because that's what the +'string-escape' encoding expects. + + >>> color('Hello') + <pyval><val-quote>'</val-quote><val-string>Hello</val-string><val-quote>'</val-quote></pyval> + >>> color('"Hello"') + <pyval><val-quote>'</val-quote><val-string>"Hello"</val-string><val-quote>'</val-quote></pyval> + >>> color("'Hello'") + <pyval><val-quote>'</val-quote><val-string>\'Hello\'</val-string><val-quote>'</val-quote></pyval> + +Strings containing newlines are automatically rendered as multiline +strings. + + >>> color("This\n is a multiline\n string!") + <pyval><val-quote>'''</val-quote><val-string>This</val-string> + <val-string> is a multiline</val-string> + <val-string> string!</val-string><val-quote>'''</val-quote></pyval> + +Unicode strings are handled properly. + + >>> color(u"Hello world") + <pyval><val-quote>u'</val-quote><val-string>Hello world</val-string><val-quote>'</val-quote></pyval> + >>> color(u"\uaaaa And \ubbbb") + <pyval><val-quote>u'</val-quote><val-string>\uaaaa And \ubbbb</val-string><val-quote>'</val-quote></pyval> + +Lists, Tuples, etc. +=================== +Lists, tuples, and sets are all colorized using the same method. The +braces and commas are tagged with "op". If the value can fit on the +current line, it is displayed on one line. Otherwise, each value is +listed on a separate line, indented by the size of the open-bracket. + + >>> color(range(10)) + <pyval><val-group>[</val-group>0<val-op>, </val-op>1<val-op>, </val-op>2<val-op>, </val-op>3<val-op>, </val-op>4<val-op>, </val-op>5<val-op>, </val-op>6<val-op>, </val-op>7<val-op>, </val-op>8<val-op>, </val-op>9<val-group>]</val-group></pyval> + >>> color(range(100)) + <pyval><val-group>[</val-group>0<val-op>,</val-op> + 1<val-op>,</val-op> + 2<val-op>,</val-op> + 3<val-op>,</val-op> + 4<val-op>,</val-op> + <ellipsis /></pyval> + >>> color([1,2,[5,6,[(11,22,33),9],10],11]+[99,98,97,96,95]) + <pyval><val-group>[</val-group>1<val-op>,</val-op> + 2<val-op>,</val-op> + <val-group>[</val-group>5<val-op>, </val-op>6<val-op>, </val-op><val-group>[</val-group><val-group>(</val-group>11<val-op>, </val-op>22<val-op>, </val-op>33<val-group>)</val-group><val-op>, </val-op>9<val-group>]</val-group><val-op>, </val-op>10<val-group>]</val-group><val-op>,</val-op> + 11<val-op>,</val-op> + 99<val-op>,</val-op> + <ellipsis /></pyval> + >>> color(set(range(20))) + <pyval><val-group>set([</val-group>0<val-op>,</val-op> + 1<val-op>,</val-op> + 2<val-op>,</val-op> + 3<val-op>,</val-op> + 4<val-op>,</val-op> + <ellipsis /></pyval> + +Dictionaries +============ +Dicts are treated just like lists, except that the ":" is also tagged as +"op". + + >>> color({1:33, 2:[1,2,3,{7:'oo'*20}]}) + <pyval><val-group>{</val-group>1<val-op>: </val-op>33<val-op>,</val-op> + 2<val-op>: </val-op><val-group>[</val-group>1<val-op>,</val-op> + 2<val-op>,</val-op> + 3<val-op>,</val-op> + <val-group>{</val-group>7<val-op>: </val-op><val-quote>'</val-quote><val-string>oooooooooooooooooooooooooooooo</val-string><linewrap /> + <ellipsis /></pyval> + +Regular Expressions +=================== + + >>> import re + >>> def color_re(s, check_roundtrip=True): + ... val = colorizer.colorize(re.compile(s)) + ... if check_roundtrip: + ... roundtrip_val = re.sub('</?[\w-]+>', '', val) + ... roundtrip_val = roundtrip_val.replace('>', '>') + ... roundtrip_val = roundtrip_val.replace('<', '<') + ... roundtrip_val = roundtrip_val.replace('&', '&') + ... assert roundtrip_val == s, roundtrip_val + ... print val + + >>> # Literal characters + >>> color_re(u'abc \t\r\n\f\v \xff \uffff \U000fffff', False) + <pyval>abc \t\r\n\f\v \xff \uffff \U000fffff</pyval> + >>> color_re(r'\.\^\$\\\*\+\?\{\}\[\]\|\(\)') + <pyval>\.\^\$\\\*\+\?\{\}\[\]\|\(\)</pyval> + + >>> # Any character & character classes + >>> color_re(r".\d\D\s\S\w\W\A^$\b\B\Z") + <pyval>.\d\D\s\S\w\W\A^$\b\B\Z</pyval> + + >>> # Branching + >>> color_re(r"foo|bar") + <pyval>foo<re-op>|</re-op>bar</pyval> + + >>> # Character classes + >>> color_re(r"[abcd]") + <pyval><re-group>[</re-group>abcd<re-group>]</re-group></pyval> + + >>> # Repeats + >>> color_re(r"a*b+c{4,}d{,5}e{3,9}f?") + <pyval>a<re-op>*</re-op>b<re-op>+</re-op>c<re-op>{4,}</re-op>d<re-op>{,5}</re-op>e<re-op>{3,9}</re-op>f<re-op>?</re-op></pyval> + >>> color_re(r"a*?b+?c{4,}?d{,5}?e{3,9}?f??") + <pyval>a<re-op>*?</re-op>b<re-op>+?</re-op>c<re-op>{4,}?</re-op>d<re-op>{,5}?</re-op>e<re-op>{3,9}?</re-op>f<re-op>??</re-op></pyval> + + >>> # Subpatterns + >>> color_re(r"(foo (bar) | (baz))") + <pyval><re-group>(</re-group>foo <re-group>(</re-group>bar<re-group>)</re-group> <re-op>|</re-op> <re-group>(</re-group>baz<re-group>)</re-group><re-group>)</re-group></pyval> + >>> color_re(r"(?:foo (?:bar) | (?:baz))") + <pyval><re-group>(?:</re-group>foo <re-group>(?:</re-group>bar<re-group>)</re-group> <re-op>|</re-op> <re-group>(?:</re-group>baz<re-group>)</re-group><re-group>)</re-group></pyval> + >>> color_re("(foo (?P<a>bar) | (?P<boop>baz))") + <pyval><re-group>(</re-group>foo <re-group>(?P<</re-group><re-ref>a</re-ref><re-group>></re-group>bar<re-group>)</re-group> <re-op>|</re-op> <re-group>(?P<</re-group><re-ref>boop</re-ref><re-group>></re-group>baz<re-group>)</re-group><re-group>)</re-group></pyval> + + >>> # Group References + >>> color_re(r"(...) and (\1)") + <pyval><re-group>(</re-group>...<re-group>)</re-group> and <re-group>(</re-group><re-ref>\1</re-ref><re-group>)</re-group></pyval> + + >>> # Ranges + >>> color_re(r"[a-bp-z]") + <pyval><re-group>[</re-group>a<re-op>-</re-op>bp<re-op>-</re-op>z<re-group>]</re-group></pyval> + >>> color_re(r"[^a-bp-z]") + <pyval><re-group>[</re-group><re-op>^</re-op>a<re-op>-</re-op>bp<re-op>-</re-op>z<re-group>]</re-group></pyval> + >>> color_re(r"[^abc]") + <pyval><re-group>[</re-group><re-op>^</re-op>abc<re-group>]</re-group></pyval> + + >>> # Lookahead/behinds + >>> color_re(r"foo(?=bar)") + <pyval>foo<re-group>(?=</re-group>bar<re-group>)</re-group></pyval> + >>> color_re(r"foo(?!bar)") + <pyval>foo<re-group>(?!</re-group>bar<re-group>)</re-group></pyval> + >>> color_re(r"(?<=bar)foo") + <pyval><re-group>(?<=</re-group>bar<re-group>)</re-group>foo</pyval> + >>> color_re(r"(?<!bar)foo") + <pyval><re-group>(?<!</re-group>bar<re-group>)</re-group>foo</pyval> + + >>> # Flags + >>> color_re(r"(?im)^Food") + <pyval><re-flags>(?im)</re-flags>^Food</pyval> + >>> color_re(r"(?Limsx)^Food") + <pyval><re-flags>(?Limsx)</re-flags>^Food</pyval> + >>> color_re(r"(?Limstux)^Food") + <pyval><re-flags>(?Limstux)</re-flags>^Food</pyval> + >>> color_re(r"(?x)This is verbose", False) + <pyval><re-flags>(?x)</re-flags>Thisisverbose</pyval> + + + + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-13 08:17:38
|
Revision: 1466 http://svn.sourceforge.net/epydoc/?rev=1466&view=rev Author: edloper Date: 2007-02-13 00:17:33 -0800 (Tue, 13 Feb 2007) Log Message: ----------- - Modified pyval_repr.py so now it generates a ParsedEpydocDocstring as its output. This should make it possible to change APIDoc.pyval_repr to return a ParsedDocstring instead of a str. This ParsedDocstring would be the result of colorization via pyval_repr, with the parsed repr as a fallback. Modified Paths: -------------- trunk/epydoc/src/epydoc/markup/epytext.py trunk/epydoc/src/epydoc/markup/pyval_repr.py trunk/epydoc/src/epydoc/test/pyval_repr.doctest Modified: trunk/epydoc/src/epydoc/markup/epytext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/epytext.py 2007-02-12 06:54:25 UTC (rev 1465) +++ trunk/epydoc/src/epydoc/markup/epytext.py 2007-02-13 08:17:33 UTC (rev 1466) @@ -67,7 +67,7 @@ <!ELEMENT tag (#PCDATA)> <!ELEMENT arg (#PCDATA)> - <!ELEMENT literalblock (#PCDATA)> + <!ELEMENT literalblock (#PCDATA | %colorized;)*> <!ELEMENT doctestblock (#PCDATA)> <!ELEMENT ulist (li+)> @@ -86,6 +86,7 @@ <!ELEMENT italic (#PCDATA | %colorized;)*> <!ELEMENT bold (#PCDATA | %colorized;)*> <!ELEMENT indexed (#PCDATA | %colorized;)> + <!ATTLIST code style CDATA #IMPLIED> <!ELEMENT symbol (#PCDATA)> @@ -1270,6 +1271,10 @@ return '%s{%s}' % (tag, childstr) raise ValueError('Unknown DOM element %r' % tree.tag) +SYMBOL_TO_PLAINTEXT = { + 'crarr': '\\', + } + def to_plaintext(tree, indent=0, seclevel=0): """ Convert a DOM document encoding epytext to a string representation. @@ -1344,7 +1349,7 @@ # if child.count('\n') > 2: return childstr return childstr.replace('\n\n', '\n')+'\n' elif tree.tag == 'symbol': - return '%s' % childstr + return '%s' % SYMBOL_TO_PLAINTEXT.get(childstr, childstr) elif tree.tag == 'graph': return '<<%s graph: %s>>' % (variables[0], ', '.join(variables[1:])) else: @@ -1606,47 +1611,47 @@ class ParsedEpytextDocstring(ParsedDocstring): SYMBOL_TO_HTML = { # Symbols - '<-': 'larr', '->': 'rarr', '^': 'uarr', 'v': 'darr', + '<-': '←', '->': '→', '^': '↑', 'v': '↓', # Greek letters - 'alpha': 'alpha', 'beta': 'beta', 'gamma': 'gamma', - 'delta': 'delta', 'epsilon': 'epsilon', 'zeta': 'zeta', - 'eta': 'eta', 'theta': 'theta', 'iota': 'iota', - 'kappa': 'kappa', 'lambda': 'lambda', 'mu': 'mu', - 'nu': 'nu', 'xi': 'xi', 'omicron': 'omicron', - 'pi': 'pi', 'rho': 'rho', 'sigma': 'sigma', - 'tau': 'tau', 'upsilon': 'upsilon', 'phi': 'phi', - 'chi': 'chi', 'psi': 'psi', 'omega': 'omega', - 'Alpha': 'Alpha', 'Beta': 'Beta', 'Gamma': 'Gamma', - 'Delta': 'Delta', 'Epsilon': 'Epsilon', 'Zeta': 'Zeta', - 'Eta': 'Eta', 'Theta': 'Theta', 'Iota': 'Iota', - 'Kappa': 'Kappa', 'Lambda': 'Lambda', 'Mu': 'Mu', - 'Nu': 'Nu', 'Xi': 'Xi', 'Omicron': 'Omicron', - 'Pi': 'Pi', 'Rho': 'Rho', 'Sigma': 'Sigma', - 'Tau': 'Tau', 'Upsilon': 'Upsilon', 'Phi': 'Phi', - 'Chi': 'Chi', 'Psi': 'Psi', 'Omega': 'Omega', + 'alpha': 'α', 'beta': 'β', 'gamma': 'γ', + 'delta': 'δ', 'epsilon': 'ε', 'zeta': 'ζ', + 'eta': 'η', 'theta': 'θ', 'iota': 'ι', + 'kappa': 'κ', 'lambda': 'λ', 'mu': 'μ', + 'nu': 'ν', 'xi': 'ξ', 'omicron': 'ο', + 'pi': 'π', 'rho': 'ρ', 'sigma': 'σ', + 'tau': 'τ', 'upsilon': 'υ', 'phi': 'φ', + 'chi': 'χ', 'psi': 'ψ', 'omega': 'ω', + 'Alpha': 'Α', 'Beta': 'Β', 'Gamma': 'Γ', + 'Delta': 'Δ', 'Epsilon': 'Ε', 'Zeta': 'Ζ', + 'Eta': 'Η', 'Theta': 'Θ', 'Iota': 'Ι', + 'Kappa': 'Κ', 'Lambda': 'Λ', 'Mu': 'Μ', + 'Nu': 'Ν', 'Xi': 'Ξ', 'Omicron': 'Ο', + 'Pi': 'Π', 'Rho': 'Ρ', 'Sigma': 'Σ', + 'Tau': 'Τ', 'Upsilon': 'Υ', 'Phi': 'Φ', + 'Chi': 'Χ', 'Psi': 'Ψ', 'Omega': 'Ω', # HTML character entities - 'larr': 'larr', 'rarr': 'rarr', 'uarr': 'uarr', - 'darr': 'darr', 'harr': 'harr', 'crarr': 'crarr', - 'lArr': 'lArr', 'rArr': 'rArr', 'uArr': 'uArr', - 'dArr': 'dArr', 'hArr': 'hArr', - 'copy': 'copy', 'times': 'times', 'forall': 'forall', - 'exist': 'exist', 'part': 'part', - 'empty': 'empty', 'isin': 'isin', 'notin': 'notin', - 'ni': 'ni', 'prod': 'prod', 'sum': 'sum', - 'prop': 'prop', 'infin': 'infin', 'ang': 'ang', - 'and': 'and', 'or': 'or', 'cap': 'cap', 'cup': 'cup', - 'int': 'int', 'there4': 'there4', 'sim': 'sim', - 'cong': 'cong', 'asymp': 'asymp', 'ne': 'ne', - 'equiv': 'equiv', 'le': 'le', 'ge': 'ge', - 'sub': 'sub', 'sup': 'sup', 'nsub': 'nsub', - 'sube': 'sube', 'supe': 'supe', 'oplus': 'oplus', - 'otimes': 'otimes', 'perp': 'perp', + 'larr': '←', 'rarr': '→', 'uarr': '↑', + 'darr': '↓', 'harr': '↔', 'crarr': '↵', + 'lArr': '⇐', 'rArr': '⇒', 'uArr': '⇑', + 'dArr': '⇓', 'hArr': '⇔', + 'copy': '©', 'times': '×', 'forall': '∀', + 'exist': '∃', 'part': '∂', + 'empty': '∅', 'isin': '∈', 'notin': '∉', + 'ni': '∋', 'prod': '∏', 'sum': '∑', + 'prop': '∝', 'infin': '∞', 'ang': '∠', + 'and': '∧', 'or': '∨', 'cap': '∩', 'cup': '∪', + 'int': '∫', 'there4': '∴', 'sim': '∼', + 'cong': '≅', 'asymp': '≈', 'ne': '≠', + 'equiv': '≡', 'le': '≤', 'ge': '≥', + 'sub': '⊂', 'sup': '⊃', 'nsub': '⊄', + 'sube': '⊆', 'supe': '⊇', 'oplus': '⊕', + 'otimes': '⊗', 'perp': '⊥', # Alternate (long) names - 'infinity': 'infin', 'integral': 'int', 'product': 'prod', - '<=': 'le', '>=': 'ge', + 'infinity': '∞', 'integral': '∫', 'product': '∏', + '<=': '≤', '>=': '≥', } SYMBOL_TO_LATEX = { @@ -1709,6 +1714,9 @@ # Caching: self._html = self._latex = self._plaintext = None self._terms = None + + def __str__(self): + return str(self._tree) def to_html(self, docstring_linker, directory=None, docindex=None, context=None, **options): @@ -1776,7 +1784,11 @@ if tree.tag == 'para': return wordwrap('<p>%s</p>' % childstr, indent) elif tree.tag == 'code': - return '<code>%s</code>' % childstr + style = tree.attribs.get('style') + if style: + return '<code class="%s">%s</code>' % (style, childstr) + else: + return '<code>%s</code>' % childstr elif tree.tag == 'uri': return ('<a href="%s" target="_top">%s</a>' % (variables[1], variables[0])) @@ -1815,10 +1827,7 @@ return childstr elif tree.tag == 'symbol': symbol = tree.children[0] - if self.SYMBOL_TO_HTML.has_key(symbol): - return '&%s;' % self.SYMBOL_TO_HTML[symbol] - else: - return '[??]' + return self.SYMBOL_TO_HTML.get(symbol, '[%s]' % symbol) elif tree.tag == 'graph': # Generate the graph. graph = self._build_graph(variables[0], variables[1:], linker, @@ -1940,10 +1949,7 @@ ' '*indent + '\\end{itemize}\n\n') elif tree.tag == 'symbol': symbol = tree.children[0] - if self.SYMBOL_TO_LATEX.has_key(symbol): - return r'%s' % self.SYMBOL_TO_LATEX[symbol] - else: - return '[??]' + return self.SYMBOL_TO_LATEX.get(symbol, '[%s]' % symbol) elif tree.tag == 'graph': return '(GRAPH)' #raise ValueError, 'graph not implemented yet for latex' Modified: trunk/epydoc/src/epydoc/markup/pyval_repr.py =================================================================== --- trunk/epydoc/src/epydoc/markup/pyval_repr.py 2007-02-12 06:54:25 UTC (rev 1465) +++ trunk/epydoc/src/epydoc/markup/pyval_repr.py 2007-02-13 08:17:33 UTC (rev 1466) @@ -20,6 +20,10 @@ number of lines (which should make it faster than pprint for large values). It does I{not} bother to do automatic cycle detection, because maxlines is typically around 5, so it's really not worth it. + +The syntax-highlighted output is encoded using a +L{ParsedEpydocDocstring}, which can then be used to generate output in +a variety of formats. """ # Implementation note: we use exact tests for classes (list, etc) @@ -29,9 +33,12 @@ import types, re import epydoc.apidoc from epydoc.util import decode_with_backslashreplace +from epydoc.util import plaintext_to_html, plaintext_to_latex from epydoc.compat import * import sre_parse, sre_constants +from epydoc.markup.epytext import Element, ParsedEpytextDocstring + def is_re_pattern(pyval): return type(pyval).__name__ == 'SRE_Pattern' @@ -42,19 +49,25 @@ a backup point, and restore back to that backup point. This is used by several colorization methods that first try colorizing their object on a single line (setting linebreakok=False); and - then fall back on a multi-line output if that fails. + then fall back on a multi-line output if that fails. The L{score} + variable is used to keep track of a 'score', reflecting how good + we think this repr is. E.g., unhelpful values like '<Foo instance + at 0x12345>' get low scores. If the score is too low, we'll use + the parse-derived repr instead. """ def __init__(self): self.result = [] self.charpos = 0 self.lineno = 1 self.linebreakok = True + self.score = 0 def mark(self): - return (len(self.result), self.charpos, self.lineno, self.linebreakok) + return (len(self.result), self.charpos, + self.lineno, self.linebreakok, self.score) def restore(self, mark): - n, self.charpos, self.lineno, self.linebreakok = mark + n, self.charpos, self.lineno, self.linebreakok, self.score = mark del self.result[n:] class _Maxlines(Exception): @@ -78,40 +91,6 @@ self.sort = sort #//////////////////////////////////////////////////////////// - # Subclassing Hooks - #//////////////////////////////////////////////////////////// - - PREFIX = None - """A string sequence that should be added to the beginning of all - colorized pyval outputs.""" - - SUFFIX = None - """A string sequence that should be added to the beginning of all - colorized pyval outputs.""" - - NEWLINE = '\n' - """The string sequence that should be generated to encode newlines.""" - - LINEWRAP = None - """The string sequence that should be generated when linewrapping a - string that is too long to fit on a single line. (The - NEWLINE sequence will be added immediately after this sequence)""" - - ELLIPSIS = None - """The string sequence that should be generated when omitting the - rest of the repr because maxlines has been exceeded.""" - - def markup(self, s, tag=None): - """ - Apply syntax highlighting to a single substring from a Python - value representation. 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: - - - (list under construction) - """ - - #//////////////////////////////////////////////////////////// # Colorization Tags #//////////////////////////////////////////////////////////// @@ -128,30 +107,43 @@ RE_REF_TAG = 're-ref' RE_OP_TAG = 're-op' RE_FLAGS_TAG = 're-flags' + + # Should these use symbols instead? + ELLIPSIS = Element('code', '...', style='ellipsis') + LINEWRAP = Element('symbol', 'crarr') #//////////////////////////////////////////////////////////// # Entry Point #//////////////////////////////////////////////////////////// - def colorize(self, pyval): + def colorize(self, pyval, min_score=None): + pds, score = self.colorize_and_score(pyval) + if min_score is None or score >= min_score: + return pds + else: + return None + + def colorize_and_score(self, pyval): + """ + @return: A tuple (parsed_docstring, score). + """ # Create an object to keep track of the colorization. state = _ColorizerState() - # Add the prefix string. - state.result.append(self.PREFIX) # Colorize the value. If we reach maxlines, then add on an # ellipsis marker and call it a day. try: self._colorize(pyval, state) except _Maxlines: state.result.append(self.ELLIPSIS) - # Add on the suffix string. - state.result.append(self.SUFFIX) # Put it all together. - return ''.join(state.result) + tree = Element('epytext', Element('code', style='pyval', + *state.result)) + return ParsedEpytextDocstring(tree), state.score def _colorize(self, pyval, state): pyval_type = type(pyval) - + state.score += 1 + if pyval is None or pyval is True or pyval is False: self._output(str(pyval), self.CONST_TAG, state) elif pyval_type in (int, float, long, types.ComplexType): @@ -179,7 +171,19 @@ elif is_re_pattern(pyval): self._colorize_re(pyval, state) else: - self._output(repr(pyval), None, state) + try: + pyval_repr = repr(pyval) + self._output(pyval_repr, None, state) + if self.GENERIC_OBJECT_RE.match(pyval_repr): + state.score -= 5 + except KeyboardInterrupt: + raise + except: + pyval_repr = '...' + state.score -= 100 + + GENERIC_OBJECT_RE = re.compile(r'^<.* at 0x[0-9a-f]+>$', + re.IGNORECASE) #//////////////////////////////////////////////////////////// # Object Colorization Functions @@ -430,7 +434,7 @@ if i > 0: if not state.linebreakok: raise _Linebreak() - state.result.append(self.NEWLINE) + state.result.append('\n') state.lineno += 1 state.charpos = 0 if state.lineno > self.maxlines: @@ -439,40 +443,21 @@ # If the segment fits on the current line, then just call # markup to tag it, and store the result. if state.charpos + len(segment) <= self.linelen: - state.result.append(self.markup(segment, tag)) state.charpos += len(segment) + if tag: + segment = Element('code', segment, style=tag) + state.result.append(segment) # If the segment doesn't fit on the current line, then # line-wrap it, and insert the remainder of the line into - # the segments list that we're iterating over. + # the segments list that we're iterating over. (We'll go + # the the beginning of the next line at the start of the + # next iteration through the loop.) else: split = self.linelen-state.charpos - state.result += [self.markup(segment[:split], tag), - self.LINEWRAP] segments.insert(i+1, segment[split:]) + segment = segment[:split] + if tag: + segment = Element('code', segment, style=tag) + state.result += [segment, self.LINEWRAP] -class HTMLPyvalColorizer(PyvalColorizer): - NEWLINE = '\n' - PREFIX = SUFFIX = '' - LINEWRAP = (r'<span class="variable-linewrap">' - '<img src="crarr.png" alt="\" /></span>') - ELLIPSIS = r'<span class="variable-ellipsis">...</span>' - def markup(self, s, tag=None): - s = s.replace('&', '&').replace('<', '<').replace('>', '>') - if tag: - return '<span class="variable-%s">%s</span>' % (tag, s) - else: - return s - -class XMLPyvalColorizer(PyvalColorizer): - NEWLINE = '\n' - PREFIX = '<pyval>' - SUFFIX = '</pyval>' - LINEWRAP = '<linewrap />' - ELLIPSIS = '<ellipsis />' - def markup(self, s, tag=None): - s = s.replace('&', '&').replace('<', '<').replace('>', '>') - if tag: - return '<%s>%s</%s>' % (tag, s, tag) - else: - return s Modified: trunk/epydoc/src/epydoc/test/pyval_repr.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/pyval_repr.doctest 2007-02-12 06:54:25 UTC (rev 1465) +++ trunk/epydoc/src/epydoc/test/pyval_repr.doctest 2007-02-13 08:17:33 UTC (rev 1466) @@ -2,32 +2,36 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >>> from epydoc.markup.pyval_repr import * - >>> colorizer = XMLPyvalColorizer(linelen=40) - >>> def color(s): print colorizer.colorize(s) + >>> colorizer = PyvalColorizer(linelen=40) + >>> def color(s): print colorizer.colorize(s).to_html(None).rstrip() - Simple Types ============ Integers, floats, None, and complex numbers get printed using str, with no syntax highlighting: >>> color(10) - <pyval>10</pyval> + <code class="pyval">10</code> >>> color(1./4) - <pyval>0.25</pyval> + <code class="pyval">0.25</code> >>> color(None) - <pyval>None</pyval> + <code class="pyval">None</code> >>> color(100) - <pyval>100</pyval> + <code class="pyval">100</code> Long ints will get wrapped if they're big enough: >>> color(10000000) - <pyval>10000000</pyval> + <code class="pyval">10000000</code> >>> color(10**90) - <pyval>1000000000000000000000000000000000000000<linewrap /> - 0000000000000000000000000000000000000000<linewrap /> - 00000000000</pyval> + <code class="pyval">1000000000000000000000000000000000000000↵ + 0000000000000000000000000000000000000000↵ + 00000000000</code> + >>> print '-'*40+'\n'+colorizer.colorize(10**90).to_plaintext(None) + ---------------------------------------- + 1000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000\ + 00000000000 Strings ======= @@ -35,37 +39,37 @@ escaped using the 'string-escape' encoding. >>> color(''.join(chr(i) for i in range(256))) - <pyval><val-quote>'''</val-quote><val-string>\x00\x01\x02\x03\x04\x05\x06\x07\x08\</val-string><linewrap /> - <val-string>t</val-string> - <val-string>\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x</val-string><linewrap /> - <val-string>15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x</val-string><linewrap /> - <val-string>1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCD</val-string><linewrap /> - <ellipsis /></pyval> + <code class="pyval"><code class="val-quote">'''</code><code class="val-string">\x00\x01\x02\x03\x04\x05\x06\x07\x08\</code>↵ + <code class="val-string">t</code> + <code class="val-string">\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x</code>↵ + <code class="val-string">15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x</code>↵ + <code class="val-string">1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCD</code>↵ + <code class="ellipsis">...</code></code> Currently, the "'" quote is always used, because that's what the 'string-escape' encoding expects. >>> color('Hello') - <pyval><val-quote>'</val-quote><val-string>Hello</val-string><val-quote>'</val-quote></pyval> + <code class="pyval"><code class="val-quote">'</code><code class="val-string">Hello</code><code class="val-quote">'</code></code> >>> color('"Hello"') - <pyval><val-quote>'</val-quote><val-string>"Hello"</val-string><val-quote>'</val-quote></pyval> + <code class="pyval"><code class="val-quote">'</code><code class="val-string">"Hello"</code><code class="val-quote">'</code></code> >>> color("'Hello'") - <pyval><val-quote>'</val-quote><val-string>\'Hello\'</val-string><val-quote>'</val-quote></pyval> + <code class="pyval"><code class="val-quote">'</code><code class="val-string">\'Hello\'</code><code class="val-quote">'</code></code> Strings containing newlines are automatically rendered as multiline strings. >>> color("This\n is a multiline\n string!") - <pyval><val-quote>'''</val-quote><val-string>This</val-string> - <val-string> is a multiline</val-string> - <val-string> string!</val-string><val-quote>'''</val-quote></pyval> + <code class="pyval"><code class="val-quote">'''</code><code class="val-string">This</code> + <code class="val-string"> is a multiline</code> + <code class="val-string"> string!</code><code class="val-quote">'''</code></code> Unicode strings are handled properly. >>> color(u"Hello world") - <pyval><val-quote>u'</val-quote><val-string>Hello world</val-string><val-quote>'</val-quote></pyval> + <code class="pyval"><code class="val-quote">u'</code><code class="val-string">Hello world</code><code class="val-quote">'</code></code> >>> color(u"\uaaaa And \ubbbb") - <pyval><val-quote>u'</val-quote><val-string>\uaaaa And \ubbbb</val-string><val-quote>'</val-quote></pyval> + <code class="pyval"><code class="val-quote">u'</code><code class="val-string">\uaaaa And \ubbbb</code><code class="val-quote">'</code></code> Lists, Tuples, etc. =================== @@ -75,28 +79,28 @@ listed on a separate line, indented by the size of the open-bracket. >>> color(range(10)) - <pyval><val-group>[</val-group>0<val-op>, </val-op>1<val-op>, </val-op>2<val-op>, </val-op>3<val-op>, </val-op>4<val-op>, </val-op>5<val-op>, </val-op>6<val-op>, </val-op>7<val-op>, </val-op>8<val-op>, </val-op>9<val-group>]</val-group></pyval> + <code class="pyval"><code class="val-group">[</code>0<code class="val-op">, </code>1<code class="val-op">, </code>2<code class="val-op">, </code>3<code class="val-op">, </code>4<code class="val-op">, </code>5<code class="val-op">, </code>6<code class="val-op">, </code>7<code class="val-op">, </code>8<code class="val-op">, </code>9<code class="val-group">]</code></code> >>> color(range(100)) - <pyval><val-group>[</val-group>0<val-op>,</val-op> - 1<val-op>,</val-op> - 2<val-op>,</val-op> - 3<val-op>,</val-op> - 4<val-op>,</val-op> - <ellipsis /></pyval> + <code class="pyval"><code class="val-group">[</code>0<code class="val-op">,</code> + 1<code class="val-op">,</code> + 2<code class="val-op">,</code> + 3<code class="val-op">,</code> + 4<code class="val-op">,</code> + <code class="ellipsis">...</code></code> >>> color([1,2,[5,6,[(11,22,33),9],10],11]+[99,98,97,96,95]) - <pyval><val-group>[</val-group>1<val-op>,</val-op> - 2<val-op>,</val-op> - <val-group>[</val-group>5<val-op>, </val-op>6<val-op>, </val-op><val-group>[</val-group><val-group>(</val-group>11<val-op>, </val-op>22<val-op>, </val-op>33<val-group>)</val-group><val-op>, </val-op>9<val-group>]</val-group><val-op>, </val-op>10<val-group>]</val-group><val-op>,</val-op> - 11<val-op>,</val-op> - 99<val-op>,</val-op> - <ellipsis /></pyval> + <code class="pyval"><code class="val-group">[</code>1<code class="val-op">,</code> + 2<code class="val-op">,</code> + <code class="val-group">[</code>5<code class="val-op">, </code>6<code class="val-op">, </code><code class="val-group">[</code><code class="val-group">(</code>11<code class="val-op">, </code>22<code class="val-op">, </code>33<code class="val-group">)</code><code class="val-op">, </code>9<code class="val-group">]</code><code class="val-op">, </code>10<code class="val-group">]</code><code class="val-op">,</code> + 11<code class="val-op">,</code> + 99<code class="val-op">,</code> + <code class="ellipsis">...</code></code> >>> color(set(range(20))) - <pyval><val-group>set([</val-group>0<val-op>,</val-op> - 1<val-op>,</val-op> - 2<val-op>,</val-op> - 3<val-op>,</val-op> - 4<val-op>,</val-op> - <ellipsis /></pyval> + <code class="pyval"><code class="val-group">set([</code>0<code class="val-op">,</code> + 1<code class="val-op">,</code> + 2<code class="val-op">,</code> + 3<code class="val-op">,</code> + 4<code class="val-op">,</code> + <code class="ellipsis">...</code></code> Dictionaries ============ @@ -104,91 +108,137 @@ "op". >>> color({1:33, 2:[1,2,3,{7:'oo'*20}]}) - <pyval><val-group>{</val-group>1<val-op>: </val-op>33<val-op>,</val-op> - 2<val-op>: </val-op><val-group>[</val-group>1<val-op>,</val-op> - 2<val-op>,</val-op> - 3<val-op>,</val-op> - <val-group>{</val-group>7<val-op>: </val-op><val-quote>'</val-quote><val-string>oooooooooooooooooooooooooooooo</val-string><linewrap /> - <ellipsis /></pyval> + <code class="pyval"><code class="val-group">{</code>1<code class="val-op">: </code>33<code class="val-op">,</code> + 2<code class="val-op">: </code><code class="val-group">[</code>1<code class="val-op">,</code> + 2<code class="val-op">,</code> + 3<code class="val-op">,</code> + <code class="val-group">{</code>7<code class="val-op">: </code><code class="val-quote">'</code><code class="val-string">oooooooooooooooooooooooooooooo</code>↵ + <code class="ellipsis">...</code></code> Regular Expressions =================== + >>> def textcontent(elt): + ... if isinstance(elt, basestring): return elt + ... else: return ''.join(textcontent(c) for c in elt.children) + >>> import re >>> def color_re(s, check_roundtrip=True): ... val = colorizer.colorize(re.compile(s)) ... if check_roundtrip: - ... roundtrip_val = re.sub('</?[\w-]+>', '', val) - ... roundtrip_val = roundtrip_val.replace('>', '>') - ... roundtrip_val = roundtrip_val.replace('<', '<') - ... roundtrip_val = roundtrip_val.replace('&', '&') - ... assert roundtrip_val == s, roundtrip_val - ... print val + ... assert textcontent(val._tree) == s, val._tree + ... print val.to_html(None).rstrip() >>> # Literal characters >>> color_re(u'abc \t\r\n\f\v \xff \uffff \U000fffff', False) - <pyval>abc \t\r\n\f\v \xff \uffff \U000fffff</pyval> + <code class="pyval">abc \t\r\n\f\v \xff \uffff \U000fffff</code> >>> color_re(r'\.\^\$\\\*\+\?\{\}\[\]\|\(\)') - <pyval>\.\^\$\\\*\+\?\{\}\[\]\|\(\)</pyval> + <code class="pyval">\.\^\$\\\*\+\?\{\}\[\]\|\(\)</code> >>> # Any character & character classes >>> color_re(r".\d\D\s\S\w\W\A^$\b\B\Z") - <pyval>.\d\D\s\S\w\W\A^$\b\B\Z</pyval> + <code class="pyval">.\d\D\s\S\w\W\A^$\b\B\Z</code> >>> # Branching >>> color_re(r"foo|bar") - <pyval>foo<re-op>|</re-op>bar</pyval> + <code class="pyval">foo<code class="re-op">|</code>bar</code> >>> # Character classes >>> color_re(r"[abcd]") - <pyval><re-group>[</re-group>abcd<re-group>]</re-group></pyval> + <code class="pyval"><code class="re-group">[</code>abcd<code class="re-group">]</code></code> >>> # Repeats >>> color_re(r"a*b+c{4,}d{,5}e{3,9}f?") - <pyval>a<re-op>*</re-op>b<re-op>+</re-op>c<re-op>{4,}</re-op>d<re-op>{,5}</re-op>e<re-op>{3,9}</re-op>f<re-op>?</re-op></pyval> + <code class="pyval">a<code class="re-op">*</code>b<code class="re-op">+</code>c<code class="re-op">{4,}</code>d<code class="re-op">{,5}</code>e<code class="re-op">{3,9}</code>f<code class="re-op">?</code></code> >>> color_re(r"a*?b+?c{4,}?d{,5}?e{3,9}?f??") - <pyval>a<re-op>*?</re-op>b<re-op>+?</re-op>c<re-op>{4,}?</re-op>d<re-op>{,5}?</re-op>e<re-op>{3,9}?</re-op>f<re-op>??</re-op></pyval> + <code class="pyval">a<code class="re-op">*?</code>b<code class="re-op">+?</code>c<code class="re-op">{4,}?</code>d<code class="re-op">{,5}?</code>e<code class="re-op">{3,9}?</code>f<code class="re-op">??</code></code> >>> # Subpatterns >>> color_re(r"(foo (bar) | (baz))") - <pyval><re-group>(</re-group>foo <re-group>(</re-group>bar<re-group>)</re-group> <re-op>|</re-op> <re-group>(</re-group>baz<re-group>)</re-group><re-group>)</re-group></pyval> + <code class="pyval"><code class="re-group">(</code>foo <code class="re-group">(</code>bar<code class="re-group">)</code> <code class="re-op">|</code> <code class="re-group">(</code>baz<code class="re-group">)</code><code class="re-group">)</code></code> >>> color_re(r"(?:foo (?:bar) | (?:baz))") - <pyval><re-group>(?:</re-group>foo <re-group>(?:</re-group>bar<re-group>)</re-group> <re-op>|</re-op> <re-group>(?:</re-group>baz<re-group>)</re-group><re-group>)</re-group></pyval> + <code class="pyval"><code class="re-group">(?:</code>foo <code class="re-group">(?:</code>bar<code class="re-group">)</code> <code class="re-op">|</code> <code class="re-group">(?:</code>baz<code class="re-group">)</code><code class="re-group">)</code></code> >>> color_re("(foo (?P<a>bar) | (?P<boop>baz))") - <pyval><re-group>(</re-group>foo <re-group>(?P<</re-group><re-ref>a</re-ref><re-group>></re-group>bar<re-group>)</re-group> <re-op>|</re-op> <re-group>(?P<</re-group><re-ref>boop</re-ref><re-group>></re-group>baz<re-group>)</re-group><re-group>)</re-group></pyval> + <code class="pyval"><code class="re-group">(</code>foo <code class="re-group">(?P<</code><code class="re-ref">a</code><code class="re-group">></code>bar<code class="re-group">)</code> <code class="re-op">|</code> <code class="re-group">(?P<</code><code class="re-ref">boop</code><code class="re-group">></code>baz<code class="re-group">)</code><code class="re-group">)</code></code> >>> # Group References >>> color_re(r"(...) and (\1)") - <pyval><re-group>(</re-group>...<re-group>)</re-group> and <re-group>(</re-group><re-ref>\1</re-ref><re-group>)</re-group></pyval> + <code class="pyval"><code class="re-group">(</code>...<code class="re-group">)</code> and <code class="re-group">(</code><code class="re-ref">\1</code><code class="re-group">)</code></code> >>> # Ranges >>> color_re(r"[a-bp-z]") - <pyval><re-group>[</re-group>a<re-op>-</re-op>bp<re-op>-</re-op>z<re-group>]</re-group></pyval> + <code class="pyval"><code class="re-group">[</code>a<code class="re-op">-</code>bp<code class="re-op">-</code>z<code class="re-group">]</code></code> >>> color_re(r"[^a-bp-z]") - <pyval><re-group>[</re-group><re-op>^</re-op>a<re-op>-</re-op>bp<re-op>-</re-op>z<re-group>]</re-group></pyval> + <code class="pyval"><code class="re-group">[</code><code class="re-op">^</code>a<code class="re-op">-</code>bp<code class="re-op">-</code>z<code class="re-group">]</code></code> >>> color_re(r"[^abc]") - <pyval><re-group>[</re-group><re-op>^</re-op>abc<re-group>]</re-group></pyval> + <code class="pyval"><code class="re-group">[</code><code class="re-op">^</code>abc<code class="re-group">]</code></code> >>> # Lookahead/behinds >>> color_re(r"foo(?=bar)") - <pyval>foo<re-group>(?=</re-group>bar<re-group>)</re-group></pyval> + <code class="pyval">foo<code class="re-group">(?=</code>bar<code class="re-group">)</code></code> >>> color_re(r"foo(?!bar)") - <pyval>foo<re-group>(?!</re-group>bar<re-group>)</re-group></pyval> + <code class="pyval">foo<code class="re-group">(?!</code>bar<code class="re-group">)</code></code> >>> color_re(r"(?<=bar)foo") - <pyval><re-group>(?<=</re-group>bar<re-group>)</re-group>foo</pyval> + <code class="pyval"><code class="re-group">(?<=</code>bar<code class="re-group">)</code>foo</code> >>> color_re(r"(?<!bar)foo") - <pyval><re-group>(?<!</re-group>bar<re-group>)</re-group>foo</pyval> + <code class="pyval"><code class="re-group">(?<!</code>bar<code class="re-group">)</code>foo</code> >>> # Flags >>> color_re(r"(?im)^Food") - <pyval><re-flags>(?im)</re-flags>^Food</pyval> + <code class="pyval"><code class="re-flags">(?im)</code>^Food</code> >>> color_re(r"(?Limsx)^Food") - <pyval><re-flags>(?Limsx)</re-flags>^Food</pyval> + <code class="pyval"><code class="re-flags">(?Limsx)</code>^Food</code> >>> color_re(r"(?Limstux)^Food") - <pyval><re-flags>(?Limstux)</re-flags>^Food</pyval> + <code class="pyval"><code class="re-flags">(?Limstux)</code>^Food</code> >>> color_re(r"(?x)This is verbose", False) - <pyval><re-flags>(?x)</re-flags>Thisisverbose</pyval> + <code class="pyval"><code class="re-flags">(?x)</code>Thisisverbose</code> +Representation Scores +===================== +When colorized representations are built, a score is computed +evaluating how helpful the repr is. E.g., unhelpful values like `<Foo +instance at 0x12345>` get low scores. Currently, the scoring +algorithm is: +- [+1] for each object colorized. When the colorizer recurses into + a structure, this will add one for each element contained. +- [-5] when repr(obj) looks like <xyz instance at ...>, for any + colorized object (including objects in structures). +- [-100] if repr(obj) raises an exception, for any colorized object + (including objects in structures). +The `min_score` arg to colorize can be used to set a cutoff-point for +scores; if the score is too low, then `colorize` will return `None`. + >>> def color2(v): + ... pds, score = colorizer.colorize_and_score(v) + ... print 'repr: %s' % pds.to_plaintext(None) + ... print 'score: %s (%s)' % (score, score>0 and 'ok' or 'bad') + + >>> class A: pass + + >>> color2('hello') + repr: 'hello' + score: 1 (ok) + + >>> color2(["hello", 123]) + repr: ['hello', 123] + score: 3 (ok) + + >>> color2(A()) + repr: <__builtin__.A instance at ...> + score: -4 (bad) + + >>> color2([A()]) + repr: [<__builtin__.A instance at ...>] + score: -3 (bad) + + >>> color2([A(),1,2,3,4,5,6]) + repr: [<__builtin__.A instance at ...>, + 1, + 2, + 3, + 4, + ... + score: 1 (ok) + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-13 08:21:30
|
Revision: 1467 http://svn.sourceforge.net/epydoc/?rev=1467&view=rev Author: edloper Date: 2007-02-13 00:21:20 -0800 (Tue, 13 Feb 2007) Log Message: ----------- - Removed unnecessary <code class="pyval">...</pyval> wrapping element from the output of the PyvalColorizer. Modified Paths: -------------- trunk/epydoc/src/epydoc/markup/pyval_repr.py trunk/epydoc/src/epydoc/test/pyval_repr.doctest Modified: trunk/epydoc/src/epydoc/markup/pyval_repr.py =================================================================== --- trunk/epydoc/src/epydoc/markup/pyval_repr.py 2007-02-13 08:17:33 UTC (rev 1466) +++ trunk/epydoc/src/epydoc/markup/pyval_repr.py 2007-02-13 08:21:20 UTC (rev 1467) @@ -136,8 +136,7 @@ except _Maxlines: state.result.append(self.ELLIPSIS) # Put it all together. - tree = Element('epytext', Element('code', style='pyval', - *state.result)) + tree = Element('epytext', *state.result) return ParsedEpytextDocstring(tree), state.score def _colorize(self, pyval, state): Modified: trunk/epydoc/src/epydoc/test/pyval_repr.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/pyval_repr.doctest 2007-02-13 08:17:33 UTC (rev 1466) +++ trunk/epydoc/src/epydoc/test/pyval_repr.doctest 2007-02-13 08:21:20 UTC (rev 1467) @@ -11,22 +11,22 @@ with no syntax highlighting: >>> color(10) - <code class="pyval">10</code> + 10 >>> color(1./4) - <code class="pyval">0.25</code> + 0.25 >>> color(None) - <code class="pyval">None</code> + None >>> color(100) - <code class="pyval">100</code> + 100 Long ints will get wrapped if they're big enough: >>> color(10000000) - <code class="pyval">10000000</code> + 10000000 >>> color(10**90) - <code class="pyval">1000000000000000000000000000000000000000↵ + 1000000000000000000000000000000000000000↵ 0000000000000000000000000000000000000000↵ - 00000000000</code> + 00000000000 >>> print '-'*40+'\n'+colorizer.colorize(10**90).to_plaintext(None) ---------------------------------------- 1000000000000000000000000000000000000000\ @@ -39,37 +39,37 @@ escaped using the 'string-escape' encoding. >>> color(''.join(chr(i) for i in range(256))) - <code class="pyval"><code class="val-quote">'''</code><code class="val-string">\x00\x01\x02\x03\x04\x05\x06\x07\x08\</code>↵ + <code class="val-quote">'''</code><code class="val-string">\x00\x01\x02\x03\x04\x05\x06\x07\x08\</code>↵ <code class="val-string">t</code> <code class="val-string">\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x</code>↵ <code class="val-string">15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x</code>↵ <code class="val-string">1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCD</code>↵ - <code class="ellipsis">...</code></code> + <code class="ellipsis">...</code> Currently, the "'" quote is always used, because that's what the 'string-escape' encoding expects. >>> color('Hello') - <code class="pyval"><code class="val-quote">'</code><code class="val-string">Hello</code><code class="val-quote">'</code></code> + <code class="val-quote">'</code><code class="val-string">Hello</code><code class="val-quote">'</code> >>> color('"Hello"') - <code class="pyval"><code class="val-quote">'</code><code class="val-string">"Hello"</code><code class="val-quote">'</code></code> + <code class="val-quote">'</code><code class="val-string">"Hello"</code><code class="val-quote">'</code> >>> color("'Hello'") - <code class="pyval"><code class="val-quote">'</code><code class="val-string">\'Hello\'</code><code class="val-quote">'</code></code> + <code class="val-quote">'</code><code class="val-string">\'Hello\'</code><code class="val-quote">'</code> Strings containing newlines are automatically rendered as multiline strings. >>> color("This\n is a multiline\n string!") - <code class="pyval"><code class="val-quote">'''</code><code class="val-string">This</code> + <code class="val-quote">'''</code><code class="val-string">This</code> <code class="val-string"> is a multiline</code> - <code class="val-string"> string!</code><code class="val-quote">'''</code></code> + <code class="val-string"> string!</code><code class="val-quote">'''</code> Unicode strings are handled properly. >>> color(u"Hello world") - <code class="pyval"><code class="val-quote">u'</code><code class="val-string">Hello world</code><code class="val-quote">'</code></code> + <code class="val-quote">u'</code><code class="val-string">Hello world</code><code class="val-quote">'</code> >>> color(u"\uaaaa And \ubbbb") - <code class="pyval"><code class="val-quote">u'</code><code class="val-string">\uaaaa And \ubbbb</code><code class="val-quote">'</code></code> + <code class="val-quote">u'</code><code class="val-string">\uaaaa And \ubbbb</code><code class="val-quote">'</code> Lists, Tuples, etc. =================== @@ -79,28 +79,28 @@ listed on a separate line, indented by the size of the open-bracket. >>> color(range(10)) - <code class="pyval"><code class="val-group">[</code>0<code class="val-op">, </code>1<code class="val-op">, </code>2<code class="val-op">, </code>3<code class="val-op">, </code>4<code class="val-op">, </code>5<code class="val-op">, </code>6<code class="val-op">, </code>7<code class="val-op">, </code>8<code class="val-op">, </code>9<code class="val-group">]</code></code> + <code class="val-group">[</code>0<code class="val-op">, </code>1<code class="val-op">, </code>2<code class="val-op">, </code>3<code class="val-op">, </code>4<code class="val-op">, </code>5<code class="val-op">, </code>6<code class="val-op">, </code>7<code class="val-op">, </code>8<code class="val-op">, </code>9<code class="val-group">]</code> >>> color(range(100)) - <code class="pyval"><code class="val-group">[</code>0<code class="val-op">,</code> + <code class="val-group">[</code>0<code class="val-op">,</code> 1<code class="val-op">,</code> 2<code class="val-op">,</code> 3<code class="val-op">,</code> 4<code class="val-op">,</code> - <code class="ellipsis">...</code></code> + <code class="ellipsis">...</code> >>> color([1,2,[5,6,[(11,22,33),9],10],11]+[99,98,97,96,95]) - <code class="pyval"><code class="val-group">[</code>1<code class="val-op">,</code> + <code class="val-group">[</code>1<code class="val-op">,</code> 2<code class="val-op">,</code> <code class="val-group">[</code>5<code class="val-op">, </code>6<code class="val-op">, </code><code class="val-group">[</code><code class="val-group">(</code>11<code class="val-op">, </code>22<code class="val-op">, </code>33<code class="val-group">)</code><code class="val-op">, </code>9<code class="val-group">]</code><code class="val-op">, </code>10<code class="val-group">]</code><code class="val-op">,</code> 11<code class="val-op">,</code> 99<code class="val-op">,</code> - <code class="ellipsis">...</code></code> + <code class="ellipsis">...</code> >>> color(set(range(20))) - <code class="pyval"><code class="val-group">set([</code>0<code class="val-op">,</code> + <code class="val-group">set([</code>0<code class="val-op">,</code> 1<code class="val-op">,</code> 2<code class="val-op">,</code> 3<code class="val-op">,</code> 4<code class="val-op">,</code> - <code class="ellipsis">...</code></code> + <code class="ellipsis">...</code> Dictionaries ============ @@ -108,12 +108,12 @@ "op". >>> color({1:33, 2:[1,2,3,{7:'oo'*20}]}) - <code class="pyval"><code class="val-group">{</code>1<code class="val-op">: </code>33<code class="val-op">,</code> + <code class="val-group">{</code>1<code class="val-op">: </code>33<code class="val-op">,</code> 2<code class="val-op">: </code><code class="val-group">[</code>1<code class="val-op">,</code> 2<code class="val-op">,</code> 3<code class="val-op">,</code> <code class="val-group">{</code>7<code class="val-op">: </code><code class="val-quote">'</code><code class="val-string">oooooooooooooooooooooooooooooo</code>↵ - <code class="ellipsis">...</code></code> + <code class="ellipsis">...</code> Regular Expressions =================== @@ -131,67 +131,67 @@ >>> # Literal characters >>> color_re(u'abc \t\r\n\f\v \xff \uffff \U000fffff', False) - <code class="pyval">abc \t\r\n\f\v \xff \uffff \U000fffff</code> + abc \t\r\n\f\v \xff \uffff \U000fffff >>> color_re(r'\.\^\$\\\*\+\?\{\}\[\]\|\(\)') - <code class="pyval">\.\^\$\\\*\+\?\{\}\[\]\|\(\)</code> + \.\^\$\\\*\+\?\{\}\[\]\|\(\) >>> # Any character & character classes >>> color_re(r".\d\D\s\S\w\W\A^$\b\B\Z") - <code class="pyval">.\d\D\s\S\w\W\A^$\b\B\Z</code> + .\d\D\s\S\w\W\A^$\b\B\Z >>> # Branching >>> color_re(r"foo|bar") - <code class="pyval">foo<code class="re-op">|</code>bar</code> + foo<code class="re-op">|</code>bar >>> # Character classes >>> color_re(r"[abcd]") - <code class="pyval"><code class="re-group">[</code>abcd<code class="re-group">]</code></code> + <code class="re-group">[</code>abcd<code class="re-group">]</code> >>> # Repeats >>> color_re(r"a*b+c{4,}d{,5}e{3,9}f?") - <code class="pyval">a<code class="re-op">*</code>b<code class="re-op">+</code>c<code class="re-op">{4,}</code>d<code class="re-op">{,5}</code>e<code class="re-op">{3,9}</code>f<code class="re-op">?</code></code> + a<code class="re-op">*</code>b<code class="re-op">+</code>c<code class="re-op">{4,}</code>d<code class="re-op">{,5}</code>e<code class="re-op">{3,9}</code>f<code class="re-op">?</code> >>> color_re(r"a*?b+?c{4,}?d{,5}?e{3,9}?f??") - <code class="pyval">a<code class="re-op">*?</code>b<code class="re-op">+?</code>c<code class="re-op">{4,}?</code>d<code class="re-op">{,5}?</code>e<code class="re-op">{3,9}?</code>f<code class="re-op">??</code></code> + a<code class="re-op">*?</code>b<code class="re-op">+?</code>c<code class="re-op">{4,}?</code>d<code class="re-op">{,5}?</code>e<code class="re-op">{3,9}?</code>f<code class="re-op">??</code> >>> # Subpatterns >>> color_re(r"(foo (bar) | (baz))") - <code class="pyval"><code class="re-group">(</code>foo <code class="re-group">(</code>bar<code class="re-group">)</code> <code class="re-op">|</code> <code class="re-group">(</code>baz<code class="re-group">)</code><code class="re-group">)</code></code> + <code class="re-group">(</code>foo <code class="re-group">(</code>bar<code class="re-group">)</code> <code class="re-op">|</code> <code class="re-group">(</code>baz<code class="re-group">)</code><code class="re-group">)</code> >>> color_re(r"(?:foo (?:bar) | (?:baz))") - <code class="pyval"><code class="re-group">(?:</code>foo <code class="re-group">(?:</code>bar<code class="re-group">)</code> <code class="re-op">|</code> <code class="re-group">(?:</code>baz<code class="re-group">)</code><code class="re-group">)</code></code> + <code class="re-group">(?:</code>foo <code class="re-group">(?:</code>bar<code class="re-group">)</code> <code class="re-op">|</code> <code class="re-group">(?:</code>baz<code class="re-group">)</code><code class="re-group">)</code> >>> color_re("(foo (?P<a>bar) | (?P<boop>baz))") - <code class="pyval"><code class="re-group">(</code>foo <code class="re-group">(?P<</code><code class="re-ref">a</code><code class="re-group">></code>bar<code class="re-group">)</code> <code class="re-op">|</code> <code class="re-group">(?P<</code><code class="re-ref">boop</code><code class="re-group">></code>baz<code class="re-group">)</code><code class="re-group">)</code></code> + <code class="re-group">(</code>foo <code class="re-group">(?P<</code><code class="re-ref">a</code><code class="re-group">></code>bar<code class="re-group">)</code> <code class="re-op">|</code> <code class="re-group">(?P<</code><code class="re-ref">boop</code><code class="re-group">></code>baz<code class="re-group">)</code><code class="re-group">)</code> >>> # Group References >>> color_re(r"(...) and (\1)") - <code class="pyval"><code class="re-group">(</code>...<code class="re-group">)</code> and <code class="re-group">(</code><code class="re-ref">\1</code><code class="re-group">)</code></code> + <code class="re-group">(</code>...<code class="re-group">)</code> and <code class="re-group">(</code><code class="re-ref">\1</code><code class="re-group">)</code> >>> # Ranges >>> color_re(r"[a-bp-z]") - <code class="pyval"><code class="re-group">[</code>a<code class="re-op">-</code>bp<code class="re-op">-</code>z<code class="re-group">]</code></code> + <code class="re-group">[</code>a<code class="re-op">-</code>bp<code class="re-op">-</code>z<code class="re-group">]</code> >>> color_re(r"[^a-bp-z]") - <code class="pyval"><code class="re-group">[</code><code class="re-op">^</code>a<code class="re-op">-</code>bp<code class="re-op">-</code>z<code class="re-group">]</code></code> + <code class="re-group">[</code><code class="re-op">^</code>a<code class="re-op">-</code>bp<code class="re-op">-</code>z<code class="re-group">]</code> >>> color_re(r"[^abc]") - <code class="pyval"><code class="re-group">[</code><code class="re-op">^</code>abc<code class="re-group">]</code></code> + <code class="re-group">[</code><code class="re-op">^</code>abc<code class="re-group">]</code> >>> # Lookahead/behinds >>> color_re(r"foo(?=bar)") - <code class="pyval">foo<code class="re-group">(?=</code>bar<code class="re-group">)</code></code> + foo<code class="re-group">(?=</code>bar<code class="re-group">)</code> >>> color_re(r"foo(?!bar)") - <code class="pyval">foo<code class="re-group">(?!</code>bar<code class="re-group">)</code></code> + foo<code class="re-group">(?!</code>bar<code class="re-group">)</code> >>> color_re(r"(?<=bar)foo") - <code class="pyval"><code class="re-group">(?<=</code>bar<code class="re-group">)</code>foo</code> + <code class="re-group">(?<=</code>bar<code class="re-group">)</code>foo >>> color_re(r"(?<!bar)foo") - <code class="pyval"><code class="re-group">(?<!</code>bar<code class="re-group">)</code>foo</code> + <code class="re-group">(?<!</code>bar<code class="re-group">)</code>foo >>> # Flags >>> color_re(r"(?im)^Food") - <code class="pyval"><code class="re-flags">(?im)</code>^Food</code> + <code class="re-flags">(?im)</code>^Food >>> color_re(r"(?Limsx)^Food") - <code class="pyval"><code class="re-flags">(?Limsx)</code>^Food</code> + <code class="re-flags">(?Limsx)</code>^Food >>> color_re(r"(?Limstux)^Food") - <code class="pyval"><code class="re-flags">(?Limstux)</code>^Food</code> + <code class="re-flags">(?Limstux)</code>^Food >>> color_re(r"(?x)This is verbose", False) - <code class="pyval"><code class="re-flags">(?x)</code>Thisisverbose</code> + <code class="re-flags">(?x)</code>Thisisverbose Representation Scores ===================== This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-02-13 14:27:25
|
Revision: 1471 http://svn.sourceforge.net/epydoc/?rev=1471&view=rev Author: dvarrazzo Date: 2007-02-13 06:27:23 -0800 (Tue, 13 Feb 2007) Log Message: ----------- - The parse representation is preferred if repr() returns a stock result, i.e. something like '<ClassName instance at 0x12345678>'. - Using LaTeX package fancyhdr instead of the deprecated fancyheadings. - Added missing escaping of LaTeX parameter default. - Dropped parse_repr/pyval_repr check in HTML parameters default. Modified Paths: -------------- trunk/epydoc/src/epydoc/apidoc.py trunk/epydoc/src/epydoc/docwriter/html.py trunk/epydoc/src/epydoc/docwriter/latex.py Modified: trunk/epydoc/src/epydoc/apidoc.py =================================================================== --- trunk/epydoc/src/epydoc/apidoc.py 2007-02-13 14:16:22 UTC (rev 1470) +++ trunk/epydoc/src/epydoc/apidoc.py 2007-02-13 14:27:23 UTC (rev 1471) @@ -794,6 +794,9 @@ UNKNOWN_REPR = "??" """@cvar: The string representation of an unknown value.""" + STOCK_REPR = re.compile(r"(?i)^<.+\bat\b.+[0-9a-f]+.*>$") + """Match the return of repr() for object that didn't customize it.""" + def pyval_repr(self): """Return a string representation of the python value. @@ -812,6 +815,9 @@ if rv is UNKNOWN: rv = self.parse_repr + elif self.STOCK_REPR.match(rv) and self.parse_repr is not UNKNOWN: + rv = self.parse_repr + if rv is UNKNOWN: rv = self.UNKNOWN_REPR Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2007-02-13 14:16:22 UTC (rev 1470) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2007-02-13 14:27:23 UTC (rev 1471) @@ -2572,12 +2572,9 @@ name = self._arg_name(name) s = '<span class="%s-arg">%s</span>' % (css_class, name) if default is not None: - if default.parse_repr is not UNKNOWN: - s += ('=<span class="%s-default">%s</span>' % - (css_class, plaintext_to_html(default.parse_repr))) - else: - s += ('=<span class="%s-default">%s</span>' % - (css_class, plaintext_to_html(default.pyval_repr()))) + s += ('=<span class="%s-default">%s</span>' % + (css_class, plaintext_to_html( + default.summary_pyval_repr()[0]))) return s def _arg_name(self, arg): Modified: trunk/epydoc/src/epydoc/docwriter/latex.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/latex.py 2007-02-13 14:16:22 UTC (rev 1470) +++ trunk/epydoc/src/epydoc/docwriter/latex.py 2007-02-13 14:27:23 UTC (rev 1471) @@ -27,7 +27,7 @@ class LatexWriter: PREAMBLE = [ "\\documentclass{article}", - "\\usepackage{alltt, parskip, fancyheadings, boxedminipage}", + "\\usepackage{alltt, parskip, fancyhdr, boxedminipage}", "\\usepackage{makeidx, multirow, longtable, tocbibind, amssymb}", "\\usepackage{fullpage}", "\\usepackage[usenames]{color}", @@ -287,7 +287,7 @@ m = re.match(r'\\usepackage(\[.*?\])?{(.*?)}', line) if m and m.group(2) in ( 'babel', 'hyperref', 'color', 'alltt', 'parskip', - 'fancyheadings', 'boxedminipage', 'makeidx', + 'fancyhdr', 'boxedminipage', 'makeidx', 'multirow', 'longtable', 'tocbind', 'assymb', 'fullpage'): pass @@ -727,7 +727,8 @@ def func_arg(self, name, default): s = '\\textit{%s}' % plaintext_to_latex(self._arg_name(name)) if default is not None: - s += '=\\texttt{%s}' % default.summary_pyval_repr()[0] + s += '=\\texttt{%s}' % plaintext_to_latex( + default.summary_pyval_repr()[0]) return s def _arg_name(self, arg): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-13 19:46:10
|
Revision: 1473 http://svn.sourceforge.net/epydoc/?rev=1473&view=rev Author: edloper Date: 2007-02-13 11:46:05 -0800 (Tue, 13 Feb 2007) Log Message: ----------- - Changed ValueDoc.pyval_repr and summary_pval_repr to return ParsedDocstring's instead of string. These ParsedDocstrings are generated by epydoc.markup.pyval_repr. Instead of returning a separate value to indicate whether there's left-over (for GenericValueDoc.is_detailed), add an 'is_complete' attribute to the parsed docstring. - Defer importing of dotgraph from epydoc.markup.epytext to avoid a circular dependency. Modified Paths: -------------- trunk/epydoc/src/epydoc/apidoc.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/epytext.py trunk/epydoc/src/epydoc/markup/pyval_repr.py trunk/epydoc/src/epydoc/test/docbuilder.doctest trunk/epydoc/src/epydoc/test/pyval_repr.doctest Modified: trunk/epydoc/src/epydoc/apidoc.py =================================================================== --- trunk/epydoc/src/epydoc/apidoc.py 2007-02-13 15:27:45 UTC (rev 1472) +++ trunk/epydoc/src/epydoc/apidoc.py 2007-02-13 19:46:05 UTC (rev 1473) @@ -44,6 +44,7 @@ import __builtin__ from epydoc.compat import * # Backwards compatibility from epydoc.util import decode_with_backslashreplace, py_src_filename +import epydoc.markup.pyval_repr ###################################################################### # Dotted Names @@ -726,8 +727,30 @@ the initial assignment). @type: C{unicode}""" - summary_linelen = 75 - """@cvar: The maximum length of a row to fit in a summary.""" + REPR_MAXLINES = 5 + """@cvar: The maximum number of lines of text that should be + generated by L{pyval_repr()}. If the string representation does + not fit in this number of lines, an ellpsis marker (...) will + be placed at the end of the formatted representation.""" + + REPR_LINELEN = 75 + """@cvar: The maximum number of characters for lines of text that + should be generated by L{pyval_repr()}. Any lines that exceed + this number of characters will be line-wrappped; The S{crarr} + symbol will be used to indicate that the line was wrapped.""" + + SUMMARY_REPR_LINELEN = 75 + """@cvar: The maximum number of characters for the single-line + text representation generated by L{summary_pyval_repr()}. If + the value's representation does not fit in this number of + characters, an ellipsis marker (...) will be placed at the end + of the formatted representation.""" + + REPR_MIN_SCORE = 0 + """@cvar: The minimum score that a value representation based on + L{pyval} should have in order to be used instead of L{parse_repr} + as the canonical representation for this C{ValueDoc}'s value. + @see: L{epydoc.markup.pyval_repr}""" #} end of "value representation" group #{ Context @@ -767,7 +790,8 @@ if self.canonical_name is not UNKNOWN: return '<%s %s>' % (self.__class__.__name__, self.canonical_name) else: - return '<%s %s>' % (self.__class__.__name__, self.pyval_repr()) + return '<%s %s>' % (self.__class__.__name__, + self.summary_pyval_repr().to_plaintext(None)) def __setstate__(self, state): self.__dict__ = state @@ -782,101 +806,64 @@ # as a private attribute, so we can reuse it later, since # merged objects need to share a single dictionary. if not hasattr(self, '_ValueDoc__pickle_state'): + # Make sure __pyval_repr & __summary_pyval_repr are cached: + self.pyval_repr(), self.summary_pyval_repr() + # Construct the dictionary; leave out 'pyval'. self.__pickle_state = self.__dict__.copy() self.__pickle_state['pyval'] = UNKNOWN - self.__pickle_state['_ValueDoc__pyval_repr'] = self.pyval_repr() if not isinstance(self, GenericValueDoc): assert self.__pickle_state != {} # Return the pickle state. return self.__pickle_state - UNKNOWN_REPR = "??" - """@cvar: The string representation of an unknown value.""" - - STOCK_REPR = re.compile(r"(?i)^<.+\bat\b.+[0-9a-f]+.*>$") - """Match the return of repr() for object that didn't customize it.""" - + #{ Value Representation def pyval_repr(self): - """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 + Return a formatted representation of the Python object + described by this C{ValueDoc}. This representation may + include data from introspection or parsing, and is authorative + as 'the best way to represent a Python value.' Any lines that + go beyond L{REPR_LINELEN} characters will be wrapped; and if + the representation as a whole takes more than L{REPR_MAXLINES} + lines, then it will be truncated (with an ellipsis marker). + This function will never return L{UNKNOWN} or C{None}. + + @rtype: L{ColorizedPyvalRepr} + """ + # Use self.__pyval_repr to cache the result. + if not hasattr(self, '_ValueDoc__pyval_repr'): + self.__pyval_repr = epydoc.markup.pyval_repr.colorize_pyval( + self.pyval, self.parse_repr, self.REPR_MIN_SCORE, + self.REPR_LINELEN, self.REPR_MAXLINES, linebreakok=True) + return self.__pyval_repr - rv = self._get_pyval_repr() - if rv is UNKNOWN: - rv = self.parse_repr - - elif self.STOCK_REPR.match(rv) and self.parse_repr is not 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 single-line formatted representation of the Python + object described by this C{ValueDoc}. This representation may + include data from introspection or parsing, and is authorative + as 'the best way to summarize a Python value.' If the + representation takes more then L{SUMMARY_REPR_LINELEN} + characters, then it will be truncated (with an ellipsis + marker). This function will never return L{UNKNOWN} or + C{None}. + + @rtype: L{ColorizedPyvalRepr} """ - Return a string representation of this value based on its pyval; - or UNKNOWN if we don't succeed. This should probably eventually - be replaced by more of a safe-repr variant. - """ - if self.pyval is UNKNOWN: - if hasattr(self, '_ValueDoc__pyval_repr'): - return self.__pyval_repr # used after unpickling. - return UNKNOWN - try: - s = '%r' % (self.pyval,) - if isinstance(s, str): - s = decode_with_backslashreplace(s) - return s - except KeyboardInterrupt: raise - except: return UNKNOWN + # If max_len is specified, then do *not* cache the result. + if max_len is not None: + return epydoc.markup.pyval_repr.colorize_pyval( + self.pyval, self.parse_repr, self.REPR_MIN_SCORE, + max_len, maxlines=1, linebreakok=False) + + # Use self.__summary_pyval_repr to cache the result. + if not hasattr(self, '_ValueDoc__summary_pyval_repr'): + self.__summary_pyval_repr = epydoc.markup.pyval_repr.colorize_pyval( + self.pyval, self.parse_repr, self.REPR_MIN_SCORE, + self.SUMMARY_REPR_LINELEN, maxlines=1, linebreakok=False) + return self.__summary_pyval_repr + #} end of "value representation" group def apidoc_links(self, **filters): return [] @@ -891,7 +878,7 @@ canonical_name = None def is_detailed(self): - return self.summary_pyval_repr()[1] + return (not self.summary_pyval_repr().is_complete) class NamespaceDoc(ValueDoc): """ Modified: trunk/epydoc/src/epydoc/docwriter/dotgraph.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/dotgraph.py 2007-02-13 15:27:45 UTC (rev 1472) +++ trunk/epydoc/src/epydoc/docwriter/dotgraph.py 2007-02-13 19:46:05 UTC (rev 1473) @@ -694,7 +694,7 @@ if default is None: return '%s' % name else: - pyval_repr = default.summary_pyval_repr()[0] + pyval_repr = default.summary_pyval_repr().to_plaintext(None) return '%s=%s' % (name, pyval_repr) def _qualifier_cell(self, key_label, port): Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2007-02-13 15:27:45 UTC (rev 1472) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2007-02-13 19:46:05 UTC (rev 1473) @@ -19,7 +19,7 @@ import __builtin__ from epydoc.apidoc import * import epydoc.docstringparser -import time, epydoc, epydoc.markup +import time, epydoc, epydoc.markup, epydoc.markup.epytext from epydoc.docwriter.html_colorize import colorize_re from epydoc.docwriter.html_colorize import PythonSourceColorizer from epydoc.docwriter import html_colorize @@ -330,7 +330,7 @@ """Max line length for variable values""" self._variable_summary_linelen = \ - kwargs.get('variable_summary_linelength', 55) + kwargs.get('variable_summary_linelength', 65) """Max length for variable value summaries""" self._variable_tooltip_linelen = \ @@ -501,6 +501,21 @@ # For progress reporting: self._files_written = 0. + # Set the default values for ValueDoc formatted representations. + orig_valdoc_defaults = (ValueDoc.SUMMARY_REPR_LINELEN, + ValueDoc.REPR_LINELEN, + ValueDoc.REPR_MAXLINES) + ValueDoc.SUMMARY_REPR_LINELEN = self._variable_summary_linelen + ValueDoc.REPR_LINELEN = self._variable_linelen + ValueDoc.REPR_MAXLINES = self._variable_maxlines + + # Use an image for the crarr symbol. + from epydoc.markup.epytext import ParsedEpytextDocstring + orig_crarr_html = ParsedEpytextDocstring.SYMBOL_TO_HTML['crarr'] + ParsedEpytextDocstring.SYMBOL_TO_HTML['crarr'] = ( + r'<span class="variable-linewrap">' + r'<img src="crarr.png" alt="\" /></span>') + # Keep track of failed xrefs, and report them at the end. self._failed_xrefs = {} @@ -509,11 +524,6 @@ 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') @@ -524,7 +534,7 @@ log.progress(self._files_written/self._num_files, 'epydoc.js') self.write_javascript(directory) - # Write images. + # Write images self.write_images(directory) # Build the indices. @@ -656,6 +666,11 @@ "wrote %d files" % (self._num_files, int(self._files_written))) + # Restore defaults that we changed. + (ValueDoc.SUMMARY_REPR_LINELEN, ValueDoc.REPR_LINELEN, + ValueDoc.REPR_MAXLINES) = orig_valdoc_defaults + ParsedEpytextDocstring.SYMBOL_TO_HTML['crarr'] = orig_crarr_html + def _write(self, write_func, directory, filename, *args): # Display our progress. self._files_written += 1 @@ -1920,12 +1935,12 @@ description = self.summary_name(var_doc, link_name=True) if isinstance(var_doc.value, GenericValueDoc): # 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) + # L{ValueDoc.SUMMARY_REPR_LINELEN} in the constructor + max_len=self._variable_summary_linelen-3-len(var_doc.name) + val_repr = var_doc.value.summary_pyval_repr(max_len) tooltip = self.variable_tooltip(var_doc) description += (' = <code%s>%s</code>' % - (tooltip, val_repr)) + (tooltip, val_repr.to_html(None))) # Add the summary to the description (if there is one). summary = self.summary(var_doc, indent=6) @@ -2058,9 +2073,7 @@ if isinstance(val_doc, RoutineDoc): return self.function_signature(val_doc, True, True) elif isinstance(val_doc, GenericValueDoc): - return ('<table><tr><td><pre class="variable">\n' + - self.pprint_value(val_doc) + - '\n</pre></td></tr></table>\n') + return self.pprint_value(val_doc) else: return self.href(val_doc) else: @@ -2272,9 +2285,7 @@ >>> self.write_standard_fields(out, var_doc) >>> if var_doc.value is not UNKNOWN: <dl><dt>Value:</dt> - <dd><table><tr><td><pre class="variable"> - $self.pprint_value(var_doc.value)$ - </pre></td></tr></table></dd> + <dd>$self.pprint_value(var_doc.value)$</dd> </dl> >>> #endif </dd></dl> @@ -2286,168 +2297,21 @@ def variable_tooltip(self, var_doc): if var_doc.value in (None, UNKNOWN): return '' - - s = var_doc.value.pyval_repr() + s = var_doc.value.pyval_repr().to_plaintext(None) if len(s) > self._variable_tooltip_linelen: s = s[:self._variable_tooltip_linelen-3]+'...' return ' title="%s"' % plaintext_to_html(s) def pprint_value(self, val_doc): - if val_doc is UNKNOWN: return '' - if val_doc.pyval is not UNKNOWN: - return self.pprint_pyval(val_doc.pyval) + if val_doc is UNKNOWN: + return '??' elif isinstance(val_doc, GenericValueDoc): - s = plaintext_to_html(val_doc.pyval_repr()) + return ('<table><tr><td><pre class="variable">\n' + + val_doc.pyval_repr().to_html(None) + + '\n</pre></td></tr></table>\n') else: - s = self.href(val_doc) - return self._linewrap_html(s, self._variable_linelen, - self._variable_maxlines) + return self.href(val_doc) - def pprint_pyval(self, pyval): - # Handle the most common cases first. The following types - # will never need any line wrapping, etc; and they cover most - # variable values (esp int, for constants). I leave out - # LongType on purpose, since long values may need line- - # wrapping. - if (type(pyval) is types.IntType or type(pyval) is types.FloatType or - type(pyval) is types.NoneType or type(pyval) is types.ComplexType): - # none of these should contain '&', '<' or '>'. - vstr = repr(pyval) - return vstr + ' ' * (self._variable_linelen-len(vstr)) - - # For strings, use repr. Use tripple-quoted-strings where - # appropriate. - elif isinstance(pyval, basestring): - vstr = repr(pyval) - # Find the left quote. - lquote = vstr.find(vstr[-1]) - # Use tripple quotes if the string is multi-line: - if vstr.find(r'\n') >= 0: - body = vstr[lquote+1:-1].replace(r'\n', '\n') - vstr = ('<span class="variable-quote">'+vstr[:lquote]+ - vstr[lquote]*3+'</span>'+ - plaintext_to_html(body) + - '<span class="variable-quote">'+vstr[-1]*3+'</span>') - # Use single quotes if the string is single-line: - else: - vstr = ('<span class="variable-quote">'+vstr[:lquote+1]+ - '</span>'+ plaintext_to_html(vstr[lquote+1:-1])+ - '<span class="variable-quote">'+vstr[-1:]+'</span>') - - # For lists, tuples, and dicts, use pprint. When possible, - # restrict the amount of stuff that pprint needs to look at, - # since pprint is surprisingly slow. - elif type(pyval) is types.TupleType or type(pyval) is types.ListType: - try: vstr = repr(pyval) - except: vstr = '...' - if len(vstr) > self._variable_linelen: - vstr = pprint.pformat(pyval[:self._variable_maxlines+1]) - vstr = plaintext_to_html(vstr) - elif type(pyval) is type({}): - try: vstr = repr(pyval) - except: vstr = '...' - if len(vstr) > self._variable_linelen: - if len(pyval) < self._variable_maxlines+50: - vstr = pprint.pformat(pyval) - else: - shortval = {} - for (k,v) in pyval.items()[:self._variable_maxlines+1]: - shortval[k]=v - vstr = pprint.pformat(shortval) - vstr = plaintext_to_html(vstr) - - # For regexps, use colorize_re. - elif type(pyval).__name__ == 'SRE_Pattern': - try: vstr = colorize_re(pyval) - except TypeError, sre_constants.error: - try: vstr = plaintext_to_html(repr(pyval)) - except: vstr = '...' - - # For other objects, use repr to generate a representation. - else: - try: vstr = plaintext_to_html(repr(pyval)) - except: vstr = '...' - - # Encode vstr, if necessary. - if isinstance(vstr, str): - vstr = decode_with_backslashreplace(vstr) - - # Do line-wrapping. - return self._linewrap_html(vstr, self._variable_linelen, - self._variable_maxlines) - - def _linewrap_html(self, s, linelen, maxlines): - """ - Add line-wrapping to the HTML string C{s}. Line length is - determined by C{linelen}; and the maximum number of - lines to display is determined by C{maxlines}. This - function treats HTML entities (e.g., C{&}) as single - characters; and ignores HTML tags (e.g., C{<p>}). - """ - LINEWRAP_MARKER = (r'<span class="variable-linewrap">' - '<img src="crarr.png" alt="\" /></span>') - ELLIPSIS_MARKER = r'<span class="variable-ellipsis">...</span>' - - open_elements = [] # tag stack - lines = [] - start = end = cnum = 0 - while len(lines) <= maxlines and end < len(s): - # Skip over HTML tags. - if s[end] == '<': - newend = s.find('>', end) - tag = s[end+1:newend] - if tag[-1]!="/": - # non-empty tag - tagname = tag.split(None,1)[0] - if tagname[0] == "/": - open_elements.pop() - else: - open_elements.append(tagname) - end = newend - cnum -= 1 - - # HTML entities just count as 1 char. - elif s[end] == '&': - end = s.find(';', end) - - # Go on to the next character. - cnum += 1 - end += 1 - - # Check for end-of-line. - if s[end-1] == '\n': - lines.append(s[start:end-1]) - cnum = 0 - start = end - - # Check for line-wrap - if cnum == linelen and end<len(s) and s[end] != '\n': - if maxlines == 1: - closing_tags = "" - for tag in open_elements: - closing_tags += "</%s>" % (tag,) - return s[start:end]+closing_tags+ELLIPSIS_MARKER - lines.append(s[start:end]+LINEWRAP_MARKER) - cnum = 0 - start = end - - # Add on anything that's left. - if end == len(s): - lines.append(s[start:end]) - - # Use the ellipsis marker if the string is too long. - if len(lines) > maxlines: - closing_tags = "" - for tag in open_elements: - closing_tags += "</%s>" % (tag,) - lines[-1] = closing_tags+ELLIPSIS_MARKER - cnum = 3 - - # Pad the last line to linelen. - lines[-1] += ' '*(linelen-cnum+1) - - return ('\n').join(lines) - #//////////////////////////////////////////////////////////// #{ Base Tree #//////////////////////////////////////////////////////////// @@ -2573,8 +2437,7 @@ s = '<span class="%s-arg">%s</span>' % (css_class, name) if default is not None: s += ('=<span class="%s-default">%s</span>' % - (css_class, plaintext_to_html( - default.summary_pyval_repr()[0]))) + (css_class, default.summary_pyval_repr().to_html(None))) 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-13 15:27:45 UTC (rev 1472) +++ trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-02-13 19:46:05 UTC (rev 1473) @@ -69,6 +69,7 @@ font-weight: bold; } h3 { font-size: +110%; font-style: italic; font-weight: normal; } +code { font-size: 100%; } /* Page Header & Footer * - The standard page header consists of a navigation bar (with @@ -210,6 +211,10 @@ .variable-linewrap { color: $variable_linewrap; font-weight: bold; } .variable-ellipsis { color: $variable_ellipsis; font-weight: bold; } .variable-quote { color: $variable_quote; font-weight: bold; } +.variable-group { color: $variable_group; font-weight: bold; } +.variable-op { color: $variable_op; font-weight: bold; } +.variable-string { color: $variable_string; } +.variable-unknown { color: $variable_unknown; font-weight: bold; } .re { color: $re; } .re-char { color: $re_char; } .re-op { color: $re_op; } @@ -384,6 +389,10 @@ variable_linewrap = '#604000', variable_ellipsis = '#604000', variable_quote = '#604000', + variable_group = '#008000', + variable_string = '#006030', + variable_op = '#604000', + variable_unknown = '#a00000', re = '#000000', re_char = '#006030', re_op = '#600000', Modified: trunk/epydoc/src/epydoc/docwriter/latex.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/latex.py 2007-02-13 15:27:45 UTC (rev 1472) +++ trunk/epydoc/src/epydoc/docwriter/latex.py 2007-02-13 19:46:05 UTC (rev 1473) @@ -144,6 +144,14 @@ # For progress reporting: self._files_written = 0. + # Set the default values for ValueDoc formatted representations. + orig_valdoc_defaults = (ValueDoc.SUMMARY_REPR_LINELEN, + ValueDoc.REPR_LINELEN, + ValueDoc.REPR_MAXLINES) + ValueDoc.SUMMARY_REPR_LINELEN = 60 + ValueDoc.REPR_LINELEN = 52 + ValueDoc.REPR_MAXLINES = 5 + # Create destination directories, if necessary if not directory: directory = os.curdir self._mkdir(directory) @@ -162,6 +170,10 @@ filename = '%s-class.tex' % val_doc.canonical_name self._write(self.write_class, directory, filename, val_doc) + # Restore defaults that we changed. + (ValueDoc.SUMMARY_REPR_LINELEN, ValueDoc.REPR_LINELEN, + ValueDoc.REPR_MAXLINES) = orig_valdoc_defaults + def _write(self, write_func, directory, filename, *args): # Display our progress. self._files_written += 1 @@ -727,8 +739,7 @@ def func_arg(self, name, default): s = '\\textit{%s}' % plaintext_to_latex(self._arg_name(name)) if default is not None: - s += '=\\texttt{%s}' % plaintext_to_latex( - default.summary_pyval_repr()[0]) + s += '=\\texttt{%s}' % default.summary_pyval_repr().to_latex(None) return s def _arg_name(self, arg): @@ -801,31 +812,28 @@ out(' & ') 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.pyval_repr() != var_doc.value.UNKNOWN_REPR) - if has_descr or has_type: - out('\\raggedright ') + out('\\raggedright ') if has_descr: out(self.docstring_to_latex(var_doc.descr, 10).strip()) if has_type or has_repr: out('\n\n') - if has_repr: - out('\\textbf{Value:} \n') - pyval_repr = var_doc.value.pyval_repr() - out(self._pprint_var_value(pyval_repr, 80)) + out('\\textbf{Value:} \n') + out(self._pprint_var_value(var_doc)) if has_type: ptype = self.docstring_to_latex(var_doc.type_descr, 12).strip() out('%s\\textit{(type=%s)}' % (' '*12, ptype)) out('&\\\\\n') out('\\cline{1-2}\n') - def _pprint_var_value(self, s, maxwidth=100): - if len(s) > maxwidth: s = s[:maxwidth-3] + '...' - if '\n' in s: + def _pprint_var_value(self, var_doc): + pyval_repr = var_doc.value.pyval_repr().to_latex(None) + if '\n' in pyval_repr: return ('\\begin{alltt}\n%s\\end{alltt}' % - plaintext_to_latex(s, nbsp=False, breakany=True)) + pyval_repr) + #plaintext_to_latex(pyval_repr, nbsp=False, breakany=True)) else: - return '{\\tt %s}' % plaintext_to_latex(s, nbsp=True, - breakany=True) + return '{\\tt %s}' % pyval_repr + #plaintext_to_latex(pyval_repr, nbsp=True, + #breakany=True) def write_property_list_line(self, out, var_doc): prop_doc = var_doc.value Modified: trunk/epydoc/src/epydoc/docwriter/plaintext.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/plaintext.py 2007-02-13 15:27:45 UTC (rev 1472) +++ trunk/epydoc/src/epydoc/docwriter/plaintext.py 2007-02-13 19:46:05 UTC (rev 1473) @@ -15,10 +15,12 @@ import re class PlaintextWriter: - def write(self, api_doc): + def write(self, api_doc, **options): result = [] out = result.append + self._cols = options.get('cols', 75) + try: if isinstance(api_doc, ModuleDoc): self.write_module(out, api_doc) @@ -128,7 +130,7 @@ self.write_list(out, 'Inherited Nested Classes', class_doc, value_type='class', prefix=prefix, inherited=True, verbose=False) - + def write_variable(self, out, var_doc, name=None, prefix='', verbose=True): if name is None: name = var_doc.name out(prefix+self.bold(str(name))) @@ -137,8 +139,9 @@ var_doc.value.canonical_name not in (None, UNKNOWN)): out(' = %s' % var_doc.value.canonical_name) elif var_doc.value not in (UNKNOWN, None): - val_repr = var_doc.value.summary_pyval_repr(max_len=len(name)-75)[0] - out(' = %s' % val_repr.expandtabs()) + val_repr = var_doc.value.summary_pyval_repr( + max_len=self._cols-len(name)-len(prefix)-3) + out(' = %s' % val_repr.to_plaintext(None)) out('\n') if not verbose: return prefix += ' ' # indent the body. @@ -199,7 +202,8 @@ if default is None: return '%s' % name else: - return '%s=%s' % (name, default.summary_pyval_repr()[0]) + default_repr = default.summary_pyval_repr() + return '%s=%s' % (name, default_repr.to_plaintext(None)) def write_list(self, out, heading, doc, value_type=None, imported=False, inherited=False, prefix='', noindent=False, Modified: trunk/epydoc/src/epydoc/markup/epytext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/epytext.py 2007-02-13 15:27:45 UTC (rev 1472) +++ trunk/epydoc/src/epydoc/markup/epytext.py 2007-02-13 19:46:05 UTC (rev 1473) @@ -148,6 +148,11 @@ ''.join([str(child) for child in self.children]) + '</%s>' % self.tag) + def __repr__(self): + attribs = ''.join([', %s=%r' % t for t in self.attribs.items()]) + args = ''.join([', %r' % c for c in self.children]) + return 'Element(%s%s%s)' % (self.tag, args, attribs) + ################################################## ## Constants ################################################## @@ -1591,7 +1596,6 @@ ################################################################# ## SUPPORT FOR EPYDOC ################################################################# -from epydoc.docwriter.dotgraph import * def parse_docstring(docstring, errors, **options): """ @@ -1854,6 +1858,7 @@ log.warning("Could not construct class tree: you must " "specify one or more base classes.") return None + from epydoc.docwriter.dotgraph import class_tree_graph return class_tree_graph(bases, linker, context) elif graph_type == 'packagetree': if graph_args: @@ -1865,9 +1870,11 @@ log.warning("Could not construct package tree: you must " "specify one or more root packages.") return None + from epydoc.docwriter.dotgraph import package_tree_graph return package_tree_graph(packages, linker, context) elif graph_type == 'importgraph': modules = [d for d in docindex.root if isinstance(d, ModuleDoc)] + from epydoc.docwriter.dotgraph import import_graph return import_graph(modules, docindex, linker, context) elif graph_type == 'callgraph': @@ -1876,6 +1883,7 @@ docs = [doc for doc in docs if doc is not None] else: docs = [context] + from epydoc.docwriter.dotgraph import call_graph return call_graph(docs, docindex, linker, context) else: log.warning("Unknown graph type %s" % graph_type) Modified: trunk/epydoc/src/epydoc/markup/pyval_repr.py =================================================================== --- trunk/epydoc/src/epydoc/markup/pyval_repr.py 2007-02-13 15:27:45 UTC (rev 1472) +++ trunk/epydoc/src/epydoc/markup/pyval_repr.py 2007-02-13 19:46:05 UTC (rev 1473) @@ -79,28 +79,44 @@ generates a string containing a newline, but the state object's linebreakok variable is False.""" +class ColorizedPyvalRepr(ParsedEpytextDocstring): + """ + @ivar score: A score, evaluating how good this repr is. + @ivar is_complete: True if this colorized repr completely describes + the object. + """ + def __init__(self, tree, score, is_complete): + ParsedEpytextDocstring.__init__(self, tree) + self.score = score + self.is_complete = is_complete +def colorize_pyval(pyval, parse_repr=None, min_score=None, + linelen=75, maxlines=5, linebreakok=True, sort=True): + return PyvalColorizer(linelen, maxlines, linebreakok, sort).colorize( + pyval, parse_repr, min_score) + class PyvalColorizer: """ Syntax highlighter for Python values. """ - def __init__(self, linelen=75, maxlines=5, sort=True): + def __init__(self, linelen=75, maxlines=5, linebreakok=True, sort=True): self.linelen = linelen self.maxlines = maxlines + self.linebreakok = linebreakok self.sort = sort #//////////////////////////////////////////////////////////// - # Colorization Tags + # Colorization Tags & other constants #//////////////////////////////////////////////////////////// - GROUP_TAG = 'val-group' # e.g., "[" and "]" - COMMA_TAG = 'val-op' # The "," that separates elements - COLON_TAG = 'val-op' # The ":" in dictionaries - CONST_TAG = None # None, True, False - NUMBER_TAG = None # ints, floats, etc - QUOTE_TAG = 'val-quote' # Quotes around strings. - STRING_TAG = 'val-string' # Body of string literals + GROUP_TAG = 'variable-group' # e.g., "[" and "]" + COMMA_TAG = 'variable-op' # The "," that separates elements + COLON_TAG = 'variable-op' # The ":" in dictionaries + CONST_TAG = None # None, True, False + NUMBER_TAG = None # ints, floats, etc + QUOTE_TAG = 'variable-quote' # Quotes around strings. + STRING_TAG = 'variable-string' # Body of string literals RE_CHAR_TAG = None RE_GROUP_TAG = 're-group' @@ -108,45 +124,60 @@ RE_OP_TAG = 're-op' RE_FLAGS_TAG = 're-flags' - # Should these use symbols instead? - ELLIPSIS = Element('code', '...', style='ellipsis') - LINEWRAP = Element('symbol', 'crarr') + ELLIPSIS = Element('code', u'...', style='variable-ellipsis') + LINEWRAP = Element('symbol', u'crarr') + UNKNOWN_REPR = Element('code', u'??', style='variable-unknown') + GENERIC_OBJECT_RE = re.compile(r'^<.* at 0x[0-9a-f]+>$', re.IGNORECASE) + #//////////////////////////////////////////////////////////// # Entry Point #//////////////////////////////////////////////////////////// - def colorize(self, pyval, min_score=None): - pds, score = self.colorize_and_score(pyval) - if min_score is None or score >= min_score: - return pds - else: - return None - - def colorize_and_score(self, pyval): + def colorize(self, pyval, parse_repr=None, min_score=None): """ - @return: A tuple (parsed_docstring, score). + @return: A L{ColorizedPyvalRepr} describing the given pyval. """ + UNKNOWN = epydoc.apidoc.UNKNOWN # Create an object to keep track of the colorization. state = _ColorizerState() + state.linebreakok = self.linebreakok # Colorize the value. If we reach maxlines, then add on an # ellipsis marker and call it a day. try: - self._colorize(pyval, state) - except _Maxlines: - state.result.append(self.ELLIPSIS) + if pyval is not UNKNOWN: + self._colorize(pyval, state) + elif parse_repr not in (None, UNKNOWN): + self._output(parse_repr, None, state) + else: + state.result.append(PyvalColorizer.UNKNOWN_REPR) + is_complete = True + except (_Maxlines, _Linebreak): + if self.linebreakok: + state.result.append('\n') + state.result.append(self.ELLIPSIS) + else: + if state.result[-1] is self.LINEWRAP: + state.result.pop() + self._trim_result(state.result, 3) + state.result.append(self.ELLIPSIS) + is_complete = False + # If we didn't score high enough, then try again. + if (pyval is not UNKNOWN and parse_repr not in (None, UNKNOWN) + and min_score is not None and state.score < min_score): + return self.colorize(UNKNOWN, parse_repr) # Put it all together. tree = Element('epytext', *state.result) - return ParsedEpytextDocstring(tree), state.score + return ColorizedPyvalRepr(tree, state.score, is_complete) def _colorize(self, pyval, state): pyval_type = type(pyval) state.score += 1 if pyval is None or pyval is True or pyval is False: - self._output(str(pyval), self.CONST_TAG, state) + self._output(unicode(pyval), self.CONST_TAG, state) elif pyval_type in (int, float, long, types.ComplexType): - self._output(str(pyval), self.NUMBER_TAG, state) + self._output(unicode(pyval), self.NUMBER_TAG, state) elif pyval_type is str: self._colorize_str(pyval, state, '', 'string-escape') elif pyval_type is unicode: @@ -156,34 +187,56 @@ elif pyval_type is tuple: self._multiline(self._colorize_iter, pyval, state, '(', ')') elif pyval_type is set: - if self.sort: pyval = sorted(pyval) - self._multiline(self._colorize_iter, pyval, state, - 'set([', '])') + self._multiline(self._colorize_iter, self._sort(pyval), + state, 'set([', '])') elif pyval_type is frozenset: - if self.sort: pyval = sorted(pyval) - self._multiline(self._colorize_iter, pyval, state, - 'frozenset([', '])') + self._multiline(self._colorize_iter, self._sort(pyval), + state, 'frozenset([', '])') elif pyval_type is dict: - items = pyval.items() - if self.sort: items = sorted(items) - self._multiline(self._colorize_dict, items, state, '{', '}') + self._multiline(self._colorize_dict, self._sort(pyval.items()), + state, '{', '}') elif is_re_pattern(pyval): self._colorize_re(pyval, state) else: try: pyval_repr = repr(pyval) - self._output(pyval_repr, None, state) - if self.GENERIC_OBJECT_RE.match(pyval_repr): - state.score -= 5 + if not isinstance(pyval_repr, (str, unicode)): + pyval_repr = unicode(pyval_repr) + pyval_repr_ok = True except KeyboardInterrupt: raise except: - pyval_repr = '...' + pyval_repr_ok = False state.score -= 100 - GENERIC_OBJECT_RE = re.compile(r'^<.* at 0x[0-9a-f]+>$', - re.IGNORECASE) + if pyval_repr_ok: + self._output(pyval_repr, None, state) + if self.GENERIC_OBJECT_RE.match(pyval_repr): + state.score -= 5 + else: + state.result.append(self.UNKNOWN_REPR) + + def _sort(self, items): + if not self.sort: return items + try: return sorted(items) + except KeyboardInterrupt: raise + except: return items + def _trim_result(self, result, num_chars): + while num_chars > 0: + if not result: return + if isinstance(result[-1], Element): + assert len(result[-1].children) == 1 + trim = min(num_chars, len(result[-1].children[0])) + result[-1].children[0] = result[-1].children[0][:-trim] + if not result[-1].children[0]: result.pop() + num_chars -= trim + else: + trim = min(num_chars, len(result[-1])) + result[-1] = result[-1][:-trim] + if not result[-1]: result.pop() + num_chars -= trim + #//////////////////////////////////////////////////////////// # Object Colorization Functions #//////////////////////////////////////////////////////////// @@ -238,12 +291,17 @@ def _colorize_str(self, pyval, state, prefix, encoding): # Decide which quote to use. - if '\n' in pyval: quote = "'''" + if '\n' in pyval and state.linebreakok: quote = "'''" else: quote = "'" + # Divide the string into lines. + if state.linebreakok: + lines = pyval.split('\n') + else: + lines = [pyval] # Open quote. self._output(prefix+quote, self.QUOTE_TAG, state) # Body - for i, line in enumerate(pyval.split('\n')): + for i, line in enumerate(lines): if i>0: self._output('\n', None, state) self._output(line.encode(encoding), self.STRING_TAG, state) # Close quote. @@ -260,8 +318,10 @@ groups = dict([(num,name) for (name,num) in tree.pattern.groupdict.items()]) # Colorize it! + self._output("re.compile(r'", None, state) self._colorize_re_flags(tree.pattern.flags, state) self._colorize_re_tree(tree, state, True, groups) + self._output("')", None, state) def _colorize_re_flags(self, flags, state): if flags: @@ -281,7 +341,7 @@ if op == sre_constants.LITERAL: c = unichr(args) # Add any appropriate escaping. - if c in '.^$\\*+?{}[]|()': c = '\\'+c + if c in '.^$\\*+?{}[]|()\'': c = '\\'+c elif c == '\t': c = '\\t' elif c == '\r': c = '\\r' elif c == '\n': c = '\\n' @@ -419,8 +479,9 @@ be line-wrapped. If the total number of lines exceeds `self.maxlines`, then raise a `_Maxlines` exception. """ - if '\n' in s and not state.linebreakok: - raise _Linebreak() + # Make sure the string is unicode. + if isinstance(s, str): + s = decode_with_backslashreplace(s) # Split the string into segments. The first segment is the # content to add to the current line, and the remaining @@ -431,13 +492,13 @@ # If this isn't the first segment, then add a newline to # split it from the previous segment. if i > 0: + if (state.lineno+1) > self.maxlines: + raise _Maxlines() if not state.linebreakok: raise _Linebreak() - state.result.append('\n') + state.result.append(u'\n') state.lineno += 1 state.charpos = 0 - if state.lineno > self.maxlines: - raise _Maxlines() # If the segment fits on the current line, then just call # markup to tag it, and store the result. Modified: trunk/epydoc/src/epydoc/test/docbuilder.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/docbuilder.doctest 2007-02-13 15:27:45 UTC (rev 1472) +++ trunk/epydoc/src/epydoc/test/docbuilder.doctest 2007-02-13 19:46:05 UTC (rev 1473) @@ -300,17 +300,39 @@ >>> from epydoc.test.util import buildvaluedoc >>> def print_py_reprs(s): ... value_doc = buildvaluedoc(s) + ... print 'Var Score Repr\n'+'-'*50 ... for (name, var_doc) in sorted(value_doc.variables.items()): - ... print "%-5s %r" % (name, var_doc.value.pyval_repr()) + ... if len(name) > 1: continue + ... var_repr = var_doc.value.pyval_repr() + ... print " %s %4s %r" % (name, var_repr.score, + ... var_repr.to_plaintext(None)) >>> print_py_reprs(''' + ... import re ... class Foo: pass - ... a = Foo() - ... b = [1, 2, 3] - ... c = 3+5 - ... b.append(99) + ... class Bar: + ... def __repr__(self): return "<specialized repr>" + ... class Baz: + ... def __repr__(self): raise ValueError() + ... a = Foo() # pyval score < 0; use parse repr. + ... b = Bar() # pyval score > 0; use pyval repr. + ... c = Baz() # pyval score < 0; use parse repr. + ... d = [1, 2, 3] # pyval score > 0; use pyval repr. + ... d.append(99) + ... e = 3+5 # pyval score > 0; use pyval repr. + ... f = re.compile('hi+') # pyval score > 0; use pyval repr. + ... globals()['h'] = Baz() # pyval score < 0; can't be parsed. + ... i = [Foo(), 1, 2] # pyval score < 0; use parse repr. + ... j = [Foo(), 1, 2, 3] # pyval score = 0; use pyval repr. ... ''') - Foo u'<class epydoc_test.Foo at ...>' - a u'Foo()' - b u'[1, 2, 3, 99]' - c u'8' + Var Score Repr + -------------------------------------------------- + a 0 u'Foo()' + b 1 u'<specialized repr>' + c 0 u'Baz()' + d 5 u'[1, 2, 3, 99]' + e 1 u'8' + f 1 u"re.compile(r'hi+')" + h -99 u'??' + i 0 u'[Foo(), 1, 2]' + j 0 u'[<epydoc_test.Foo instance at ...>, 1, 2, 3]' Modified: trunk/epydoc/src/epydoc/test/pyval_repr.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/pyval_repr.doctest 2007-02-13 15:27:45 UTC (rev 1472) +++ trunk/epydoc/src/epydoc/test/pyval_repr.doctest 2007-02-13 19:46:05 UTC (rev 1473) @@ -3,7 +3,10 @@ >>> from epydoc.markup.pyval_repr import * >>> colorizer = PyvalColorizer(linelen=40) - >>> def color(s): print colorizer.colorize(s).to_html(None).rstrip() + >>> def color(v, linebreakok=True): + ... colorizer = PyvalColorizer(linelen=40, linebreakok=linebreakok) + ... pds = colorizer.colorize(v, None) + ... print pds.to_html(None).rstrip() Simple Types ============ @@ -27,6 +30,7 @@ 1000000000000000000000000000000000000000↵ 0000000000000000000000000000000000000000↵ 00000000000 + >>> colorizer = PyvalColorizer(linelen=40) >>> print '-'*40+'\n'+colorizer.colorize(10**90).to_plaintext(None) ---------------------------------------- 1000000000000000000000000000000000000000\ @@ -39,37 +43,42 @@ escaped using the 'string-escape' encoding. >>> color(''.join(chr(i) for i in range(256))) - <code class="val-quote">'''</code><code class="val-string">\x00\x01\x02\x03\x04\x05\x06\x07\x08\</code>↵ - <code class="val-string">t</code> - <code class="val-string">\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x</code>↵ - <code class="val-string">15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x</code>↵ - <code class="val-string">1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCD</code>↵ - <code class="ellipsis">...</code> + <code class="variable-quote">'''</code><code class="variable-string">\x00\x01\x02\x03\x04\x05\x06\x07\x08\</code>↵ + <code class="variable-string">t</code> + <code class="variable-string">\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x</code>↵ + <code class="variable-string">15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x</code>↵ + <code class="variable-string">1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCD</code>↵ + <code class="variable-ellipsis">...</code> Currently, the "'" quote is always used, because that's what the 'string-escape' encoding expects. >>> color('Hello') - <code class="val-quote">'</code><code class="val-string">Hello</code><code class="val-quote">'</code> + <code class="variable-quote">'</code><code class="variable-string">Hello</code><code class="variable-quote">'</code> >>> color('"Hello"') - <code class="val-quote">'</code><code class="val-string">"Hello"</code><code class="val-quote">'</code> + <code class="variable-quote">'</code><code class="variable-string">"Hello"</code><code class="variable-quote">'</code> >>> color("'Hello'") - <code class="val-quote">'</code><code class="val-string">\'Hello\'</code><code class="val-quote">'</code> + <code class="variable-quote">'</code><code class="variable-string">\'Hello\'</code><code class="variable-quote">'</code> Strings containing newlines are automatically rendered as multiline strings. >>> color("This\n is a multiline\n string!") - <code class="val-quote">'''</code><code class="val-string">This</code> - <code class="val-string"> is a multiline</code> - <code class="val-string"> string!</code><code class="val-quote">'''</code> + <code class="variable-quote">'''</code><code class="variable-string">This</code> + <code class="variable-string"> is a multiline</code> + <code class="variable-string"> string!</code><code class="variable-quote">'''</code> +Unless we ask for them not to be: + + >>> color("This\n is a multiline\n string!", linebreakok=False) + <code class="variable-quote">'</code><code class="variable-string">This\n is a multiline\n string!</code><code class="variable-quote">'</code> + Unicode strings are handled properly. >>> color(u"Hello world") - <code class="val-quote">u'</code><code class="val-string">Hello world</code><code class="val-quote">'</code> + <code class="variable-quote">u'</code><code class="variable-string">Hello world</code><code class="variable-quote">'</code> >>> color(u"\uaaaa And \ubbbb") - <code class="val-quote">u'</code><code class="val-string">\uaaaa And \ubbbb</code><code class="val-quote">'</code> + <code class="variable-quote">u'</code><code class="variable-string">\uaaaa And \ubbbb</code><code class="variable-quote">'</code> Lists, Tuples, etc. =================== @@ -79,28 +88,28 @@ listed on a separate line, indented by the size of the open-bracket. >>> color(range(10)) - <code class="val-group">[</code>0<code class="val-op">, </code>1<code class="val-op">, </code>2<code class="val-op">, </code>3<code class="val-op">, </code>4<code class="val-op">, </code>5<code class="val-op">, </code>6<code class="val-op">, </code>7<code class="val-op">, </code>8<code class="val-op">, </code>9<code class="val-group">]</code> + <code class="variable-group">[</code>0<code class="variable-op">, </code>1<code class="variable-op">, </code>2<code class="variable-op">, </code>3<code class="variable-op">, </code>4<code class="variable-op">, </code>5<code class="variable-op">, </code>6<code class="variable-op">, </code>7<code class="variable-op">, </code>8<code class="variable-op">, </code>9<code class="variable-group">]</code> >>> color(range(100)) - <code class="val-group">[</code>0<code class="val-op">,</code> - 1<code class="val-op">,</code> - 2<code class="val-op">,</code> - 3<code class="val-op">,</code> - 4<code class="val-op">,</code> - <code class="ellipsis">...</code> + <code class="variable-group">[</code>0<code class="variable-op">,</code> + 1<code class="variable-op">,</code> + 2<code class="variable-op">,</code> + 3<code class="variable-op">,</code> + 4<code class="variable-op">,</code> + <code class="variable-ellipsis">...</code> >>> color([1,2,[5,6,[(11,22,33),9],10],11]+[99,98,97,96,95]) - <code class="val-group">[</code>1<code class="val-op">,</code> - 2<code class="val-op">,</code> - <code class="val-group">[</code>5<code class="val-op">, </code>6<code class="val-op">, </code><code class="val-group">[</code><code class="val-group">(</code>11<code class="val-op">, </code>22<code class="val-op">, </code>33<code class="val-group">)</code><code class="val-op">, </code>9<code class="val-group">]</code><code class="val-op">, </code>10<code class="val-group">]</code><code class="val-op">,</code> - 11<code class="val-op">,</code> - 99<code class="val-op">,</code> - <code class="ellipsis">...</code> + <code class="variable-group">[</code>1<code class="variable-op">,</code> + 2<code class="variable-op">,</code> + <code class="variable-group">[</code>5<code class="variable-op">, </code>6<code class="variable-op">, </code><code class="variable-group">[</code><code class="variable-group">(</code>11<code class="variable-op">, </code>22<code class="variable-op">, </code>33<code class="variable-group">)</code><code class="variable-op">, </code>9<code class="variable-group">]</code><code class="variable-op">, </code>10<code class="variable-group">]</code><code class="variable-op">,</code> + 11<code class="variable-op">,</code> + 99<code class="variable-op">,</code> + <code class="variable-ellipsis">...</code> >>> color(set(range(20))) - <code class="val-group">set([</code>0<code class="val-op">,</code> - 1<code class="val-op">,</code> - 2<code class="val-op">,</code> - 3<code class="val-op">,</code> - 4<code class="val-op">,</code> - <code class="ellipsis">...</code> + <code class="variable-group">set([</code>0<code class="variable-op">,</code> + 1<code class="variable-op">,</code> + 2<code class="variable-op">,</code> + 3<code class="variable-op">,</code> + 4<code class="variable-op">,</code> + <code class="variable-ellipsis">...</code> Dictionaries ============ @@ -108,12 +117,12 @@ "op". >>> color({1:33, 2:[1,2,3,{7:'oo'*20}]}) - <code class="val-group">{</code>1<code class="val-op">: </code>33<code class="val-op">,</code> - 2<code class="val-op">: </code><code class="val-group">[</code>1<code class="val-op">,</code> - 2<code class="val-op">,</code> - 3<code class="val-op">,</code> - <code class="val-group">{</code>7<code class="val-op">: </code><code class="val-quote">'</code><code class="val-string">oooooooooooooooooooooooooooooo</code>↵ - <code class="ellipsis">...</code> + <code class="variable-group">{</code>1<code class="variable-op">: </code>33<code class="variable-op">,</code> + 2<code class="variable-op">: </code><code class="variable-group">[</code>1<code class="variable-op">,</code> + 2<code class="variable-op">,</code> + 3<code class="variable-op">,</code> + <code class="variable-group">{</code>7<code class="variable-op">: </code><code class="variable-quote">'</code><code class="variable-string">oooooooooooooooooooooooooooooo</code>↵ + <code class="variable-ellipsis">...</code> Regular Expressions =================== @@ -124,16 +133,17 @@ >>> import re >>> def color_re(s, check_roundtrip=True): + ... colorizer = PyvalColorizer(linelen=55) ... val = colorizer.colorize(re.compile(s)) ... if check_roundtrip: - ... assert textcontent(val._tree) == s, val._tree - ... print val.to_html(None).rstrip() + ... assert textcontent(val._tree)[13:-2] == s, val._tree + ... print val.to_html(None).rstrip()[13:-2] >>> # Literal characters - >>> color_re(u'abc \t\r\n\f\v \xff \uffff \U000fffff', False) - abc \t\r\n\f\v \xff \uffff \U000fffff - >>> color_re(r'\.\^\$\\\*\+\?\{\}\[\]\|\(\)') - \.\^\$\\\*\+\?\{\}\[\]\|\(\) + >>> color_re(u'abc \t\r\n\f\v \xff \uffff', False) + abc \t\r\n\f\v \xff \uffff + >>> color_re(r'\.\^\$\\\*\+\?\{\}\[\]\|\(\)\'') + \.\^\$\\\*\+\?\{\}\[\]\|\(\)\' >>> # Any character & character classes >>> color_re(r".\d\D\s\S\w\W\A^$\b\B\Z") @@ -193,6 +203,33 @@ >>> color_re(r"(?x)This is verbose", False) <code class="re-flags">(?x)</code>Thisisverbose +Line Wrapping +============= +If a line goes beyond linelen, it is wrapped using ``↵`` (which +gets translated to ``\\`` by `to_plaintext()`). + + >>> colorizer = PyvalColorizer(linelen=40) + >>> print colorizer.colorize('x'*100).to_plaintext(None) + 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ + xxxxxxxxxxxxxxxxxxxxx' + +Check that the last line gets a ``↵`` when maxlines is exceeded: + + >>> print colorizer.colorize('x'*1000).to_plaintext(None) + 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\ + ... + +If linebreakok is False, then line wrapping gives an ellipsis instead: + + >>> colorizer = PyvalColorizer(linelen=40, linebreakok=False) + >>> print colorizer.colorize('x'*100).to_plaintext(None) + 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx... + Representation Scores ===================== When colorized representations are built, a score is computed @@ -211,9 +248,10 @@ scores; if the score is too low, then `colorize` will return `None`. >>> def color2(v): - ... pds, score = colorizer.colorize_and_score(v) + ... colorizer = PyvalColorizer(linelen=40) + ... pds = colorizer.colorize(v) ... print 'repr: %s' % pds.to_plaintext(None) - ... print 'score: %s (%s)' % (score, score>0 and 'ok' or 'bad') + ... print 'score: %s (%s)' % (pds.score, pds.score>0 and 'ok' or 'bad') >>> class A: pass @@ -242,3 +280,19 @@ ... score: 1 (ok) +Summary +======= +To generate summary-reprs, use maxlines=1 and linebreakok=False: + + >>> summarizer = PyvalColorizer(linelen=60, maxlines=1, linebreakok=False) + >>> def summarize(v): + ... print summarizer.colorize(v).to_plaintext(None) + + >>> summarize(range(100)) + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16... + >>> summarize('hello\nworld') + 'hello\nworld' + >>> summarize('hello\nworld'*100) + 'hello\nworldhello\nworldhello\nworldhello\nworldhello\nw... + + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-02-14 00:28:00
|
Revision: 1485 http://svn.sourceforge.net/epydoc/?rev=1485&view=rev Author: dvarrazzo Date: 2007-02-13 16:27:58 -0800 (Tue, 13 Feb 2007) Log Message: ----------- - If the callgraph is available, show it in the summary too. Added a cache to avoid running graphviz twice on the same callgraph. Modified Paths: -------------- trunk/epydoc/src/epydoc/apidoc.py trunk/epydoc/src/epydoc/docwriter/html.py Modified: trunk/epydoc/src/epydoc/apidoc.py =================================================================== --- trunk/epydoc/src/epydoc/apidoc.py 2007-02-14 00:24:22 UTC (rev 1484) +++ trunk/epydoc/src/epydoc/apidoc.py 2007-02-14 00:27:58 UTC (rev 1485) @@ -1502,6 +1502,9 @@ under which the exception specified by C{exc} is raised. @type: C{list}""" #} end of "information extracted from docstrings" group + callgraph_uid = None + """@ivar: L{DotGraph}.uid of the call graph for the function. + @type: C{str}""" def is_detailed(self): if super(RoutineDoc, self).is_detailed(): Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2007-02-14 00:24:22 UTC (rev 1484) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2007-02-14 00:27:58 UTC (rev 1485) @@ -349,6 +349,10 @@ self._graph_types = kwargs.get('graphs', ()) or () """Graphs that we should include in our output.""" + self._callgraph_cache = {} + """Map the callgraph L{uid<DotGraph.uid>} to their HTML + representation.""" + # For use with select_variables(): if self._show_private: self._public_filter = None @@ -1512,22 +1516,75 @@ image_file = os.path.join(self._directory, image_url) return graph.to_html(image_file, image_url) - def render_callgraph(self, callgraph): - graph_html = self.render_graph(callgraph, css='graph-with-title') - if graph_html == '': return '' - return ('<div style="display:none" id="%s-div"><center>\n' - '<table border="0" cellpadding="0" cellspacing="0">\n' - ' <tr><td>%s</td></tr>\n' - ' <tr><th>Call Graph</th></tr>\n' - '</table><br />\n</center></div>\n' % - (callgraph.uid, graph_html)) + RE_CALLGRAPH_ID = re.compile(r"""["'](.+-div)['"]""") + + def render_callgraph(self, callgraph, token=""): + """Render the HTML chunk of a callgraph. - def callgraph_link(self, callgraph): + If C{callgraph} is a string, use the L{_callgraph_cache} to return + a pre-rendered HTML chunk. This mostly avoids to run C{dot} twice for + the same callgraph. Else, run the graph and store its HTML output in + the cache. + + @param callgraph: The graph to render or its L{uid<DotGraph.uid>}. + @type callgraph: L{DotGraph} or C{str} + @param token: A string that can be used to make the C{<div>} id + unambiguous, if the callgraph is used more than once in a page. + @type token: C{str} + @return: The HTML representation of the graph. + @rtype: C{str} + """ + if callgraph is None: return "" + + if isinstance(callgraph, basestring): + uid = callgraph + rv = self._callgraph_cache.get(callgraph, "") + + else: + uid = callgraph.uid + graph_html = self.render_graph(callgraph, css='graph-with-title') + if graph_html == '': + rv = "" + else: + rv = ('<div style="display:none" id="%%s-div"><center>\n' + '<table border="0" cellpadding="0" cellspacing="0">\n' + ' <tr><td>%s</td></tr>\n' + ' <tr><th>Call Graph</th></tr>\n' + '</table><br />\n</center></div>\n' % graph_html) + + # Store in the cache the complete HTML chunk without the + # div id, which may be made unambiguous by the token + self._callgraph_cache[uid] = rv + + # Mangle with the graph + if rv: rv = rv % (uid + token) + return rv + + def callgraph_link(self, callgraph, token=""): + """Render the HTML chunk of a callgraph link. + + The link can toggles the visibility of the callgraph rendered using + L{render_callgraph} with matching parameters. + + @param callgraph: The graph to render or its L{uid<DotGraph.uid>}. + @type callgraph: L{DotGraph} or C{str} + @param token: A string that can be used to make the C{<div>} id + unambiguous, if the callgraph is used more than once in a page. + @type token: C{str} + @return: The HTML representation of the graph link. + @rtype: C{str} + """ # Use class=codelink, to match style w/ the source code link. if callgraph is None: return '' + + if isinstance(callgraph, basestring): + uid = callgraph + else: + uid = callgraph.uid + return ('<br /><span class="codelink"><a href="javascript:void(0);" ' 'onclick="toggleCallGraph(\'%s-div\');return false;">' - 'call graph</a></span> ' % callgraph.uid) + 'call graph</a></span> ' % (uid + token)) #//////////////////////////////////////////////////////////// #{ 2.11. Images @@ -1917,8 +1974,9 @@ @param container: The API documentation for the class or module whose summary table we're writing. """ - link = None # link to the source code - + pysrc_link = None + callgraph = None + # If it's a private variable, then mark its <tr>. if var_doc.is_public: tr_class = '' else: tr_class = ' class="private"' @@ -1928,7 +1986,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) + pysrc_link = self.pysrc_link(var_doc.value) + + # Perpare the call-graph, if requested + if 'callgraph' in self._graph_types: + linker = _HTMLDocstringLinker(self, var_doc.value) + callgraph = call_graph([var_doc.value], self.docindex, + linker, var_doc, add_callers=True, + add_callees=True) + if callgraph and callgraph.nodes: + var_doc.value.callgraph_uid = callgraph.uid + else: + callgraph = None else: typ = self.type_descr(var_doc, indent=6) description = self.summary_name(var_doc, link_name=True) @@ -1951,27 +2020,31 @@ self.href(var_doc.container) + ")</em>") # Write the summary line. - self._write_summary_line(out, typ, description, tr_class, link) + self._write_summary_line(out, typ, description, tr_class, pysrc_link, + callgraph) _write_summary_line = compile_template( - """ - _write_summary_line(self, out, typ, description, tr_class, link) - """, + "_write_summary_line(self, out, typ, description, tr_class, " + "pysrc_link, callgraph)", # /------------------------- Template -------------------------\ ''' <tr$tr_class$> <td width="15%" align="right" valign="top" class="summary"> <span class="summary-type">$typ or " "$</span> </td><td class="summary"> - >>> if link is not None: + >>> if pysrc_link is not None or callgraph is not None: <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td>$description$</td> - <td align="right" valign="top">$link$</td> + <td align="right" valign="top"> + $pysrc_link$ + $self.callgraph_link(callgraph, token='-summary')$ + </td> </tr> </table> + $self.render_callgraph(callgraph, token='-summary')$ >>> #endif - >>> if link is None: + >>> if pysrc_link is None and callgraph is None: $description$ >>> #endif </td> @@ -2025,17 +2098,9 @@ for n in arg_names]) rhs = self.docstring_to_html(arg_descr, var_doc.value, 10) arg_descrs.append( (lhs, rhs) ) - # Perpare the call-graph, if requested - if 'callgraph' in self._graph_types: - linker = _HTMLDocstringLinker(self, var_doc.value) - callgraph = call_graph([var_doc.value], self.docindex, - linker, var_doc, add_callers=True, - add_callees=True) - if callgraph is not None and len(callgraph.nodes) == 0: - callgraph = None - else: - callgraph = None - self.write_function_details_entry(out, var_doc, descr, callgraph, + + self.write_function_details_entry(out, var_doc, descr, + var_doc.value.callgraph_uid, rtype, rdescr, arg_descrs, div_class) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-14 00:34:29
|
Revision: 1488 http://svn.sourceforge.net/epydoc/?rev=1488&view=rev Author: edloper Date: 2007-02-13 16:34:27 -0800 (Tue, 13 Feb 2007) Log Message: ----------- - Added --include-log option (feature request #1639425). Currently, it's only useful with --html. The log page is named "epydoc-log.html", and is linked from the footer. - Put option defaults in a global dictionary at the top of the 'argument & config file parsing' section - Added log.close() hook to close logs. Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py trunk/epydoc/src/epydoc/docwriter/html.py trunk/epydoc/src/epydoc/docwriter/html_css.py trunk/epydoc/src/epydoc/log.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2007-02-14 00:34:00 UTC (rev 1487) +++ trunk/epydoc/src/epydoc/cli.py 2007-02-14 00:34:27 UTC (rev 1488) @@ -63,12 +63,14 @@ """ __docformat__ = 'epytext en' -import sys, os, time, re, pickle +import sys, os, time, re, pickle, textwrap from glob import glob from optparse import OptionParser, OptionGroup, SUPPRESS_HELP +import optparse import epydoc from epydoc import log from epydoc.util import wordwrap, run_subprocess, RunSubprocessError +from epydoc.util import plaintext_to_html from epydoc.apidoc import UNKNOWN from epydoc.compat import * import ConfigParser @@ -83,6 +85,15 @@ #{ Argument & Config File Parsing ###################################################################### +OPTION_DEFAULTS = dict( + action="html", show_frames=True, docformat=DEFAULT_DOCFORMAT, + show_private=True, show_imports=False, inheritance="listed", + verbose=0, quiet=0, load_pickle=False, parse=True, introspect=True, + debug=epydoc.DEBUG, profile=False, graphs=[], + list_classes_separately=False, graph_font=None, graph_font_size=None, + include_source_code=True, pstat_files=[], simple_term=False, fail_on=None, + exclude=[], exclude_parse=[], exclude_introspect=[]) + def parse_arguments(): # Construct the option parser. usage = '%prog ACTION [options] NAMES...' @@ -180,6 +191,9 @@ generation_group.add_option( # --no-imports "--no-imports", action="store_false", dest="show_imports", help="Do not list each module's imports. (default)") + generation_group.add_option( # --include-log + '--include-log', action='store_true', dest='include_log', + help=("Include a page with the process log (epydoc-log.html)")) generation_group.add_option( # --show-sourcecode '--show-sourcecode', action='store_true', dest='include_source_code', help=("Include source code with syntax highlighting in the " @@ -285,19 +299,7 @@ optparser.add_option_group(return_group) # Set the option parser's defaults. - optparser.set_defaults(action="html", show_frames=True, - docformat=DEFAULT_DOCFORMAT, - show_private=True, show_imports=False, - inheritance="listed", - verbose=0, quiet=0, load_pickle=False, - parse=True, introspect=True, - debug=epydoc.DEBUG, profile=False, - graphs=[], list_classes_separately=False, - graph_font=None, graph_font_size=None, - include_source_code=True, pstat_files=[], - simple_term=False, fail_on=None, - exclude=[], exclude_parse=[], - exclude_introspect=[]) + optparser.set_defaults(**OPTION_DEFAULTS) # Parse the arguments. options, names = optparser.parse_args() @@ -367,6 +369,7 @@ options.target = options.action # Return parsed args. + options.names = names return options, names def parse_configfiles(configfiles, options, names): @@ -524,6 +527,12 @@ log.error("%s is not a directory" % options.target) sys.exit(1) + if options.include_log: + if options.action == 'html': + log.register_logger(HTMLLogger(options.target, options)) + else: + log.warning("--include-log requires --html") + # Set the default docformat from epydoc import docstringparser docstringparser.DEFAULT_DOCFORMAT = options.docformat @@ -770,10 +779,13 @@ options, names = parse_arguments() try: - if options.profile: - _profile() - else: - main(options, names) + try: + if options.profile: + _profile() + else: + main(options, names) + finally: + log.close() except SystemExit: raise except KeyboardInterrupt: @@ -1169,14 +1181,95 @@ def print_times(self): pass +class HTMLLogger(log.Logger): + """ + A logger used to generate a log of all warnings and messages to an + HTML file. + """ + + FILENAME = "epydoc-log.html" + HEADER = textwrap.dedent('''\ + <?xml version="1.0" encoding="ascii"?> + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "DTD/xhtml1-transitional.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>$title$</title> + <link rel="stylesheet" href="epydoc.css" type="text/css" /> + </head> + + <body bgcolor="white" text="black" link="blue" vlink="#204080" + alink="#204080"> + <h1 class="epydoc">Epydoc Log</h1> + <p class="log">Epydoc started at %s</p>''') + START_BLOCK = '<div class="log-block"><h2 class="log-hdr">%s</h2>' + MESSAGE = '<div class="log-%s"><pre class="log"><b>%s</b>: %s</pre></div>\n' + END_BLOCK = '</div>' + FOOTER = "</body>\n</html>\n" + + def __init__(self, directory, options): + self.start_time = time.time() + self.out = open(os.path.join(directory, self.FILENAME), 'w') + self.out.write(self.HEADER % time.ctime(self.start_time)) + self.is_empty = True + self.options = options + + def write_options(self, options): + self.out.write(self.START_BLOCK % 'Epydoc Options') + msg = '<table border="0" cellpadding="0" cellspacing="0">\n' + opts = [(key, getattr(options, key)) for key in dir(options) + if key not in dir(optparse.Values)] + opts = [(val==OPTION_DEFAULTS.get(key), key, val) + for (key, val) in opts] + for is_default, key, val in sorted(opts): + css = is_default and 'opt-default' or 'opt-changed' + msg += ('<tr class="%s"><td>%s</td><td><tt> = ' + '</tt></td><td><tt>%s</tt></td></tr>' % + (css, key, plaintext_to_html(repr(val)))) + msg += '</table>\n' + self.out.write('<div class="log-info">\n%s</div>\n' % msg) + self.out.write(self.END_BLOCK) + + def start_block(self, header): + self.out.write(self.START_BLOCK % header) + + def end_block(self): + self.out.write(self.END_BLOCK) + + def log(self, level, message): + if message.endswith("(-v) to display markup errors."): return + if level >= log.ERROR: + self.out.write(self.MESSAGE % ('error', 'Error', message)) + self.is_empty = False + elif level >= log.DOCSTRING_WARNING: + self.out.write(self.MESSAGE % ('warning', 'Warning', message)) + self.is_empty = False + + def close(self): + if self.is_empty: + self.out.write('<div class="log-info">' + 'No warnings or errors!</div>') + self.write_options(self.options) + self.out.write('<p class="log">Epydoc finished at %s</p>\n' + '<p class="log">(Elapsed time: %s)</p>' % + (time.ctime(), self._elapsed_time())) + self.out.write(self.FOOTER) + self.out.close() + + def _elapsed_time(self): + secs = int(time.time()-self.start_time) + if secs < 60: + return '%d seconds' % secs + if secs < 3600: + return '%d minutes, %d seconds' % (secs/60, secs%60) + else: + return '%d hours, %d minutes' % (secs/3600, secs%3600) + + ###################################################################### ## main ###################################################################### if __name__ == '__main__': - try: - cli() - except: - print '\n\n' - raise + cli() Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2007-02-14 00:34:00 UTC (rev 1487) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2007-02-14 00:34:27 UTC (rev 1488) @@ -288,6 +288,9 @@ @type include_source_code: C{boolean} @keyword include_source_code: If true, then generate colorized source code files for each python module. + @type include_log: C{boolean} + @keyword include_log: If true, the the footer will include an + href to the page 'epydoc-log.html'. """ self.docindex = docindex @@ -349,6 +352,9 @@ self._graph_types = kwargs.get('graphs', ()) or () """Graphs that we should include in our output.""" + self._include_log = kwargs.get('include_log', False) + """Are we generating an HTML log page?""" + self._callgraph_cache = {} """Map the callgraph L{uid<DotGraph.uid>} to their HTML representation.""" @@ -1653,8 +1659,14 @@ >>> if not short: <table border="0" cellpadding="0" cellspacing="0" width="100%%"> <tr> - <td align="left" class="footer">Generated by Epydoc - $epydoc.__version__$ on $time.asctime()$</td> + <td align="left" class="footer"> + >>> if self._include_log: + <a href="epydoc-log.html">Generated by Epydoc + $epydoc.__version__$ on $time.asctime()$</a> + >>> else: + Generated by Epydoc $epydoc.__version__$ on $time.asctime()$ + >>> #endif + </td> <td align="right" class="footer"> <a href="http://epydoc.sourceforge.net">http://epydoc.sourceforge.net</a> </td> Modified: trunk/epydoc/src/epydoc/docwriter/html_css.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-02-14 00:34:00 UTC (rev 1487) +++ trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-02-14 00:34:27 UTC (rev 1488) @@ -316,8 +316,29 @@ margin: 0; } .nomargin-top { margin-top: 0; } .nomargin { margin-top: 0; margin-bottom: 0; } -""" +/* HTML Log */ +div.log-block { padding: 0; margin: .5em; + background: $log_bg; color: $log_fg; + border: $log_border; } +div.log-error { padding: .5em; margin: .5em; + background: $log_error_bg; color: $log_error_fg; + border: $log_error_border; } +div.log-warning { padding: .5em; margin: .5em; + background: $log_warn_bg; color: $log_warn_fg; + border: $log_warn_border; } +div.log-info { padding: .5em; margin: .5em; + background: $log_info_bg; color: $log_info_fg; + border: $log_info_border; } +h2.log-hdr { background: $log_hdr_bg; color: $log_hdr_fg; + margin: 0; padding: 0.1em 0.5em 0.1em 0.5em; + border-bottom: $log_border; } +p.log { font-weight: bold; } +tr.opt-changed { color: $opt_changed_fg; font-weight: bold; } +tr.opt-default { color: $opt_default_fg; } +pre.log { margin: 0; padding: 0; } +""" + ############################################################ ## Derived stylesheets ############################################################ @@ -425,6 +446,23 @@ py_decorator = '#804020', # Graphs graph_border = '1px solid #000000', + # Log block + log_bg = '#e8f0f8', + log_fg = '#000000', + log_border = '1px solid #000000', + log_hdr_bg = '#70b0ff', + log_hdr_fg = '#000000', + log_error_bg = '#ffb0b0', + log_error_fg = '#000000', + log_error_border = '1px solid #000000', + log_warn_bg = '#ffffb0', + log_warn_fg = '#000000', + log_warn_border = '1px solid #000000', + log_info_bg = '#b0ffb0', + log_info_fg = '#000000', + log_info_border = '1px solid #000000', + opt_changed_fg = '#000000', + opt_default_fg = '#606060', ) _BLUE_COLORS = _WHITE_COLORS.copy() Modified: trunk/epydoc/src/epydoc/log.py =================================================================== --- trunk/epydoc/src/epydoc/log.py 2007-02-14 00:34:00 UTC (rev 1487) +++ trunk/epydoc/src/epydoc/log.py 2007-02-14 00:34:27 UTC (rev 1488) @@ -64,6 +64,11 @@ message. """ + def close(self): + """ + Perform any tasks needed to close this logger. + """ + #//////////////////////////////////////////////////////////// # Message blocks #//////////////////////////////////////////////////////////// @@ -195,4 +200,5 @@ for logger in _loggers: logger.progress(percent, '%s' % message) progress.__doc__ = Logger.progress.__doc__ - +def close(): + for logger in _loggers: logger.close() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-02-14 02:16:39
|
Revision: 1491 http://svn.sourceforge.net/epydoc/?rev=1491&view=rev Author: edloper Date: 2007-02-13 18:16:36 -0800 (Tue, 13 Feb 2007) Log Message: ----------- - Reduced vertical whitespace space in epydoc-log.html Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py trunk/epydoc/src/epydoc/docwriter/html_css.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2007-02-14 01:33:29 UTC (rev 1490) +++ trunk/epydoc/src/epydoc/cli.py 2007-02-14 02:16:36 UTC (rev 1491) @@ -1203,7 +1203,8 @@ <h1 class="epydoc">Epydoc Log</h1> <p class="log">Epydoc started at %s</p>''') START_BLOCK = '<div class="log-block"><h2 class="log-hdr">%s</h2>' - MESSAGE = '<div class="log-%s"><pre class="log"><b>%s</b>: %s</pre></div>\n' + MESSAGE = ('<div class="log-%s"><b>%s</b>: \n' + '%s</div>\n') END_BLOCK = '</div>' FOOTER = "</body>\n</html>\n" @@ -1239,12 +1240,20 @@ def log(self, level, message): if message.endswith("(-v) to display markup errors."): return if level >= log.ERROR: - self.out.write(self.MESSAGE % ('error', 'Error', message)) - self.is_empty = False + self.out.write(self._message('error', message)) + elif level >= log.WARNING: + self.out.write(self._message('warning', message)) elif level >= log.DOCSTRING_WARNING: - self.out.write(self.MESSAGE % ('warning', 'Warning', message)) - self.is_empty = False + self.out.write(self._message('docstring warning', message)) + def _message(self, level, message): + self.is_empty = False + message = plaintext_to_html(message) + if '\n' in message: + message = '<pre class="log">%s</pre>' % message + hdr = ' '.join([w.capitalize() for w in level.split()]) + return self.MESSAGE % (level.split()[-1], hdr, message) + def close(self): if self.is_empty: self.out.write('<div class="log-info">' Modified: trunk/epydoc/src/epydoc/docwriter/html_css.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-02-14 01:33:29 UTC (rev 1490) +++ trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-02-14 02:16:36 UTC (rev 1491) @@ -318,25 +318,25 @@ .nomargin { margin-top: 0; margin-bottom: 0; } /* HTML Log */ -div.log-block { padding: 0; margin: .5em; +div.log-block { padding: 0; margin: .5em 0 .5em 0; background: $log_bg; color: $log_fg; border: $log_border; } -div.log-error { padding: .5em; margin: .5em; +div.log-error { padding: .1em .3em .1em .3em; margin: 4px; background: $log_error_bg; color: $log_error_fg; border: $log_error_border; } -div.log-warning { padding: .5em; margin: .5em; +div.log-warning { padding: .1em .3em .1em .3em; margin: 4px; background: $log_warn_bg; color: $log_warn_fg; border: $log_warn_border; } -div.log-info { padding: .5em; margin: .5em; +div.log-info { padding: .1em .3em .1em .3em; margin: 4px; background: $log_info_bg; color: $log_info_fg; border: $log_info_border; } h2.log-hdr { background: $log_hdr_bg; color: $log_hdr_fg; - margin: 0; padding: 0.1em 0.5em 0.1em 0.5em; - border-bottom: $log_border; } -p.log { font-weight: bold; } + margin: 0; padding: 0em 0.5em 0em 0.5em; + border-bottom: $log_border; font-size: 110%; } +p.log { font-weight: bold; margin: .5em 0 .5em 0; } tr.opt-changed { color: $opt_changed_fg; font-weight: bold; } tr.opt-default { color: $opt_default_fg; } -pre.log { margin: 0; padding: 0; } +pre.log { margin: 0; padding: 0; padding-left: 1em; } """ ############################################################ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-03-07 01:23:20
|
Revision: 1572 http://svn.sourceforge.net/epydoc/?rev=1572&view=rev Author: dvarrazzo Date: 2007-03-06 17:23:18 -0800 (Tue, 06 Mar 2007) Log Message: ----------- - All "free" Epydoc paragraphs are rendered in HTML into ``<p>``\ 's: removed the "HTML postprocessing" required to fix excessive spacing. - Added an ``inline`` attribute to `Ticket` and `Element`. Inline elements are similar tho HTMl ``<span>``; they are rendered in HTML without ``<p>``. Inline elements are, for instance: - list items (fields too); - docstring summaries; - HTML code simplified: no more ``<br><br>`` to accomodate for the lack of ``<p>``. This layout is more CSS-friendly. - Paragraphs vertical margins tweaked. - H3 top margin value set for cross browser consistency (IE and FF have different defaults). Modified Paths: -------------- trunk/epydoc/src/epydoc/docstringparser.py trunk/epydoc/src/epydoc/docwriter/html.py trunk/epydoc/src/epydoc/docwriter/html_css.py trunk/epydoc/src/epydoc/markup/epytext.py trunk/epydoc/src/epydoc/test/encoding.doctest trunk/epydoc/src/epydoc/test/epytext.doctest Modified: trunk/epydoc/src/epydoc/docstringparser.py =================================================================== --- trunk/epydoc/src/epydoc/docstringparser.py 2007-03-06 19:24:12 UTC (rev 1571) +++ trunk/epydoc/src/epydoc/docstringparser.py 2007-03-07 01:23:18 UTC (rev 1572) @@ -507,6 +507,7 @@ """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}.""" +RETURN_PDS._tree.children[0].attribs['inline'] = True ###################################################################### #{ Field Processing Error Messages Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2007-03-06 19:24:12 UTC (rev 1571) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2007-03-07 01:23:18 UTC (rev 1572) @@ -739,11 +739,11 @@ out('<!-- ==================== %s ' % typ.upper() + 'DESCRIPTION ==================== -->\n') out('<h1 class="epydoc">%s %s</h1>' % (typ, shortname)) - out(self.pysrc_link(doc) + '<br /><br />\n') + out('<p class="nomargin-top">%s</p>\n' % self.pysrc_link(doc)) # If the module has a description, then list it. if doc.descr not in (None, UNKNOWN): - out(self.descr(doc, 2)+'<br /><br />\n\n') + out(self.descr(doc, 2)+'\n\n') # Write any standarad metadata (todo, author, etc.) if doc.metadata is not UNKNOWN and doc.metadata: @@ -830,7 +830,7 @@ out('<!-- ==================== %s ' % typ.upper() + 'DESCRIPTION ==================== -->\n') out('<h1 class="epydoc">%s %s</h1>' % (typ, shortname)) - out(self.pysrc_link(doc) + '<br /><br />\n') + out('<p class="nomargin-top">%s</p>\n' % self.pysrc_link(doc)) if ((doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0) or (doc.subclasses not in (UNKNOWN,None) and len(doc.subclasses)>0)): @@ -864,7 +864,7 @@ # If the class has a description, then list it. if doc.descr not in (None, UNKNOWN): - out(self.descr(doc, 2)+'<br /><br />\n\n') + out(self.descr(doc, 2)+'\n\n') # Write any standarad metadata (todo, author, etc.) if doc.metadata is not UNKNOWN and doc.metadata: Modified: trunk/epydoc/src/epydoc/docwriter/html_css.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-03-06 19:24:12 UTC (rev 1571) +++ trunk/epydoc/src/epydoc/docwriter/html_css.py 2007-03-07 01:23:18 UTC (rev 1572) @@ -60,6 +60,7 @@ * defined below). */ body { background: $body_bg; color: $body_fg; } +p { margin-top: 0.5em; margin-bottom: 0.5em; } a:link { color: $body_link; } a:visited { color: $body_visited_link; } dt { font-weight: bold; } @@ -84,7 +85,8 @@ */ h1.epydoc { margin: 0; font-size: +140%; font-weight: bold; } h2.epydoc { font-size: +130%; font-weight: bold; } -h3.epydoc { font-size: +115%; font-weight: bold; } +h3.epydoc { font-size: +115%; font-weight: bold; + margin-top: 0.2em; } td h3.epydoc { font-size: +115%; font-weight: bold; margin-bottom: 0; } table.navbar { background: $navbar_bg; color: $navbar_fg; Modified: trunk/epydoc/src/epydoc/markup/epytext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/epytext.py 2007-03-06 19:24:12 UTC (rev 1571) +++ trunk/epydoc/src/epydoc/markup/epytext.py 2007-03-07 01:23:18 UTC (rev 1572) @@ -367,6 +367,8 @@ if para_token.indent == indent_stack[-1]: # Colorize the paragraph and add it. para = _colorize(doc, para_token, errors) + if para_token.inline: + para.attribs['inline'] = True stack[-1].children.append(para) else: estr = "Improper paragraph indentation." @@ -554,6 +556,11 @@ heading; C{None}, otherwise. Valid heading levels are 0, 1, and 2. + @type inline: C{bool} + @ivar inline: If True, the element is an inline level element, comparable + to an HTML C{<span>} tag. Else, it is a block level element, comparable + to an HTML C{<div>}. + @type PARA: C{string} @cvar PARA: The C{tag} value for paragraph C{Token}s. @type LBLOCK: C{string} @@ -574,7 +581,8 @@ HEADING = "heading" BULLET = "bullet" - def __init__(self, tag, startline, contents, indent, level=None): + def __init__(self, tag, startline, contents, indent, level=None, + inline=False): """ Create a new C{Token}. @@ -591,12 +599,15 @@ @param level: The heading-level of this C{Token} if it is a heading; C{None}, otherwise. @type level: C{int} or C{None} + @param inline: Is this C{Token} inline as a C{<span>}?. + @type inline: C{bool} """ self.tag = tag self.startline = startline self.contents = contents self.indent = indent self.level = level + self.inline = inline def __repr__(self): """ @@ -794,14 +805,16 @@ linenum += 1 # Add the bullet token. - tokens.append(Token(Token.BULLET, start, bcontents, bullet_indent)) + tokens.append(Token(Token.BULLET, start, bcontents, bullet_indent, + inline=True)) # Add the paragraph token. pcontents = ([lines[start][para_start:].strip()] + [line.strip() for line in lines[start+1:linenum]]) pcontents = ' '.join(pcontents).strip() if pcontents: - tokens.append(Token(Token.PARA, start, pcontents, para_indent)) + tokens.append(Token(Token.PARA, start, pcontents, para_indent, + inline=True)) # Return the linenum after the paragraph token ends. return linenum @@ -1768,25 +1781,14 @@ indent+2, seclevel) for c in tree.children] - # Get rid of unnecessary <P>...</P> tags; they introduce extra - # space on most browsers that we don't want. - for i in range(len(variables)-1): - if (not isinstance(tree.children[i], basestring) and - tree.children[i].tag == 'para' and - (isinstance(tree.children[i+1], basestring) or - tree.children[i+1].tag != 'para')): - variables[i] = ' '*(indent+2)+variables[i][5+indent:-5]+'\n' - if (tree.children and - not isinstance(tree.children[-1], basestring) and - tree.children[-1].tag == 'para'): - variables[-1] = ' '*(indent+2)+variables[-1][5+indent:-5]+'\n' - # Construct the HTML string for the variables. childstr = ''.join(variables) # Perform the approriate action for the DOM tree type. if tree.tag == 'para': - return wordwrap('<p>%s</p>' % childstr, indent) + return wordwrap( + (tree.attribs.get('inline') and '%s' or '<p>%s</p>') % childstr, + indent) elif tree.tag == 'code': style = tree.attribs.get('style') if style: @@ -2002,7 +2004,7 @@ # Extract the first sentence. parachildren = variables[0].children - para = Element('para') + para = Element('para', inline=True) doc.children.append(para) for parachild in parachildren: if isinstance(parachild, basestring): Modified: trunk/epydoc/src/epydoc/test/encoding.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/encoding.doctest 2007-03-06 19:24:12 UTC (rev 1571) +++ trunk/epydoc/src/epydoc/test/encoding.doctest 2007-03-07 01:23:18 UTC (rev 1572) @@ -27,27 +27,27 @@ >>> testencoding('''# -*- coding: cp874 -*- ... """abc ABC 123 \x80 \x85""" ... ''') - abc ABC 123 € … + <p>abc ABC 123 € …</p> >>> testencoding('''# -*- coding: cp1250 -*- ... """abc ABC 123 \x80 \x82 \x84 \x85 \xff""" ... ''') - abc ABC 123 € ‚ „ … ˙ + <p>abc ABC 123 € ‚ „ … ˙</p> >>> testencoding('''# -*- coding: cp1251 -*- ... """abc ABC 123 \x80 \x81 \x82 \xff""" ... ''') - abc ABC 123 Ђ Ѓ ‚ я + <p>abc ABC 123 Ђ Ѓ ‚ я</p> >>> testencoding('''# -*- coding: cp1252 -*- ... """abc ABC 123 \x80 \x82 \x83 \xff""" ... ''') - abc ABC 123 € ‚ ƒ ÿ + <p>abc ABC 123 € ‚ ƒ ÿ</p> >>> testencoding('''# -*- coding: cp1253 -*- ... """abc ABC 123 \x80 \x82 \x83 \xfe""" ... ''') - abc ABC 123 € ‚ ƒ ώ + <p>abc ABC 123 € ‚ ƒ ώ</p> Unicode tests: @@ -71,52 +71,52 @@ <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> - 0x10000-0x10ffff range: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> >>> # UTF-8 with a BOM & a coding directive: >>> 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: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> >>> # UTF-8 with a BOM & no coding directive: >>> testencoding(utf8_bom+utf8_test) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> - 0x10000-0x10ffff range: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> Tests for KOI8-R: >>> testencoding('''# -*- coding: koi8-r -*- ... """abc ABC 123 \x80 \x82 \x83 \xff""" ... ''') - abc ABC 123 ─ ┌ ┐ Ъ + <p>abc ABC 123 ─ ┌ ┐ Ъ</p> Tests for 'coding' directive on the second line: >>> testencoding('''\n# -*- coding: cp1252 -*- ... """abc ABC 123 \x80 \x82 \x83 \xff""" ... ''') - abc ABC 123 € ‚ ƒ ÿ + <p>abc ABC 123 € ‚ ƒ ÿ</p> >>> testencoding('''# comment on the first line.\n# -*- coding: cp1252 -*- ... """abc ABC 123 \x80 \x82 \x83 \xff""" ... ''') - abc ABC 123 € ‚ ƒ ÿ + <p>abc ABC 123 € ‚ ƒ ÿ</p> >>> 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: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> >>> testencoding("# comment\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: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> Tests for shift-jis @@ -132,12 +132,12 @@ >>> testencoding('''# -*- coding: utf-8 -*- ... """abc ABC 123 \xc2\x80 \xdf\xbf \xe0\xa0\x80""" ... ''') - abc ABC 123 € ߿ ࠀ + <p>abc ABC 123 € ߿ ࠀ</p> >>> testencoding('''# -*- coding: utf-8 -*- ... u"""abc ABC 123 \xc2\x80 \xdf\xbf \xe0\xa0\x80""" ... ''') - abc ABC 123 € ߿ ࠀ + <p>abc ABC 123 € ߿ ࠀ</p> Under special circumstances, we may not be able to tell what the proper encoding for a docstring is. This happens if: @@ -166,33 +166,33 @@ <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> - 0x10000-0x10ffff range: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> >>> 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: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> >>> 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: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> >>> 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: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> >>> 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: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> >>> testencoding(utf8_bom+utf8_test, parse=False) <p>abc ABC 123</p> <p>0x80-0x7ff range: €  ߾ ߿</p> <p>0x800-0xffff range: ࠀ ࠁ  </p> - 0x10000-0x10ffff range: 𐀀 𐀁   + <p>0x10000-0x10ffff range: 𐀀 𐀁  </p> Context checks ============== @@ -219,12 +219,12 @@ ... ''') abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ + <p>abc ABC 123 € ߿ ࠀ</p> abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ - abc ABC 123 € ߿ ࠀ >>> testencoding('''# -*- coding: utf-8 -*- ... class A: @@ -238,11 +238,11 @@ ... z = property(doc=u"abc ABC 123 \xc2\x80 \xdf\xbf \xe0\xa0\x80") ... ''') abc ABC 123 € ߿ ࠀ + <p>abc ABC 123 € ߿ ࠀ</p> abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ abc ABC 123 € ߿ ࠀ - abc ABC 123 € ߿ ࠀ Modified: trunk/epydoc/src/epydoc/test/epytext.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/epytext.doctest 2007-03-06 19:24:12 UTC (rev 1571) +++ trunk/epydoc/src/epydoc/test/epytext.doctest 2007-03-07 01:23:18 UTC (rev 1572) @@ -45,14 +45,14 @@ ... @foo: This is a field.""") <para>This is a paragraph.</para> <fieldlist><field><tag>foo</tag> - <para>This is a field.</para></field></fieldlist> + <para inline=True>This is a field.</para></field></fieldlist> >>> print testparse(""" ... This is a paragraph. ... @foo: This is a field.""") <para>This is a paragraph.</para> <fieldlist><field><tag>foo</tag> - <para>This is a field.</para></field></fieldlist> + <para inline=True>This is a field.</para></field></fieldlist> >>> print testparse(""" ... This is a paragraph. @@ -60,23 +60,23 @@ ... Hello.""") <para>This is a paragraph.</para> <fieldlist><field><tag>foo</tag> - <para>This is a field. Hello.</para></field></fieldlist> - + <para inline=True>This is a field. Hello.</para></field> + </fieldlist> >>> print testparse("""Paragraph\n@foo: field""") <para>Paragraph</para> <fieldlist><field><tag>foo</tag> - <para>field</para></field></fieldlist> + <para inline=True>field</para></field></fieldlist> >>> print testparse("""Paragraph\n\n@foo: field""") <para>Paragraph</para> <fieldlist><field><tag>foo</tag> - <para>field</para></field></fieldlist> + <para inline=True>field</para></field></fieldlist> >>> print testparse("""\nParagraph\n@foo: field""") <para>Paragraph</para> <fieldlist><field><tag>foo</tag> - <para>field</para></field></fieldlist> + <para inline=True>field</para></field></fieldlist> Make sure thta unindented lists are not allowed: @@ -122,20 +122,22 @@ >>> print testparse("""Paragraph\n- list item""") <para>Paragraph</para> - <ulist><li><para>list item</para></li></ulist> + <ulist><li><para inline=True>list item</para></li></ulist> Make sure that indented lists are allowed: >>> print testparse('This is a paragraph.\n - This is a list item.\n'+ ... 'This is a paragraph') <para>This is a paragraph.</para> - <ulist><li><para>This is a list item.</para></li></ulist> + <ulist><li><para inline=True>This is a list item.</para></li> + </ulist> <para>This is a paragraph</para> >>> print testparse('This is a paragraph.\n\n - This is a list item.'+ ... '\n\nThis is a paragraph') <para>This is a paragraph.</para> - <ulist><li><para>This is a list item.</para></li></ulist> + <ulist><li><para inline=True>This is a list item.</para></li> + </ulist> <para>This is a paragraph</para> >>> print testparse(""" @@ -145,7 +147,8 @@ ... ... This is a paragraph""") <para>This is a paragraph.</para> - <ulist><li><para>This is a list item.</para></li></ulist> + <ulist><li><para inline=True>This is a list item.</para></li> + </ulist> <para>This is a paragraph</para> >>> print testparse(""" @@ -154,18 +157,22 @@ ... - 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> + <ulist><li><para inline=True>This is a list item.</para></li> + </ulist> <para>This is a paragraph</para> >>> print testparse(""" ... - This is a list item.""") - <ulist><li><para>This is a list item.</para></li></ulist> + <ulist><li><para inline=True>This is a list item.</para></li> + </ulist> >>> print testparse("""- This is a list item.""") - <ulist><li><para>This is a list item.</para></li></ulist> + <ulist><li><para inline=True>This is a list item.</para></li> + </ulist> >>> print testparse("""\n- This is a list item.""") - <ulist><li><para>This is a list item.</para></li></ulist> + <ulist><li><para inline=True>This is a list item.</para></li> + </ulist> Basic list tests: @@ -176,10 +183,10 @@ >>> LI3 = " - This is a list\n item." >>> LI4 = "\n - This is a list\n item." >>> PARA = ('<para>This is a paragraph.</para>') - >>> ONELIST = ('<ulist><li><para>This is a '+ + >>> ONELIST = ('<ulist><li><para inline=True>This is a '+ ... 'list item.</para></li></ulist>') - >>> TWOLIST = ('<ulist><li><para>This is a '+ - ... 'list item.</para></li><li><para>This is a '+ + >>> TWOLIST = ('<ulist><li><para inline=True>This is a '+ + ... 'list item.</para></li><li><para inline=True>This is a '+ ... 'list item.</para></li></ulist>') >>> for p in (P1, P2): @@ -198,7 +205,7 @@ ... PARA+TWOLIST+PARA) >>> LI5 = " - This is a list item.\n\n It contains two paragraphs." - >>> LI5LIST = ('<ulist><li><para>This is a list item.</para>'+ + >>> LI5LIST = ('<ulist><li><para inline=True>This is a list item.</para>'+ ... '<para>It contains two paragraphs.</para></li></ulist>') >>> checkparse(LI5, LI5LIST) >>> checkparse('%s\n%s' % (P1, LI5), PARA+LI5LIST) @@ -206,7 +213,7 @@ >>> LI6 = (" - This is a list item with a literal block::\n" + ... " hello\n there") - >>> LI6LIST = ('<ulist><li><para>This is a list item with a literal '+ + >>> LI6LIST = ('<ulist><li><para inline=True>This is a list item with a literal '+ ... 'block:</para><literalblock> hello\n there'+ ... '</literalblock></li></ulist>') >>> checkparse(LI6, LI6LIST) @@ -216,10 +223,10 @@ Item wrap tests: >>> LI = "- This is a list\n item." - >>> ONELIST = ('<ulist><li><para>This is a '+ + >>> ONELIST = ('<ulist><li><para inline=True>This is a '+ ... 'list item.</para></li></ulist>') - >>> TWOLIST = ('<ulist><li><para>This is a '+ - ... 'list item.</para></li><li><para>This is a '+ + >>> TWOLIST = ('<ulist><li><para inline=True>This is a '+ + ... 'list item.</para></li><li><para inline=True>This is a '+ ... 'list item.</para></li></ulist>') >>> for indent in ('', ' '): ... for nl1 in ('', '\n'): @@ -229,7 +236,7 @@ Summary ======= -The implementation of the summaization function works as expected. +The implementation of the summarization function works as expected. >>> from epydoc.markup import epytext >>> def getsummary(s): @@ -298,14 +305,14 @@ ... return (v or '').rstrip() >>> print epytext2html("{1:{2:3}}") -{1:{2:3}} +<p>{1:{2:3}}</p> >>> print epytext2html("C{{1:{2:3}}}") -<code>{1:{2:3}}</code> +<p><code>{1:{2:3}}</code></p> >>> print epytext2html("{1:C{{2:3}}}") -{1:<code>{2:3}</code>} +<p>{1:<code>{2:3}</code>}</p> >>> print epytext2html("{{{}{}}{}}") -{{{}{}}{}} +<p>{{{}{}}{}}</p> >>> print epytext2html("{{E{lb}E{lb}E{lb}}}") -{{{{{}} +<p>{{{{{}}</p> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-03-07 02:55:15
|
Revision: 1574 http://svn.sourceforge.net/epydoc/?rev=1574&view=rev Author: dvarrazzo Date: 2007-03-06 18:55:14 -0800 (Tue, 06 Mar 2007) Log Message: ----------- - Fixed summarization for plaintext markup. If a docstring had one (or more) line not ending with a full stop, but separated from the rest of the docstring by a blank line, and there was a full stop somewhere in the following paragraphs, the docstring was summarized up to the full stop instead of the blank line. Such docstrings appear in many places in the stdlib. - Test case added. - Pre-compiling the regular expression to recognize the summary. Modified Paths: -------------- 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/plaintext.doctest Modified: trunk/epydoc/src/epydoc/markup/epytext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/epytext.py 2007-03-07 01:26:50 UTC (rev 1573) +++ trunk/epydoc/src/epydoc/markup/epytext.py 2007-03-07 02:55:14 UTC (rev 1574) @@ -1969,6 +1969,8 @@ # Assume that anything else can be passed through. return childstr + _SUMMARY_RE = re.compile(r'(\s*[\w\W]*?\.)(\s|$)') + def summary(self): if self._tree is None: return self, False tree = self._tree @@ -2008,7 +2010,7 @@ doc.children.append(para) for parachild in parachildren: if isinstance(parachild, basestring): - m = re.match(r'(\s*[\w\W]*?\.)(\s|$)', parachild) + m = self._SUMMARY_RE.match(parachild) if m: para.children.append(m.group(1)) long_docs |= parachild is not parachildren[-1] Modified: trunk/epydoc/src/epydoc/markup/javadoc.py =================================================================== --- trunk/epydoc/src/epydoc/markup/javadoc.py 2007-03-07 01:26:50 UTC (rev 1573) +++ trunk/epydoc/src/epydoc/markup/javadoc.py 2007-03-07 02:55:14 UTC (rev 1574) @@ -219,13 +219,15 @@ def to_plaintext(self, docstring_linker, **options): return self._docstring + _SUMMARY_RE = re.compile(r'(\s*[\w\W]*?\.)(\s|$)') + # Jeff's hack to get summary working def summary(self): # 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) + m = self._SUMMARY_RE.match(doc) if m: other = doc[m.end():] return (ParsedJavadocDocstring(m.group(1)), Modified: trunk/epydoc/src/epydoc/markup/plaintext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/plaintext.py 2007-03-07 01:26:50 UTC (rev 1573) +++ trunk/epydoc/src/epydoc/markup/plaintext.py 2007-03-07 02:55:14 UTC (rev 1574) @@ -50,8 +50,10 @@ return '\n'.join([' '*indent+l for l in lines])+'\n' return self._text+'\n' + _SUMMARY_RE = re.compile(r'(\s*[\w\W]*?(?:\.(\s|$)|[\n][\t ]*[\n]))') + def summary(self): - m = re.match(r'(\s*[\w\W]*?\.)(\s|$)', self._text) + m = self._SUMMARY_RE.match(self._text) if m: other = self._text[m.end():] return (ParsedPlaintextDocstring(m.group(1), verbatim=0), Modified: trunk/epydoc/src/epydoc/markup/restructuredtext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/restructuredtext.py 2007-03-07 01:26:50 UTC (rev 1573) +++ trunk/epydoc/src/epydoc/markup/restructuredtext.py 2007-03-07 02:55:14 UTC (rev 1574) @@ -291,6 +291,7 @@ def visit_document(self, node): self.summary = None + _SUMMARY_RE = re.compile(r'(\s*[\w\W]*?\.)(\s|$)') def visit_paragraph(self, node): if self.summary is not None: # found a paragraph after the first one @@ -302,7 +303,7 @@ # Extract the first sentence. for child in node: if isinstance(child, docutils.nodes.Text): - m = re.match(r'(\s*[\w\W]*?\.)(\s|$)', child.data) + m = self._SUMMARY_RE.match(child.data) if m: summary_pieces.append(docutils.nodes.Text(m.group(1))) other = child.data[m.end():] Modified: trunk/epydoc/src/epydoc/test/plaintext.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/plaintext.doctest 2007-03-07 01:26:50 UTC (rev 1573) +++ trunk/epydoc/src/epydoc/test/plaintext.doctest 2007-03-07 02:55:14 UTC (rev 1574) @@ -52,3 +52,19 @@ ... This is detached ... """) ('Other lines without period...', True) + +In 3.0beta1 docstrings such this were not correctly summarized. + +>>> getsummary("""A user-defined wrapper around string objects +... +... Note: string objects have grown methods in Python 1.6 +... This module requires Python 1.6 or later. +... """) +('A user-defined wrapper around string objects', True) + +>>> getsummary("""This is more tricky +... than the test before +... +... but i am looking for the same bug. +... """) +('This is more tricky\nthan the test before', True) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dva...@us...> - 2007-03-09 23:26:24
|
Revision: 1577 http://svn.sourceforge.net/epydoc/?rev=1577&view=rev Author: dvarrazzo Date: 2007-03-09 15:26:21 -0800 (Fri, 09 Mar 2007) Log Message: ----------- - Small optimization trick: ``in`` is way faster than ``has_key()``. The former is a single opcode while the latter involves a lookup and the call to a bound method. Modified Paths: -------------- trunk/epydoc/src/epydoc/docparser.py trunk/epydoc/src/epydoc/docwriter/html.py trunk/epydoc/src/epydoc/markup/__init__.py trunk/epydoc/src/epydoc/markup/epytext.py trunk/epydoc/src/epydoc/markup/restructuredtext.py Modified: trunk/epydoc/src/epydoc/docparser.py =================================================================== --- trunk/epydoc/src/epydoc/docparser.py 2007-03-09 23:08:24 UTC (rev 1576) +++ trunk/epydoc/src/epydoc/docparser.py 2007-03-09 23:26:21 UTC (rev 1577) @@ -230,7 +230,7 @@ except ValueError, e: raise ImportError('%s' % e) # Check the cache, first. - if _moduledoc_cache.has_key(filename): + if filename in _moduledoc_cache: return _moduledoc_cache[filename] log.info("Parsing %s" % filename) @@ -1871,18 +1871,18 @@ # Locals if isinstance(parent_docs[-1], NamespaceDoc): - if parent_docs[-1].variables.has_key(identifier): + if identifier in parent_docs[-1].variables: return parent_docs[-1].variables[identifier] # Globals (aka the containing module) if isinstance(parent_docs[0], NamespaceDoc): - if parent_docs[0].variables.has_key(identifier): + if identifier in parent_docs[0].variables: return parent_docs[0].variables[identifier] # Builtins builtins = epydoc.docintrospecter.introspect_docs(__builtin__) if isinstance(builtins, NamespaceDoc): - if builtins.variables.has_key(identifier): + if identifier in builtins.variables: return builtins.variables[identifier] # We didn't find it; return None. Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2007-03-09 23:08:24 UTC (rev 1576) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2007-03-09 23:26:21 UTC (rev 1577) @@ -1389,7 +1389,7 @@ if os.path.exists(cssname): try: css = open(cssname).read() except: raise IOError("Can't open CSS file: %r" % cssname) - elif STYLESHEETS.has_key(cssname): + elif cssname in STYLESHEETS: css = STYLESHEETS[cssname][0] else: raise IOError("Can't find CSS file: %r" % cssname) Modified: trunk/epydoc/src/epydoc/markup/__init__.py =================================================================== --- trunk/epydoc/src/epydoc/markup/__init__.py 2007-03-09 23:08:24 UTC (rev 1576) +++ trunk/epydoc/src/epydoc/markup/__init__.py 2007-03-09 23:26:21 UTC (rev 1577) @@ -200,7 +200,7 @@ printed, then do nothing. """ global _parse_warnings - if _parse_warnings.has_key(estr): return + if estr in _parse_warnings: return _parse_warnings[estr] = 1 log.warning(estr) Modified: trunk/epydoc/src/epydoc/markup/epytext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/epytext.py 2007-03-09 23:08:24 UTC (rev 1576) +++ trunk/epydoc/src/epydoc/markup/epytext.py 2007-03-09 23:26:21 UTC (rev 1577) @@ -1021,7 +1021,7 @@ if (end>0) and 'A' <= str[end-1] <= 'Z': if (end-1) > start: stack[-1].children.append(str[start:end-1]) - if not _COLORIZING_TAGS.has_key(str[end-1]): + if str[end-1] not in _COLORIZING_TAGS: estr = "Unknown inline markup tag." errors.append(ColorizingError(estr, token, end-1)) stack.append(Element('unknown')) @@ -1056,7 +1056,7 @@ errors.append(ColorizingError(estr, token, end)) else: symb = stack[-1].children[0] - if _SYMBOLS.has_key(symb): + if symb in _SYMBOLS: # It's a symbol stack[-2].children[-1] = Element('symbol', symb) else: @@ -1071,7 +1071,7 @@ errors.append(ColorizingError(estr, token, end)) else: escp = stack[-1].children[0] - if _ESCAPES.has_key(escp): + if escp in _ESCAPES: # It's an escape from _ESCPAES stack[-2].children[-1] = _ESCAPES[escp] elif len(escp) == 1: Modified: trunk/epydoc/src/epydoc/markup/restructuredtext.py =================================================================== --- trunk/epydoc/src/epydoc/markup/restructuredtext.py 2007-03-09 23:08:24 UTC (rev 1576) +++ trunk/epydoc/src/epydoc/markup/restructuredtext.py 2007-03-09 23:26:21 UTC (rev 1577) @@ -413,7 +413,7 @@ is_fatal=0)) # Use a @newfield to let it be displayed as-is. - if not self._newfields.has_key(tagname.lower()): + if tagname.lower() not in self._newfields: newfield = Field('newfield', tagname.lower(), parse(tagname, 'plaintext')) self.fields.append(newfield) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-09-23 15:07:38
|
Revision: 1618 http://epydoc.svn.sourceforge.net/epydoc/?rev=1618&view=rev Author: edloper Date: 2007-09-23 08:07:34 -0700 (Sun, 23 Sep 2007) Log Message: ----------- - Added --redundant-details option: "Include values in the details lists even if all info about them is already provided by the summary table." Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py trunk/epydoc/src/epydoc/docwriter/html.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2007-09-23 14:33:08 UTC (rev 1617) +++ trunk/epydoc/src/epydoc/cli.py 2007-09-23 15:07:34 UTC (rev 1618) @@ -136,7 +136,8 @@ list_classes_separately=False, graph_font=None, graph_font_size=None, include_source_code=True, pstat_files=[], simple_term=False, fail_on=None, exclude=[], exclude_parse=[], exclude_introspect=[], - external_api=[],external_api_file=[],external_api_root=[]) + external_api=[],external_api_file=[],external_api_root=[], + redundant_details=False) def parse_arguments(): # Construct the option parser. @@ -285,6 +286,11 @@ action='store_true', dest='include_log', help=("Include a page with the process log (epydoc-log.html)")) + generation_group.add_option( + '--redundant-details', + action='store_true', dest='redundant_details', + help=("Include values in the details lists even if all info " + "about them is already provided by the summary table.")) output_group = OptionGroup(optparser, 'Output Options') optparser.add_option_group(output_group) @@ -547,6 +553,8 @@ options.include_source_code = _str_to_bool(val, optname) elif optname in ('include-log', 'include_log'): options.include_log = _str_to_bool(val, optname) + elif optname in ('redundant-details', 'redundant_details'): + options.redundant_details = _str_to_bool(val, optname) # Output options elif optname == 'name': Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2007-09-23 14:33:08 UTC (rev 1617) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2007-09-23 15:07:34 UTC (rev 1618) @@ -359,6 +359,10 @@ """Map the callgraph L{uid<DotGraph.uid>} to their HTML representation.""" + self._redundant_details = kwargs.get('redundant_details', False) + """If true, then include objects in the details list even if all + info about them is already provided by the summary table.""" + # For use with select_variables(): if self._show_private: self._public_filter = None @@ -2049,7 +2053,7 @@ else: tr_class = ' class="private"' # Decide an anchor or a link is to be generated. - link_name = var_doc.is_detailed() + link_name = self._redundant_details or var_doc.is_detailed() anchor = not link_name # Construct the HTML code for the type (cell 1) & description @@ -2131,16 +2135,20 @@ def write_details_list(self, out, heading, doc, value_type): # Get a list of the VarDocs we should describe. + if self._redundant_details: + detailed = None + else: + detailed = True if isinstance(doc, ClassDoc): var_docs = doc.select_variables(value_type=value_type, imported=False, inherited=False, public=self._public_filter, - detailed=True) + detailed=detailed) else: var_docs = doc.select_variables(value_type=value_type, imported=False, public=self._public_filter, - detailed=True) + detailed=detailed) if not var_docs: return # Write a header This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-09-24 00:49:37
|
Revision: 1629 http://epydoc.svn.sourceforge.net/epydoc/?rev=1629&view=rev Author: edloper Date: 2007-09-23 17:49:36 -0700 (Sun, 23 Sep 2007) Log Message: ----------- - Changed all sites that expected DottedName to raise an exception to use the strict=True option, to make sure it does. Modified Paths: -------------- trunk/epydoc/src/epydoc/docbuilder.py trunk/epydoc/src/epydoc/docintrospecter.py trunk/epydoc/src/epydoc/docstringparser.py Modified: trunk/epydoc/src/epydoc/docbuilder.py =================================================================== --- trunk/epydoc/src/epydoc/docbuilder.py 2007-09-24 00:48:48 UTC (rev 1628) +++ trunk/epydoc/src/epydoc/docbuilder.py 2007-09-24 00:49:36 UTC (rev 1629) @@ -1213,7 +1213,7 @@ hasattr(val_doc.pyval, '__name__')): try: name = DottedName(DottedName.UNREACHABLE, - val_doc.pyval.__name__) + val_doc.pyval.__name__, strict=True) except DottedName.InvalidDottedName: name = DottedName(DottedName.UNREACHABLE) else: Modified: trunk/epydoc/src/epydoc/docintrospecter.py =================================================================== --- trunk/epydoc/src/epydoc/docintrospecter.py 2007-09-24 00:48:48 UTC (rev 1628) +++ trunk/epydoc/src/epydoc/docintrospecter.py 2007-09-24 00:49:36 UTC (rev 1629) @@ -157,7 +157,7 @@ pyid = id(value) val_doc = _valuedoc_cache.get(pyid) if val_doc is None: - try: canonical_name = get_canonical_name(value) + try: canonical_name = get_canonical_name(value, strict=True) except DottedName.InvalidDottedName: canonical_name = UNKNOWN val_doc = ValueDoc(pyval=value, canonical_name = canonical_name, docs_extracted_by='introspecter') @@ -592,7 +592,7 @@ name) return None -def get_canonical_name(value): +def get_canonical_name(value, strict=False): """ @return: the canonical name for C{value}, or C{UNKNOWN} if no canonical name can be found. Currently, C{get_canonical_name} @@ -606,30 +606,31 @@ # Get the name via introspection. if isinstance(value, ModuleType): - dotted_name = DottedName(value.__name__) + dotted_name = DottedName(value.__name__, strict=strict) elif isclass(value): if value.__module__ == '__builtin__': - dotted_name = DottedName(value.__name__) + dotted_name = DottedName(value.__name__, strict=strict) else: - dotted_name = DottedName(value.__module__, value.__name__) + dotted_name = DottedName(value.__module__, value.__name__, + strict=strict) elif (inspect.ismethod(value) and value.im_self is not None and value.im_class is ClassType and not value.__name__.startswith('<')): # class method. class_name = get_canonical_name(value.im_self) if class_name is UNKNOWN: return UNKNOWN - dotted_name = DottedName(class_name, value.__name__) + dotted_name = DottedName(class_name, value.__name__, strict=strict) elif (inspect.ismethod(value) and not value.__name__.startswith('<')): class_name = get_canonical_name(value.im_class) if class_name is UNKNOWN: return UNKNOWN - dotted_name = DottedName(class_name, value.__name__) + dotted_name = DottedName(class_name, value.__name__, strict=strict) elif (isinstance(value, FunctionType) and not value.__name__.startswith('<')): module_name = _find_function_module(value) if module_name is None: return UNKNOWN - dotted_name = DottedName(module_name, value.__name__) + dotted_name = DottedName(module_name, value.__name__, strict=strict) else: return UNKNOWN Modified: trunk/epydoc/src/epydoc/docstringparser.py =================================================================== --- trunk/epydoc/src/epydoc/docstringparser.py 2007-09-24 00:48:48 UTC (rev 1628) +++ trunk/epydoc/src/epydoc/docstringparser.py 2007-09-24 00:49:36 UTC (rev 1629) @@ -693,7 +693,7 @@ """Record the fact that C{api_doc} can raise the exception named C{tag} in C{api_doc.exception_descrs}.""" _check(api_doc, tag, arg, context=RoutineDoc, expect_arg='single') - try: name = DottedName(arg) + try: name = DottedName(arg, strict=True) except DottedName.InvalidDottedName: name = arg api_doc.exception_descrs.append( (name, descr) ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-09-25 23:33:02
|
Revision: 1649 http://epydoc.svn.sourceforge.net/epydoc/?rev=1649&view=rev Author: edloper Date: 2007-09-25 16:32:59 -0700 (Tue, 25 Sep 2007) Log Message: ----------- - Added warnings for unused identifiers in @group and @sort fields. This helps catch typos, eg: "@group foo: tree_wlaker" Modified Paths: -------------- trunk/epydoc/src/epydoc/apidoc.py trunk/epydoc/src/epydoc/docbuilder.py Modified: trunk/epydoc/src/epydoc/apidoc.py =================================================================== --- trunk/epydoc/src/epydoc/apidoc.py 2007-09-25 22:08:01 UTC (rev 1648) +++ trunk/epydoc/src/epydoc/apidoc.py 2007-09-25 23:32:59 UTC (rev 1649) @@ -994,17 +994,22 @@ # Add any variables that are listed in sort_spec if self.sort_spec is not UNKNOWN: + unused_idents = set(self.sort_spec) for ident in self.sort_spec: if ident in unsorted: - self.sorted_variables.append(unsorted[ident]) - del unsorted[ident] + self.sorted_variables.append(unsorted.pop(ident)) + unused_idents.discard(ident) elif '*' in ident: regexp = re.compile('^%s$' % ident.replace('*', '(.*)')) # sort within matching group? for name, var_doc in unsorted.items(): if regexp.match(name): - self.sorted_variables.append(var_doc) - unsorted.remove(var_doc) + self.sorted_variables.append(unsorted.pop(name)) + unused_idents.discard(ident) + for ident in unused_idents: + log.warning("@sort: %s.%s not found" % + (self.canonical_name, ident)) + # Add any remaining variables in alphabetical order. var_docs = unsorted.items() @@ -1022,6 +1027,7 @@ assert len(self.sorted_variables) == len(self.variables) elts = [(v.name, v) for v in self.sorted_variables] + self._unused_groups = dict([(n,set(i)) for (n,i) in self.group_specs]) self.variable_groups = self._init_grouping(elts) def group_names(self): @@ -1057,27 +1063,37 @@ return {'': [elt[1] for elt in elts]} ungrouped = set([elt_doc for (elt_name, elt_doc) in elts]) + + ungrouped = dict(elts) groups = {} - for (group_name, elt_names) in self.group_specs: - group_re = re.compile('|'.join([n.replace('*','.*')+'$' - for n in elt_names])) - group = groups.get(group_name, []) - for elt_name, elt_doc in list(elts): - if group_re.match(elt_name): - group.append(elt_doc) - if elt_doc in ungrouped: - ungrouped.remove(elt_doc) - else: - # [xx] might just be listed in the same group twice! - log.warning("%s.%s is in multiple groups" % - (self.canonical_name, elt_name)) - groups[group_name] = group + for elt_name, elt_doc in elts: + for (group_name, idents) in self.group_specs: + group = groups.setdefault(group_name, []) + unused_groups = self._unused_groups[group_name] + for ident in idents: + if re.match('^%s$' % ident.replace('*', '(.*)'), elt_name): + unused_groups.discard(ident) + if elt_name in ungrouped: + group.append(ungrouped.pop(elt_name)) + else: + log.warning("%s.%s in multiple groups" % + (self.canonical_name, elt_name)) # Convert ungrouped from an unordered set to an ordered list. groups[''] = [elt_doc for (elt_name, elt_doc) in elts - if elt_doc in ungrouped] + if elt_name in ungrouped] return groups + def report_unused_groups(self): + """ + Issue a warning for any @group items that were not used by + L{_init_grouping()}. + """ + for (group, unused_idents) in self._unused_groups.items(): + for ident in unused_idents: + log.warning("@group %s: %s.%s not found" % + (group, self.canonical_name, ident)) + class ModuleDoc(NamespaceDoc): """ API documentation information about a single module. Modified: trunk/epydoc/src/epydoc/docbuilder.py =================================================================== --- trunk/epydoc/src/epydoc/docbuilder.py 2007-09-25 22:08:01 UTC (rev 1648) +++ trunk/epydoc/src/epydoc/docbuilder.py 2007-09-25 23:32:59 UTC (rev 1649) @@ -291,6 +291,7 @@ val_doc.init_variable_groups() if isinstance(val_doc, ModuleDoc): val_doc.init_submodule_groups() + val_doc.report_unused_groups() log.end_progress() return docindex This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2007-09-26 04:45:38
|
Revision: 1652 http://epydoc.svn.sourceforge.net/epydoc/?rev=1652&view=rev Author: edloper Date: 2007-09-25 21:45:34 -0700 (Tue, 25 Sep 2007) Log Message: ----------- - Fixed sf bug [ 1673017 ] Graphs are considered inline elements -- graphs are now 'raised' to an appropraite level after the dom tree is created. 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-09-26 04:00:55 UTC (rev 1651) +++ trunk/epydoc/src/epydoc/markup/epytext.py 2007-09-26 04:45:34 UTC (rev 1652) @@ -316,6 +316,14 @@ "epytext string.") errors.append(StructuringError(estr, token.startline)) + # Graphs use inline markup (G{...}) but are really block-level + # elements; so "raise" any graphs we generated. This is a bit of + # a hack, but the alternative is to define a new markup for + # block-level elements, which I'd rather not do. (See sourceforge + # bug #1673017.) + for child in doc.children: + _raise_graphs(child, doc) + # If there was an error, then signal it! if len([e for e in errors if e.is_fatal()]) > 0: if raise_on_error: @@ -326,6 +334,32 @@ # Return the top-level epytext DOM element. return doc +def _raise_graphs(tree, parent): + # Recurse to children. + have_graph_child = False + for elt in tree.children: + if isinstance(elt, Element): + _raise_graphs(elt, tree) + if elt.tag == 'graph': have_graph_child = True + + block = ('section', 'fieldlist', 'field', 'ulist', 'olist', 'li') + if have_graph_child and tree.tag not in block: + child_index = 0 + for elt in tree.children: + if isinstance(elt, Element) and elt.tag == 'graph': + # We found a graph: splice it into the parent. + parent_index = parent.children.index(tree) + left = tree.children[:child_index] + right = tree.children[child_index+1:] + parent.children[parent_index:parent_index+1] = [ + Element(tree.tag, *left, **tree.attribs), + elt, + Element(tree.tag, *right, **tree.attribs)] + child_index = 0 + parent_index += 2 + else: + child_index += 1 + def _pop_completed_blocks(token, stack, indent_stack): """ Pop any completed blocks off the stack. This includes any Modified: trunk/epydoc/src/epydoc/test/epytext.doctest =================================================================== --- trunk/epydoc/src/epydoc/test/epytext.doctest 2007-09-26 04:00:55 UTC (rev 1651) +++ trunk/epydoc/src/epydoc/test/epytext.doctest 2007-09-26 04:45:34 UTC (rev 1652) @@ -315,4 +315,37 @@ >>> print epytext2html("{{E{lb}E{lb}E{lb}}}") <p>{{{{{}}</p> +Graph Raising +============= +>>> epytext._x = True +>>> print testparse(""" +... Para containing G{classtree} graph. +... """) +<para>Para containing </para> +<graph>classtree</graph> +<para> graph.</para> + +>>> print testparse(""" +... Para B{I{containing C{G{classtree} graph}} inside nested markup}. +... """) +<para>Para <bold><italic>containing <code></code></italic></bold> +</para> +<graph>classtree</graph> +<para><bold><italic><code> graph</code></italic> + inside nested markup</bold> +.</para> + +Should we strip the 'inline' from the paras in cases like this:? +>>> print testparse(""" +... - List item with G{classtree foo} graph. +... - And with I{nested G{callgraph: zippy} markup} too. +... """) +<ulist><li><para inline=True>List item with </para> +<graph>classtreefoo</graph> +<para inline=True> graph.</para></li> +<li><para inline=True>And with <italic>nested </italic> +</para> +<graph>callgraphzippy</graph> +<para inline=True><italic> markup</italic> + too.</para></li></ulist> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2008-01-29 06:03:38
|
Revision: 1674 http://epydoc.svn.sourceforge.net/epydoc/?rev=1674&view=rev Author: edloper Date: 2008-01-28 22:03:36 -0800 (Mon, 28 Jan 2008) Log Message: ----------- - Applied sourceforge patch #1678242 -- added command-line option '-src-code-tab-width'. Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py trunk/epydoc/src/epydoc/docwriter/html.py trunk/epydoc/src/epydoc/docwriter/html_colorize.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2008-01-29 05:42:58 UTC (rev 1673) +++ trunk/epydoc/src/epydoc/cli.py 2008-01-29 06:03:36 UTC (rev 1674) @@ -136,8 +136,8 @@ list_classes_separately=False, graph_font=None, graph_font_size=None, include_source_code=True, pstat_files=[], simple_term=False, fail_on=None, exclude=[], exclude_parse=[], exclude_introspect=[], - external_api=[],external_api_file=[],external_api_root=[], - redundant_details=False) + external_api=[], external_api_file=[], external_api_root=[], + redundant_details=False, src_code_tab_width=8) def parse_arguments(): # Construct the option parser. @@ -338,6 +338,11 @@ "its own section, instead of listing them under their " "containing module.")) + output_group.add_option('--src-code-tab-width', + action='store', type='int', dest='src_code_tab_width', + help=("When generating HTML output, sets the number of spaces " + "each tab in source code listings is replaced with.")) + # The group of external API options. # Skip if the module couldn't be imported (usually missing docutils) if xlink is not None: @@ -573,6 +578,8 @@ options.show_frames = _str_to_bool(val, optname) elif optname in ('separate-classes', 'separate_classes'): options.list_classes_separately = _str_to_bool(val, optname) + elif optname in ('src-code-tab-width', 'src_code_tab_width'): + options.src_code_tab_width = _str_to_int(val, optname) # External API elif optname in ('external-api', 'external_api'): Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2008-01-29 05:42:58 UTC (rev 1673) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2008-01-29 06:03:36 UTC (rev 1674) @@ -291,6 +291,9 @@ @type include_log: C{boolean} @keyword include_log: If true, the the footer will include an href to the page 'epydoc-log.html'. + @type src_code_tab_width: C{int} + @keyword src_code_tab_width: Number of spaces to replace each tab + with in source code listings. """ self.docindex = docindex @@ -354,6 +357,10 @@ self._include_log = kwargs.get('include_log', False) """Are we generating an HTML log page?""" + + self._src_code_tab_width = kwargs.get('src_code_tab_width', 8) + """Number of spaces to replace each tab with in source code + listings.""" self._callgraph_cache = {} """Map the callgraph L{uid<DotGraph.uid>} to their HTML @@ -797,7 +804,8 @@ self.href(doc, label='%s %s' % (self.doc_kind(doc), name))) out('<pre class="py-src">\n') out(PythonSourceColorizer(filename, name, self.docindex, - self.url, name_to_docs).colorize()) + self.url, name_to_docs, + self._src_code_tab_width).colorize()) out('</pre>\n<br />\n') # Footer Modified: trunk/epydoc/src/epydoc/docwriter/html_colorize.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html_colorize.py 2008-01-29 05:42:58 UTC (rev 1673) +++ trunk/epydoc/src/epydoc/docwriter/html_colorize.py 2008-01-29 06:03:36 UTC (rev 1674) @@ -324,7 +324,8 @@ GUESS_LINK_TARGETS = False def __init__(self, module_filename, module_name, - docindex=None, url_func=None, name_to_docs=None): + docindex=None, url_func=None, name_to_docs=None, + tab_width=8): """ Create a new HTML colorizer for the specified module. @@ -406,6 +407,9 @@ #: Can be C{'func'}, C{'class'}, C{None}. self.def_type = None + #: The number of spaces to replace each tab in source code with + self.tab_width = tab_width + def find_line_offsets(self): """ @@ -450,7 +454,7 @@ # Load the module's text. self.text = open(self.module_filename).read() - self.text = self.text.expandtabs().rstrip()+'\n' + self.text = self.text.expandtabs(self.tab_width).rstrip()+'\n' # Construct the line_offsets table. self.find_line_offsets() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2008-01-29 17:17:05
|
Revision: 1677 http://epydoc.svn.sourceforge.net/epydoc/?rev=1677&view=rev Author: edloper Date: 2008-01-29 09:16:38 -0800 (Tue, 29 Jan 2008) Log Message: ----------- Supress docstring warnings for any objects that are not included in the documented set. This includes inherited values and variables, *unless* they are overridden, in which case the docstring may be inherited. Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py trunk/epydoc/src/epydoc/docbuilder.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2008-01-29 17:14:05 UTC (rev 1676) +++ trunk/epydoc/src/epydoc/cli.py 2008-01-29 17:16:38 UTC (rev 1677) @@ -667,6 +667,7 @@ 7, # Merging parsed & introspected information 1, # Linking imported variables 3, # Indexing documentation + 1, # Checking for overridden methods 30, # Parsing Docstrings 1, # Inheriting documentation 2] # Sorting & Grouping Modified: trunk/epydoc/src/epydoc/docbuilder.py =================================================================== --- trunk/epydoc/src/epydoc/docbuilder.py 2008-01-29 17:14:05 UTC (rev 1676) +++ trunk/epydoc/src/epydoc/docbuilder.py 2008-01-29 17:16:38 UTC (rev 1677) @@ -198,7 +198,8 @@ options = BuildOptions(parse=parse, introspect=introspect, exclude_introspect=exclude_introspect, exclude_parse=exclude_parse, add_submodules=add_submodules) - except Exception: + except Exception, e: + # log.error already reported by constructor. return None # Get the basic docs for each item. @@ -251,14 +252,27 @@ assign_canonical_names(val_doc, val_doc.canonical_name, docindex) log.end_progress() + # Set overrides pointers + log.start_progress('Checking for overridden methods') + for i, val_doc in enumerate(valdocs): + if isinstance(val_doc, ClassDoc): + percent = float(i)/len(valdocs) + log.progress(percent, val_doc.canonical_name) + find_overrides(val_doc) + log.end_progress() + # Parse the docstrings for each object. log.start_progress('Parsing docstrings') valdocs = sorted(docindex.reachable_valdocs( imports=False, submodules=False, packages=False, subclasses=False)) + supress_warnings = set(valdocs).difference( + docindex.reachable_valdocs( + imports=False, submodules=False, packages=False, subclasses=False, + bases=False, overrides=True)) for i, val_doc in enumerate(valdocs): _report_valdoc_progress(i, val_doc, valdocs) # the value's docstring - parse_docstring(val_doc, docindex) + parse_docstring(val_doc, docindex, supress_warnings) # the value's variables' docstrings if (isinstance(val_doc, NamespaceDoc) and val_doc.variables not in (None, UNKNOWN)): @@ -269,7 +283,7 @@ if (isinstance(var_doc.value, ValueDoc) and var_doc.value.defining_module is UNKNOWN): var_doc.value.defining_module = val_doc.defining_module - parse_docstring(var_doc, docindex) + parse_docstring(var_doc, docindex, supress_warnings) log.end_progress() # Take care of inheritance. @@ -1229,6 +1243,24 @@ ## Documentation Inheritance ###################################################################### +def find_overrides(class_doc): + """ + Set the C{overrides} attribute for all variables in C{class_doc}. + This needs to be done early (before docstring parsing), so we can + know which docstrings to supress warnings for. + """ + for base_class in list(class_doc.mro(warn_about_bad_bases=True)): + if base_class == class_doc: continue + if base_class.variables is UNKNOWN: continue + for name, var_doc in base_class.variables.items(): + if ( not (name.startswith('__') and not name.endswith('__')) and + base_class == var_doc.container and + name in class_doc.variables and + class_doc.variables[name].container==class_doc and + class_doc.variables[name].overrides is UNKNOWN ): + class_doc.variables[name].overrides = var_doc + + def inherit_docs(class_doc): for base_class in list(class_doc.mro(warn_about_bad_bases=True)): if base_class == class_doc: continue This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2008-01-29 17:21:31
|
Revision: 1678 http://epydoc.svn.sourceforge.net/epydoc/?rev=1678&view=rev Author: edloper Date: 2008-01-29 09:21:29 -0800 (Tue, 29 Jan 2008) Log Message: ----------- Fixed spelling error (supress -> suppress) Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py trunk/epydoc/src/epydoc/docbuilder.py trunk/epydoc/src/epydoc/docintrospecter.py trunk/epydoc/src/epydoc/docstringparser.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2008-01-29 17:16:38 UTC (rev 1677) +++ trunk/epydoc/src/epydoc/cli.py 2008-01-29 17:21:29 UTC (rev 1678) @@ -792,13 +792,13 @@ else: print >>sys.stderr, '\nUnsupported action %s!' % options.action - # If we supressed docstring warnings, then let the user know. - if logger is not None and logger.supressed_docstring_warning: - if logger.supressed_docstring_warning == 1: + # If we suppressed docstring warnings, then let the user know. + if logger is not None and logger.suppressed_docstring_warning: + if logger.suppressed_docstring_warning == 1: prefix = '1 markup error was found' else: prefix = ('%d markup errors were found' % - logger.supressed_docstring_warning) + logger.suppressed_docstring_warning) log.warning("%s while processing docstrings. Use the verbose " "switch (-v) to display markup errors." % prefix) @@ -1125,7 +1125,7 @@ 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 + self.suppressed_docstring_warning = 0 """This variable will be incremented once every time a docstring warning is reported tothe logger, but the verbosity level is too low for it to be displayed.""" @@ -1202,7 +1202,7 @@ message = self._format(' Debug: ', message, self.term.CYAN) else: if level >= log.DOCSTRING_WARNING: - self.supressed_docstring_warning += 1 + self.suppressed_docstring_warning += 1 return self._report(message) Modified: trunk/epydoc/src/epydoc/docbuilder.py =================================================================== --- trunk/epydoc/src/epydoc/docbuilder.py 2008-01-29 17:16:38 UTC (rev 1677) +++ trunk/epydoc/src/epydoc/docbuilder.py 2008-01-29 17:21:29 UTC (rev 1678) @@ -265,14 +265,14 @@ log.start_progress('Parsing docstrings') valdocs = sorted(docindex.reachable_valdocs( imports=False, submodules=False, packages=False, subclasses=False)) - supress_warnings = set(valdocs).difference( + suppress_warnings = set(valdocs).difference( docindex.reachable_valdocs( imports=False, submodules=False, packages=False, subclasses=False, bases=False, overrides=True)) for i, val_doc in enumerate(valdocs): _report_valdoc_progress(i, val_doc, valdocs) # the value's docstring - parse_docstring(val_doc, docindex, supress_warnings) + parse_docstring(val_doc, docindex, suppress_warnings) # the value's variables' docstrings if (isinstance(val_doc, NamespaceDoc) and val_doc.variables not in (None, UNKNOWN)): @@ -283,7 +283,7 @@ if (isinstance(var_doc.value, ValueDoc) and var_doc.value.defining_module is UNKNOWN): var_doc.value.defining_module = val_doc.defining_module - parse_docstring(var_doc, docindex, supress_warnings) + parse_docstring(var_doc, docindex, suppress_warnings) log.end_progress() # Take care of inheritance. @@ -422,7 +422,7 @@ try: _, parse_docs = _get_docs_from_pyname( str(introspect_doc.canonical_name), options, - progress_estimator, supress_warnings=True) + progress_estimator, suppress_warnings=True) finally: options.introspect = prev_introspect @@ -437,7 +437,7 @@ return (introspect_doc, parse_doc) def _get_docs_from_pyname(name, options, progress_estimator, - supress_warnings=False): + suppress_warnings=False): progress_estimator.complete += 1 if options.must_introspect(name) or options.must_parse(name): log.progress(progress_estimator.progress(), name) @@ -460,7 +460,7 @@ pass # Report any errors we encountered. - if not supress_warnings: + if not suppress_warnings: _report_errors(name, introspect_doc, parse_doc, introspect_error, parse_error) @@ -1247,7 +1247,7 @@ """ Set the C{overrides} attribute for all variables in C{class_doc}. This needs to be done early (before docstring parsing), so we can - know which docstrings to supress warnings for. + know which docstrings to suppress warnings for. """ for base_class in list(class_doc.mro(warn_about_bad_bases=True)): if base_class == class_doc: continue Modified: trunk/epydoc/src/epydoc/docintrospecter.py =================================================================== --- trunk/epydoc/src/epydoc/docintrospecter.py 2008-01-29 17:16:38 UTC (rev 1677) +++ trunk/epydoc/src/epydoc/docintrospecter.py 2008-01-29 17:21:29 UTC (rev 1678) @@ -893,7 +893,7 @@ """ Run the given callable in a 'sandboxed' environment. Currently, this includes saving and restoring the contents of - sys and __builtins__; and supressing stdin, stdout, and stderr. + sys and __builtins__; and suppressing stdin, stdout, and stderr. """ # Note that we just do a shallow copy of sys. In particular, # any changes made to sys.modules will be kept. But we do @@ -908,7 +908,7 @@ # in get_value_from_filename might get overwritten sys.path.append('') - # Supress input and output. (These get restored when we restore + # Suppress input and output. (These get restored when we restore # sys to old_sys). sys.stdin = sys.stdout = sys.stderr = _dev_null sys.__stdin__ = sys.__stdout__ = sys.__stderr__ = _dev_null Modified: trunk/epydoc/src/epydoc/docstringparser.py =================================================================== --- trunk/epydoc/src/epydoc/docstringparser.py 2008-01-29 17:16:38 UTC (rev 1677) +++ trunk/epydoc/src/epydoc/docstringparser.py 2008-01-29 17:21:29 UTC (rev 1678) @@ -167,7 +167,7 @@ # asked to process one twice? e.g., for @include we might have to # parse the included docstring earlier than we might otherwise..?? -def parse_docstring(api_doc, docindex, supress_warnings=[]): +def parse_docstring(api_doc, docindex, suppress_warnings=[]): """ Process the given C{APIDoc}'s docstring. In particular, populate the C{APIDoc}'s C{descr} and C{summary} attributes, and add any @@ -176,8 +176,8 @@ @param docindex: A DocIndex, used to find the containing module (to look up the docformat); and to find any user docfields defined by containing objects. - @param supress_warnings: A set of objects for which docstring - warnings should be supressed. + @param suppress_warnings: A set of objects for which docstring + warnings should be suppressed. """ if api_doc.metadata is not UNKNOWN: if not (isinstance(api_doc, RoutineDoc) @@ -231,7 +231,7 @@ initvar = api_doc.variables.get('__init__') if initvar and isinstance(initvar.value, RoutineDoc): init_api_doc = initvar.value - parse_docstring(init_api_doc, docindex, supress_warnings) + parse_docstring(init_api_doc, docindex, suppress_warnings) parse_function_signature(init_api_doc, api_doc, docformat, parse_errors) @@ -276,9 +276,9 @@ # vars/params? # Report any errors that occured - if api_doc in supress_warnings: + if api_doc in suppress_warnings: if parse_errors or field_warnings: - log.info("Supressing docstring warnings for %s, since it " + log.info("Suppressing docstring warnings for %s, since it " "is not included in the documented set." % api_doc.canonical_name) else: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2008-02-01 19:15:36
|
Revision: 1704 http://epydoc.svn.sourceforge.net/epydoc/?rev=1704&view=rev Author: edloper Date: 2008-02-01 11:15:34 -0800 (Fri, 01 Feb 2008) Log Message: ----------- - Deregister loggers before cli.main() exits. - Rearranged logger handling code in cli, to better handle the case where multiple loggers are used. Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py trunk/epydoc/src/epydoc/log.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2008-01-31 06:52:33 UTC (rev 1703) +++ trunk/epydoc/src/epydoc/cli.py 2008-02-01 19:15:34 UTC (rev 1704) @@ -660,13 +660,15 @@ # options.parse = False # Set up the logger + loggers = [] if options.simple_term: TerminalController.FORCE_SIMPLE_TERM = True if options.action == 'text': - logger = None # no logger for text output. + pass # no logger for text output. elif options.verbosity > 1: logger = ConsoleLogger(options.verbosity) log.register_logger(logger) + loggers.append(logger) else: # Each number is a rough approximation of how long we spend on # that task, used to divide up the unified progress bar. @@ -695,6 +697,7 @@ del stages[1:3] # no merging or linking logger = UnifiedProgressConsoleLogger(options.verbosity, stages) log.register_logger(logger) + loggers.append(logger) # check the output directory. if options.action not in ('text', 'check', 'pickle'): @@ -707,7 +710,9 @@ if options.action == 'html': if not os.path.exists(options.target): os.mkdir(options.target) - log.register_logger(HTMLLogger(options.target, options)) + logger = HTMLLogger(options.target, options) + log.register_logger(logger) + loggers.append(logger) else: log.warning("--include-log requires --html") @@ -764,9 +769,11 @@ exclude_parse=exclude_parse) if docindex is None: - if log.ERROR in logger.reported_message_levels: - sys.exit(1) + for logger in loggers: + if log.ERROR in logger.reported_message_levels: + sys.exit(1) else: + for logger in loggers: log.remove_logger(logger) return # docbuilder already logged an error. # Load profile information, if it was given. @@ -778,7 +785,9 @@ profile_stats = pstats.Stats(options.pstat_files[0]) for filename in options.pstat_files[1:]: profile_stats.add(filename) - except KeyboardInterrupt: raise + except KeyboardInterrupt: + for logger in loggers: log.remove_logger(logger) + raise except Exception, e: log.error("Error reading pstat file: %s" % e) profile_stats = None @@ -800,18 +809,22 @@ print >>sys.stderr, '\nUnsupported action %s!' % options.action # If we suppressed docstring warnings, then let the user know. - if logger is not None and logger.suppressed_docstring_warning: - if logger.suppressed_docstring_warning == 1: - prefix = '1 markup error was found' - else: - prefix = ('%d markup errors were found' % - logger.suppressed_docstring_warning) - log.warning("%s while processing docstrings. Use the verbose " - "switch (-v) to display markup errors." % prefix) + for logger in loggers: + if (isinstance(logger, ConsoleLogger) and + logger.suppressed_docstring_warning): + if logger.suppressed_docstring_warning == 1: + prefix = '1 markup error was found' + else: + prefix = ('%d markup errors were found' % + logger.suppressed_docstring_warning) + logger.warning("%s while processing docstrings. Use the verbose " + "switch (-v) to display markup errors." % prefix) # Basic timing breakdown: - if options.verbosity >= 2 and logger is not None: - logger.print_times() + if options.verbosity >= 2: + for logger in logger: + if isinstance(logger, ConsoleLogger): + logger.print_times() # If we encountered any message types that we were requested to # fail on, then exit with status 2. @@ -820,6 +833,9 @@ if max_reported_message_level >= options.fail_on: sys.exit(2) + # Deregister our logger(s). + for logger in loggers: log.remove_logger(logger) + def write_html(docindex, options): from epydoc.docwriter.html import HTMLWriter html_writer = HTMLWriter(docindex, **options.__dict__) @@ -1309,7 +1325,7 @@ def start_progress(self, header=None): if self._progress is not None: - raise ValueError + raise ValueError('previous progress bar not ended') self._progress = None self._progress_start_time = time.time() self._progress_header = header @@ -1317,6 +1333,8 @@ print self.term.BOLD + header + self.term.NORMAL def end_progress(self): + if self._progress is None: + return # already ended. self.progress(1.) if self._progress_mode == 'bar': sys.stdout.write(self.term.CLEAR_LINE) @@ -1365,6 +1383,8 @@ if self.stage == 0: ConsoleLogger.start_progress(self) self.stage += 1 + if self.stage > len(self.stages): + self.stage = len(self.stages) # should never happen! def end_progress(self): if self.stage == len(self.stages): @@ -1448,6 +1468,7 @@ return self.MESSAGE % (level.split()[-1], hdr, message) def close(self): + if self.out is None: return if self.is_empty: self.out.write('<div class="log-info">' 'No warnings or errors!</div>') @@ -1457,6 +1478,7 @@ (time.ctime(), self._elapsed_time())) self.out.write(self.FOOTER) self.out.close() + self.out = None def _elapsed_time(self): secs = int(time.time()-self.start_time) Modified: trunk/epydoc/src/epydoc/log.py =================================================================== --- trunk/epydoc/src/epydoc/log.py 2008-01-31 06:52:33 UTC (rev 1703) +++ trunk/epydoc/src/epydoc/log.py 2008-02-01 19:15:34 UTC (rev 1704) @@ -66,7 +66,8 @@ def close(self): """ - Perform any tasks needed to close this logger. + Perform any tasks needed to close this logger. This should + be safe to call multiple times. """ #//////////////////////////////////////////////////////////// @@ -141,7 +142,8 @@ """ _loggers.append(logger) -def remove_logger(logger): +def remove_logger(logger, close_logger=True): + if close_logger: logger.close() _loggers.remove(logger) ###################################################################### This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2008-02-02 06:32:01
|
Revision: 1714 http://epydoc.svn.sourceforge.net/epydoc/?rev=1714&view=rev Author: edloper Date: 2008-02-01 22:31:52 -0800 (Fri, 01 Feb 2008) Log Message: ----------- - Moved TerminalController to epydoc.util - Added TerminalController.render Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py trunk/epydoc/src/epydoc/util.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2008-02-02 06:28:09 UTC (rev 1713) +++ trunk/epydoc/src/epydoc/cli.py 2008-02-02 06:31:52 UTC (rev 1714) @@ -70,7 +70,7 @@ import epydoc from epydoc import log from epydoc.util import wordwrap, run_subprocess, RunSubprocessError -from epydoc.util import plaintext_to_html +from epydoc.util import plaintext_to_html, TerminalController from epydoc.apidoc import UNKNOWN from epydoc.compat import * import ConfigParser @@ -1118,82 +1118,6 @@ ###################################################################### # [xx] this should maybe move to util.py or log.py -class TerminalController: - """ - A class that can be used to portably generate formatted output to - a terminal. See - U{http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116} - for documentation. (This is a somewhat stripped-down version.) - """ - BOL = '' #: Move the cursor to the beginning of the line - UP = '' #: Move the cursor up one line - DOWN = '' #: Move the cursor down one line - LEFT = '' #: Move the cursor left one char - RIGHT = '' #: Move the cursor right one char - CLEAR_EOL = '' #: Clear to the end of the line. - CLEAR_LINE = '' #: Clear the current line; cursor to BOL. - BOLD = '' #: Turn on bold mode - NORMAL = '' #: Turn off all modes - COLS = 75 #: Width of the terminal (default to 75) - BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = '' - - _STRING_CAPABILITIES = """ - BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1 - CLEAR_EOL=el BOLD=bold UNDERLINE=smul NORMAL=sgr0""".split() - _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 - except: - # If it's not available, then try faking enough to get a - # simple progress bar. - self.BOL = '\r' - self.CLEAR_LINE = '\r' + ' '*self.COLS + '\r' - - # Check the terminal type. If we fail, then assume that the - # terminal has no capabilities. - try: curses.setupterm() - except: return - - # Look up numeric capabilities. - self.COLS = curses.tigetnum('cols') - - # Look up string capabilities. - for capability in self._STRING_CAPABILITIES: - (attrib, cap_name) = capability.split('=') - setattr(self, attrib, self._tigetstr(cap_name) or '') - if self.BOL and self.CLEAR_EOL: - self.CLEAR_LINE = self.BOL+self.CLEAR_EOL - - # Colors - set_fg = self._tigetstr('setf') - if set_fg: - for i,color in zip(range(len(self._COLORS)), self._COLORS): - setattr(self, color, curses.tparm(set_fg, i) or '') - set_fg_ansi = self._tigetstr('setaf') - if set_fg_ansi: - for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): - setattr(self, color, curses.tparm(set_fg_ansi, i) or '') - - def _tigetstr(self, cap_name): - # String capabilities can include "delays" of the form "$<2>". - # For any modern terminal, we should be able to just ignore - # these, so strip them out. - import curses - cap = curses.tigetstr(cap_name) or '' - return re.sub(r'\$<\d+>[/*]?', '', cap) - class ConsoleLogger(log.Logger): def __init__(self, verbosity, progress_mode=None): self._verbosity = verbosity Modified: trunk/epydoc/src/epydoc/util.py =================================================================== --- trunk/epydoc/src/epydoc/util.py 2008-02-02 06:28:09 UTC (rev 1713) +++ trunk/epydoc/src/epydoc/util.py 2008-02-02 06:31:52 UTC (rev 1714) @@ -16,7 +16,7 @@ """ __docformat__ = 'epytext en' -import os, os.path, re +import os, os.path, re, sys ###################################################################### ## Python Source Types @@ -287,3 +287,97 @@ return out, err else: raise RunSubprocessError(cmd, out, err) + +###################################################################### +## Terminal Control +###################################################################### + +class TerminalController: + """ + A class that can be used to portably generate formatted output to + a terminal. See + U{http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116} + for documentation. (This is a somewhat stripped-down version.) + """ + BOL = '' #: Move the cursor to the beginning of the line + UP = '' #: Move the cursor up one line + DOWN = '' #: Move the cursor down one line + LEFT = '' #: Move the cursor left one char + RIGHT = '' #: Move the cursor right one char + CLEAR_EOL = '' #: Clear to the end of the line. + CLEAR_LINE = '' #: Clear the current line; cursor to BOL. + BOLD = '' #: Turn on bold mode + NORMAL = '' #: Turn off all modes + COLS = 75 #: Width of the terminal (default to 75) + BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = '' + + _STRING_CAPABILITIES = """ + BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1 + CLEAR_EOL=el BOLD=bold UNDERLINE=smul NORMAL=sgr0""".split() + _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 + except: + # If it's not available, then try faking enough to get a + # simple progress bar. + self.BOL = '\r' + self.CLEAR_LINE = '\r' + ' '*self.COLS + '\r' + + # Check the terminal type. If we fail, then assume that the + # terminal has no capabilities. + try: curses.setupterm() + except: return + + # Look up numeric capabilities. + self.COLS = curses.tigetnum('cols') + + # Look up string capabilities. + for capability in self._STRING_CAPABILITIES: + (attrib, cap_name) = capability.split('=') + setattr(self, attrib, self._tigetstr(cap_name) or '') + if self.BOL and self.CLEAR_EOL: + self.CLEAR_LINE = self.BOL+self.CLEAR_EOL + + # Colors + set_fg = self._tigetstr('setf') + if set_fg: + for i,color in zip(range(len(self._COLORS)), self._COLORS): + setattr(self, color, curses.tparm(set_fg, i) or '') + set_fg_ansi = self._tigetstr('setaf') + if set_fg_ansi: + for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): + setattr(self, color, curses.tparm(set_fg_ansi, i) or '') + + def _tigetstr(self, cap_name): + # String capabilities can include "delays" of the form "$<2>". + # For any modern terminal, we should be able to just ignore + # these, so strip them out. + import curses + cap = curses.tigetstr(cap_name) or '' + return re.sub(r'\$<\d+>[/*]?', '', cap) + + def render(self, template): + """ + Replace each $-substitutions in the given template string with + the corresponding terminal control string (if it's defined) or + '' (if it's not). + """ + return re.sub(r'\$\$|\${\w+}', self._render_sub, template) + + def _render_sub(self, match): + s = match.group() + if s == '$$': return s + else: return getattr(self, s[2:-1]) + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2008-02-15 01:11:20
|
Revision: 1722 http://epydoc.svn.sourceforge.net/epydoc/?rev=1722&view=rev Author: edloper Date: 2008-02-14 17:11:18 -0800 (Thu, 14 Feb 2008) Log Message: ----------- - Added 'metaclass' var to ClassDoc, to record the metaclass (when defined) Modified Paths: -------------- trunk/epydoc/src/epydoc/apidoc.py trunk/epydoc/src/epydoc/docintrospecter.py trunk/epydoc/src/epydoc/docparser.py Modified: trunk/epydoc/src/epydoc/apidoc.py =================================================================== --- trunk/epydoc/src/epydoc/apidoc.py 2008-02-15 01:02:30 UTC (rev 1721) +++ trunk/epydoc/src/epydoc/apidoc.py 2008-02-15 01:11:18 UTC (rev 1722) @@ -1257,6 +1257,9 @@ """@ivar: API documentation for the class's known subclasses. @type: C{list} of L{ClassDoc}""" #} + #{ Information about Metaclasses + metaclass = UNKNOWN + #} def apidoc_links(self, **filters): val_docs = NamespaceDoc.apidoc_links(self, **filters) Modified: trunk/epydoc/src/epydoc/docintrospecter.py =================================================================== --- trunk/epydoc/src/epydoc/docintrospecter.py 2008-02-15 01:02:30 UTC (rev 1721) +++ trunk/epydoc/src/epydoc/docintrospecter.py 2008-02-15 01:11:18 UTC (rev 1722) @@ -321,7 +321,7 @@ #: class's API documentation. UNDOCUMENTED_CLASS_VARS = ( '__doc__', '__module__', '__dict__', '__weakref__', '__slots__', - '__pyx_vtable__') + '__pyx_vtable__', '__metaclass__') def introspect_class(cls, class_doc, module_name=None): """ @@ -341,6 +341,9 @@ except KeyboardInterrupt: raise except: pass + # Record the class's metaclass + class_doc.metaclass = introspect_docs(type(cls)) + # Start a list of subclasses. class_doc.subclasses = [] Modified: trunk/epydoc/src/epydoc/docparser.py =================================================================== --- trunk/epydoc/src/epydoc/docparser.py 2008-02-15 01:02:30 UTC (rev 1721) +++ trunk/epydoc/src/epydoc/docparser.py 2008-02-15 01:11:18 UTC (rev 1722) @@ -1128,6 +1128,12 @@ if lhs_name[-1] == '__slots__': continue + # Handle metaclass assignment + if (lhs_name[-1] == '__metaclass__' and + isinstance(parent_docs[-1], ClassDoc)): + parent_docs[-1].metaclass = rhs_val + continue + # Create the VariableDoc. var_doc = VariableDoc(name=lhs_name[-1], value=rhs_val, is_imported=False, is_alias=is_alias, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2008-02-20 21:14:16
|
Revision: 1732 http://epydoc.svn.sourceforge.net/epydoc/?rev=1732&view=rev Author: edloper Date: 2008-02-20 13:14:12 -0800 (Wed, 20 Feb 2008) Log Message: ----------- - Added "--inheritance hidden" to not list inherited vars at all. Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py trunk/epydoc/src/epydoc/docwriter/html.py trunk/epydoc/src/epydoc/docwriter/latex.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2008-02-20 00:49:48 UTC (rev 1731) +++ trunk/epydoc/src/epydoc/cli.py 2008-02-20 21:14:12 UTC (rev 1732) @@ -82,7 +82,7 @@ except: xlink = None -INHERITANCE_STYLES = ('grouped', 'listed', 'included') +INHERITANCE_STYLES = ('grouped', 'listed', 'included', 'hidden') GRAPH_TYPES = ('classtree', 'callgraph', 'umlclasstree') ACTIONS = ('html', 'text', 'latex', 'dvi', 'ps', 'pdf', 'check') DEFAULT_DOCFORMAT = 'epytext' Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2008-02-20 00:49:48 UTC (rev 1731) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2008-02-20 21:14:12 UTC (rev 1732) @@ -383,7 +383,8 @@ self._public_filter = True # Make sure inheritance has a sane value. - if self._inheritance not in ('listed', 'included', 'grouped'): + if self._inheritance not in ('listed', 'included', + 'grouped', 'hidden'): raise ValueError, 'Bad value for inheritance' # Create the project homepage link, if it was not specified. @@ -2056,6 +2057,8 @@ listed_inh_vars.setdefault(base,[]).append(var_doc) elif self._inheritance == 'grouped': grouped_inh_vars.setdefault(base,[]).append(var_doc) + elif self._inheritance == 'hidden': + pass else: normal_vars.append(var_doc) else: Modified: trunk/epydoc/src/epydoc/docwriter/latex.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/latex.py 2008-02-20 00:49:48 UTC (rev 1731) +++ trunk/epydoc/src/epydoc/docwriter/latex.py 2008-02-20 21:14:12 UTC (rev 1732) @@ -669,6 +669,8 @@ listed_inh_vars.setdefault(base,[]).append(var_doc) elif self._inheritance == 'grouped': grouped_inh_vars.setdefault(base,[]).append(var_doc) + elif self._inheritance == 'hidden': + pass else: normal_vars.append(var_doc) else: @@ -938,6 +940,8 @@ listed_inh_vars.setdefault(base,[]).append(var_doc) elif self._inheritance == 'grouped': grouped_inh_vars.setdefault(base,[]).append(var_doc) + elif self._inheritance == 'hidden': + pass else: normal_vars.append(var_doc) else: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ed...@us...> - 2008-02-23 00:55:53
|
Revision: 1734 http://epydoc.svn.sourceforge.net/epydoc/?rev=1734&view=rev Author: edloper Date: 2008-02-22 16:55:52 -0800 (Fri, 22 Feb 2008) Log Message: ----------- - Incorporated (and extended) patches from Jonathan Guyer, to move formatting decisions for the latex writer into a separate stylesheet. The new version is not compatible with Jonathan Guyer's original patch -- I redesigned the interface between epydoc.docwriter.latex and the stylesheet somewhat. At present, three style files are available: 'base', 'boxes', and 'shaded'. 'boxes' resembles the old (3.0) output. Modified Paths: -------------- trunk/epydoc/src/epydoc/cli.py trunk/epydoc/src/epydoc/docwriter/latex.py Added Paths: ----------- trunk/epydoc/src/epydoc/docwriter/latex_sty.py Modified: trunk/epydoc/src/epydoc/cli.py =================================================================== --- trunk/epydoc/src/epydoc/cli.py 2008-02-23 00:52:21 UTC (rev 1733) +++ trunk/epydoc/src/epydoc/cli.py 2008-02-23 00:55:52 UTC (rev 1734) @@ -325,6 +325,11 @@ help="The CSS stylesheet. STYLESHEET can be either a " "builtin stylesheet or the name of a CSS file.") + output_group.add_option("--sty", + dest="sty", metavar="LATEXSTYLE", + help="The LaTeX style file. LATEXSTYLE can be either a " + "builtin style file or the name of a .sty file.") + output_group.add_option("--url", "-u", dest="prj_url", metavar="URL", help="The documented project's URL (for the navigation bar).") @@ -698,13 +703,13 @@ if options.load_pickle: stages = [30] # Loading pickled documentation if 'html' in options.actions: stages += [100] - if 'text' in options.actions: stages += [30] if 'check' in options.actions: stages += [10] if 'pickle' in options.actions: stages += [10] if 'latex' in options.actions: stages += [60] if 'pdf' in options.actions: stages += [50] - elif 'ps' in options.actions: stages += [40] - elif 'dvi' in options.actions: stages += [30] + elif 'ps' in options.actions: stages += [40] # implied by pdf + elif 'dvi' in options.actions: stages += [30] # implied by ps + if 'text' in options.actions: stages += [30] if options.parse and not options.introspect: del stages[1] # no merging @@ -828,13 +833,15 @@ if profile_stats is not None: docindex.read_profiling_info(profile_stats) - # Perform the specified action. + # Perform the specified action. NOTE: It is important that these + # are performed in the same order that the 'stages' list was + # constructed, at the top of this function. + if 'html' in options.actions: + write_html(docindex, options) if 'check' in options.actions: check_docs(docindex, options) if 'pickle' in options.actions: write_pickle(docindex, options) - if 'html' in options.actions: - write_html(docindex, options) if ('latex' in options.actions or 'dvi' in options.actions or 'ps' in options.actions or 'pdf' in options.actions): write_latex(docindex, options) Modified: trunk/epydoc/src/epydoc/docwriter/latex.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/latex.py 2008-02-23 00:52:21 UTC (rev 1733) +++ trunk/epydoc/src/epydoc/docwriter/latex.py 2008-02-23 00:55:52 UTC (rev 1734) @@ -23,100 +23,16 @@ from epydoc import markup from epydoc.util import plaintext_to_latex import epydoc.markup +from epydoc.docwriter.dotgraph import * +from epydoc.docwriter.latex_sty import STYLESHEETS class LatexWriter: + #: Expects (options,) PREAMBLE = [ "\\documentclass{article}", - "\\usepackage{alltt, parskip, fancyhdr, boxedminipage}", - "\\usepackage{makeidx, multirow, longtable, tocbibind, amssymb}", - "\\usepackage{fullpage}", - "\\usepackage[usenames]{color}", - # Fix the heading position -- without this, the headings generated - # by the fancyheadings package sometimes overlap the text. - "\\setlength{\\headheight}{16pt}", - "\\setlength{\\headsep}{24pt}", - "\\setlength{\\topmargin}{-\\headsep}", - # By default, do not indent paragraphs. - "\\setlength{\\parindent}{0ex}", - "\\setlength{\\parskip}{2ex}", - # Double the standard size boxedminipage outlines. - "\\setlength{\\fboxrule}{2\\fboxrule}", - # Create a 'base class' length named BCL for use in base trees. - "\\newlength{\\BCL} % base class length, for base trees.", - # Display the section & subsection names in a header. - "\\pagestyle{fancy}", - "\\renewcommand{\\sectionmark}[1]{\\markboth{#1}{}}", - "\\renewcommand{\\subsectionmark}[1]{\\markright{#1}}", - # Colorization for python source code - "\\definecolor{py@keywordcolour}{rgb}{1,0.45882,0}", - "\\definecolor{py@stringcolour}{rgb}{0,0.666666,0}", - "\\definecolor{py@commentcolour}{rgb}{1,0,0}", - "\\definecolor{py@ps1colour}{rgb}{0.60784,0,0}", - "\\definecolor{py@ps2colour}{rgb}{0.60784,0,1}", - "\\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}", - "\\definecolor{py@inputcolour}{rgb}{0,0,0}", - "% Prompt", - "\\newcommand{\\pysrcprompt}[1]{\\textcolor{py@ps1colour}" - "{\\small\\textbf{#1}}}", - "\\newcommand{\\pysrcmore}[1]{\\textcolor{py@ps2colour}" - "{\\small\\textbf{#1}}}", - "% Source code", - "\\newcommand{\\pysrckeyword}[1]{\\textcolor{py@keywordcolour}" - "{\\small\\textbf{#1}}}", - "\\newcommand{\\pysrcbuiltin}[1]{\\textcolor{py@builtincolour}" - "{\\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}" - "{\\small\\textbf{#1}}}", - "% Output", - "\\newcommand{\\pysrcoutput}[1]{\\textcolor{py@outputcolour}" - "{\\small\\textbf{#1}}}", - "% Exceptions", - "\\newcommand{\\pysrcexcept}[1]{\\textcolor{py@exceptcolour}" - "{\\small\\textbf{#1}}}", - # Size of the function description boxes. - "\\newlength{\\funcindent}", - "\\newlength{\\funcwidth}", - "\\setlength{\\funcindent}{1cm}", - "\\setlength{\\funcwidth}{\\textwidth}", - "\\addtolength{\\funcwidth}{-2\\funcindent}", - # Size of the var description tables. - "\\newlength{\\varindent}", - "\\newlength{\\varnamewidth}", - "\\newlength{\\vardescrwidth}", - "\\newlength{\\varwidth}", - "\\setlength{\\varindent}{1cm}", - "\\setlength{\\varnamewidth}{.3\\textwidth}", - "\\setlength{\\varwidth}{\\textwidth}", - "\\addtolength{\\varwidth}{-4\\tabcolsep}", - "\\addtolength{\\varwidth}{-3\\arrayrulewidth}", - "\\addtolength{\\varwidth}{-2\\varindent}", - "\\setlength{\\vardescrwidth}{\\varwidth}", - "\\addtolength{\\vardescrwidth}{-\\varnamewidth}", - # Define new environment for displaying parameter lists. - textwrap.dedent("""\ - \\newenvironment{Ventry}[1]% - {\\begin{list}{}{% - \\renewcommand{\\makelabel}[1]{\\texttt{##1:}\\hfil}% - \\settowidth{\\labelwidth}{\\texttt{#1:}}% - \\setlength{\\leftmargin}{\\labelsep}% - \\addtolength{\\leftmargin}{\\labelwidth}}}% - {\\end{list}}"""), + "\\usepackage[%s]{epydoc}", ] - HRULE = '\\rule{\\textwidth}{0.5\\fboxrule}\n\n' - SECTIONS = ['\\part{%s}', '\\chapter{%s}', '\\section{%s}', '\\subsection{%s}', '\\subsubsection{%s}', '\\textbf{%s}'] @@ -130,14 +46,23 @@ # Process keyword arguments self._show_private = kwargs.get('show_private', 0) self._prj_name = kwargs.get('prj_name', None) or 'API Documentation' - self._crossref = kwargs.get('crossref', 1) + self._show_crossrefs = kwargs.get('crossref', 1) self._index = kwargs.get('index', 1) + self._hyperlink = kwargs.get('hyperlink', True) self._list_classes_separately=kwargs.get('list_classes_separately',0) self._inheritance = kwargs.get('inheritance', 'listed') self._exclude = kwargs.get('exclude', 1) + self._list_submodules = kwargs.get('list_submodules', 1) + self._sty = kwargs.get('sty') self._top_section = 2 self._index_functions = 1 self._hyperref = 1 + + # [xx] check into this: + self._pdflatex = kwargs.get('action', '') == "pdflatex" + + self._graph_types = kwargs.get('graphs', ()) or () + """Graphs that we should include in our output.""" #: The Python representation of the encoding. #: Update L{latex_encodings} in case of mismatch between it and @@ -156,6 +81,10 @@ """The list of L{ClassDoc}s for the documented classes.""" self.class_set = set(self.class_list) """The set of L{ClassDoc}s for the documented classes.""" + self.module_list = [d for d in valdocs if isinstance(d, ModuleDoc)] + """The list of L{ModuleDoc}s for the documented modules.""" + self.module_set = set(self.module_list) + """The set of L{ModuleDoc}s for the documented modules.""" def write(self, directory=None): """ @@ -186,6 +115,9 @@ if not directory: directory = os.curdir self._mkdir(directory) self._directory = directory + + # Write the style file. + self._write_sty(directory, self._sty) # Write the top-level file. self._write(self.write_topfile, directory, 'api.tex') @@ -203,6 +135,35 @@ # Restore defaults that we changed. (ValueDoc.SUMMARY_REPR_LINELEN, ValueDoc.REPR_LINELEN, ValueDoc.REPR_MAXLINES) = orig_valdoc_defaults + + def _write_sty(self, directory, stylesheet, filename='epydoc.sty'): + """ + Copy the requested LaTeX stylesheet to the target directory. + The stylesheet can be specified as a name (i.e., a key from + the STYLESHEETS directory); a filename; or None for the default + stylesheet. If any stylesheet *other* than the default + stylesheet is selected, then the default stylesheet will be + copied to 'epydoc-default.sty', which makes it possible to + reference it via \RequirePackage. + """ + if stylesheet is None: + sty = STYLESHEETS['base'] + elif os.path.exists(stylesheet): + try: sty = open(stylesheet, 'rb').read() + except: raise IOError("Can't open LaTeX style file: %r" % + stylesheet) + self._write_sty(directory, None, 'epydoc-default.sty') + elif stylesheet in STYLESHEETS: + sty = STYLESHEETS[stylesheet] + if sty != STYLESHEETS['base']: + self._write_sty(directory, None, 'epydoc-default.sty') + else: + raise IOError("Can't find LaTeX style file: %r" % stylesheet) + + # Write the stylesheet. + out = open(os.path.join(directory, filename), 'wb') + out.write(sty) + out.close() def _write(self, write_func, directory, filename, *args): # Display our progress. @@ -273,9 +234,9 @@ # Add a table of contents. self.write_start_of(out, 'Table of Contents') - out('\\addtolength{\\parskip}{-2ex}\n') + out('\\addtolength{\\parskip}{-1ex}\n') out('\\tableofcontents\n') - out('\\addtolength{\\parskip}{2ex}\n') + out('\\addtolength{\\parskip}{1ex}\n') # Include documentation files. self.write_start_of(out, 'Includes') @@ -300,27 +261,35 @@ out('\\end{document}\n\n') def write_preamble(self, out): - out('\n'.join(self.PREAMBLE)) - out('\n') + # If we're generating an index, add it to the preamble. + options = [] + if self._index: options.append('index') + if self._hyperlink: options.append('hyperlink') + out('\n'.join(self.PREAMBLE) % (','.join(options),) + '\n') # Set the encoding. out('\\usepackage[%s]{inputenc}\n' % self.get_latex_encoding()) # If we're generating hyperrefs, add the appropriate packages. + # !!!!!!!!!!!!!!!!!!!!!! + # !!! JEG - this needs to be the last thing in the preamble + # !!!!!!!!!!!!!!!!!!!!!! if self._hyperref: out('\\definecolor{UrlColor}{rgb}{0,0.08,0.45}\n') - out('\\usepackage[dvips, pagebackref, pdftitle={%s}, ' + + if self._pdflatex: + driver = 'pdftex' + else: + driver = 'dvips' + + out('\\usepackage[%s, pagebackref, pdftitle={%s}, ' 'pdfcreator={epydoc %s}, bookmarks=true, ' 'bookmarksopen=false, pdfpagemode=UseOutlines, ' 'colorlinks=true, linkcolor=black, anchorcolor=black, ' 'citecolor=black, filecolor=black, menucolor=black, ' 'pagecolor=black, urlcolor=UrlColor]{hyperref}\n' % - (self._prj_name or '', epydoc.__version__)) + (driver, self._prj_name or '', epydoc.__version__)) - # If we're generating an index, add it to the preamble. - if self._index: - out("\\makeindex\n") - # If restructuredtext was used, then we need to extend # the prefix to include LatexTranslator.head_prefix. if 'restructuredtext' in epydoc.markup.MARKUP_LANGUAGES_USED: @@ -352,27 +321,28 @@ # Add a section marker. out(self.section('%s %s' % (self.doc_kind(doc), - doc.canonical_name))) + _dotted(doc.canonical_name)), + ref=doc)) - # Label our current location. - out(' \\label{%s}\n' % self.label(doc)) - # Add the module's description. if doc.descr not in (None, UNKNOWN): - out(self.docstring_to_latex(doc.descr)) + out(' '*4 + '\\begin{EpydocModuleDescription}%\n') + out(self.docstring_to_latex(doc.descr, 4)) + out(' '*4 + '\\end{EpydocModuleDescription}\n') # Add version, author, warnings, requirements, notes, etc. self.write_standard_fields(out, doc) # If it's a package, list the sub-modules. - if doc.submodules != UNKNOWN and doc.submodules: + if self._list_submodules and doc.submodules != UNKNOWN and doc.submodules: self.write_module_list(out, doc) # Contents. if self._list_classes_separately: self.write_class_list(out, doc) - self.write_func_list(out, 'Functions', doc, 'function') - self.write_var_list(out, 'Variables', doc, 'other') + self.write_list(out, 'Functions', doc, 'EpydocFunctionList', + 'function') + self.write_list(out, 'Variables', doc, 'EpydocVariableList', 'other') # Class list. if not self._list_classes_separately: @@ -384,6 +354,19 @@ # Mark the end of the module (for the index) out(' ' + self.indexterm(doc, 'end')) + def render_graph(self, graph): + if graph is None: return '' + graph.caption = graph.title = None + if self._pdflatex: + return graph.to_dot2tex() +## image_url = '%s.ps' % graph.uid +## image_file = os.path.join(self._directory, image_url) +## return graph.to_pdf(image_file, image_url) + else: + image_url = '%s.eps' % graph.uid + image_file = os.path.join(self._directory, image_url) + return graph.to_latex(image_file, image_url) + def write_class(self, out, doc): if self._list_classes_separately: self.write_header(out, doc) @@ -396,41 +379,60 @@ if self._list_classes_separately: seclevel = 0 out(self.section('%s %s' % (self.doc_kind(doc), - doc.canonical_name), seclevel)) + _dotted(doc.canonical_name)), + seclevel, ref=doc)) else: seclevel = 1 out(self.section('%s %s' % (self.doc_kind(doc), - doc.canonical_name[-1]), seclevel)) + _dotted(doc.canonical_name[-1])), + seclevel, ref=doc)) - # Label our current location. - out(' \\label{%s}\n' % self.label(doc)) + if ((doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0) or + (doc.subclasses not in (UNKNOWN,None) and len(doc.subclasses)>0)): + # Display bases graphically, if requested. + if 'umlclasstree' in self._graph_types: +## linker = self._LatexDocstringLinker() + graph = uml_class_tree_graph(doc, self._docstring_linker, doc) + out(self.render_graph(graph)) + + elif 'classtree' in self._graph_types: +## linker = self._LatexDocstringLinker() + graph = class_tree_graph([doc], self._docstring_linker, doc) + out(self.render_graph(graph)) - # Add our base list. - if doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0: - out(self.base_tree(doc)) + # Otherwise, use ascii-art. + else: + + # Add our base list. + if doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0: + out(self.base_tree(doc)) - # The class's known subclasses - if doc.subclasses not in (UNKNOWN, None) and len(doc.subclasses) > 0: - sc_items = [plaintext_to_latex('%s' % sc.canonical_name) - for sc in doc.subclasses] - out(self._descrlist(sc_items, 'Known Subclasses', short=1)) + # The class's known subclasses + if doc.subclasses not in (UNKNOWN, None) and len(doc.subclasses) > 0: + sc_items = [_hyperlink(sc, '%s' % sc.canonical_name) + for sc in doc.subclasses] + out(self._descrlist(sc_items, 'Known Subclasses', short=1)) # The class's description. if doc.descr not in (None, UNKNOWN): + out(' '*4 + '\\begin{EpydocClassDescription}\n') out(self.docstring_to_latex(doc.descr)) + out(' '*4 + '\\end{EpydocClassDescription}\n') # Version, author, warnings, requirements, notes, etc. self.write_standard_fields(out, doc) # Contents. - self.write_func_list(out, 'Methods', doc, 'method', - seclevel+1) - self.write_var_list(out, 'Properties', doc, - 'property', seclevel+1) - self.write_var_list(out, 'Class Variables', doc, - 'classvariable', seclevel+1) - self.write_var_list(out, 'Instance Variables', doc, - 'instancevariable', seclevel+1) + self.write_list(out, 'Methods', doc, 'EpydocFunctionList', + 'method', seclevel+1) + self.write_list(out, 'Properties', doc, 'EpydocPropertyList', + 'property', seclevel+1) + self.write_list(out, 'Class Variables', doc, + 'EpydocClassVariableList', + 'classvariable', seclevel+1) + self.write_list(out, 'Instance Variables', doc, + 'EpydocInstanceVariableList', + 'instancevariable', seclevel+1) # Mark the end of the class (for the index) out(' ' + self.indexterm(doc, 'end')) @@ -455,23 +457,22 @@ def write_module_list(self, out, doc): if len(doc.submodules) == 0: return - self.write_start_of(out, 'Modules') + self.write_start_of(out, 'Submodules') - out(self.section('Modules', 1)) - out('\\begin{itemize}\n') - out('\\setlength{\\parskip}{0ex}\n') + out(self.section('Submodules', 1)) + out('\\begin{EpydocModuleList}\n') for group_name in doc.group_names(): if not doc.submodule_groups[group_name]: continue if group_name: - out(' \\item \\textbf{%s}\n' % group_name) - out(' \\begin{itemize}\n') + out(' \\EpydocGroup{%s}\n' % group_name) + out(' \\begin{EpydocModuleList}\n') for submodule in doc.submodule_groups[group_name]: self.write_module_tree_item(out, submodule) if group_name: - out(' \end{itemize}\n') + out(' \end{EpydocModuleList}\n') - out('\\end{itemize}\n\n') + out('\\end{EpydocModuleList}\n\n') def write_module_tree_item(self, out, doc, depth=0): """ @@ -479,19 +480,16 @@ @rtype: C{string} """ - out(' '*depth + '\\item \\textbf{') - out(plaintext_to_latex(doc.canonical_name[-1]) +'}') + out(' '*depth + '\\item[%s]' % _hyperlink(doc, doc.canonical_name[-1])) + if doc.summary not in (None, UNKNOWN): - out(': %s\n' % self.docstring_to_latex(doc.summary)) - if self._crossref: - out('\n \\textit{(Section \\ref{%s}' % self.label(doc)) - out(', p.~\\pageref{%s})}\n\n' % self.label(doc)) + out(' %s\n' % self.docstring_to_latex(doc.summary)) + out(self.crossref(doc) + '\n\n') if doc.submodules != UNKNOWN and doc.submodules: - out(' '*depth + ' \\begin{itemize}\n') - out(' '*depth + '\\setlength{\\parskip}{0ex}\n') + out(' '*depth + ' \\begin{EpydocModuleList}\n') for submodule in doc.submodules: self.write_module_tree_item(out, submodule, depth+4) - out(' '*depth + ' \\end{itemize}\n') + out(' '*depth + ' \\end{EpydocModuleList}\n') #//////////////////////////////////////////////////////////// #{ Base class trees @@ -502,7 +500,7 @@ width = self._find_tree_width(doc)+2 linespec = [] s = ('&'*(width-4)+'\\multicolumn{2}{l}{\\textbf{%s}}\n' % - plaintext_to_latex('%s'%self._base_name(doc))) + _dotted('%s'%self._base_name(doc))) s += '\\end{tabular}\n\n' top = 1 else: @@ -537,7 +535,7 @@ return width def _base_tree_line(self, doc, width, linespec): - base_name = plaintext_to_latex(self._base_name(doc)) + base_name = _dotted(self._base_name(doc)) # linespec is a list of booleans. s = '%% Line for %s, linespec=%s\n' % (base_name, linespec) @@ -546,8 +544,8 @@ # The base class name. s += ('\\multicolumn{%s}{r}{' % labelwidth) - s += '\\settowidth{\\BCL}{%s}' % base_name - s += '\\multirow{2}{\\BCL}{%s}}\n' % base_name + s += '\\settowidth{\\EpydocBCL}{%s}' % base_name + s += '\\multirow{2}{\\EpydocBCL}{%s}}\n' % _hyperlink(doc, self._base_name(doc)) # The vertical bars for other base classes (top half) for vbar in linespec: @@ -587,38 +585,36 @@ # Write a header. self.write_start_of(out, 'Classes') out(self.section('Classes', 1)) - out('\\begin{itemize}') - out(' \\setlength{\\parskip}{0ex}\n') + out('\\begin{EpydocClassList}\n') for name, var_docs in groups: if name: - out(' \\item \\textbf{%s}\n' % name) - out(' \\begin{itemize}\n') + out(' \\EpydocGroup{%s}\n' % name) + out(' \\begin{EpydocClassList}\n') # Add the lines for each class for var_doc in var_docs: self.write_class_list_line(out, var_doc) if name: - out(' \\end{itemize}\n') + out(' \\end{EpydocClassList}\n') - out('\\end{itemize}\n') + out('\\end{EpydocClassList}\n') def write_class_list_line(self, out, var_doc): if var_doc.value in (None, UNKNOWN): return # shouldn't happen doc = var_doc.value - out(' ' + '\\item \\textbf{') - out(plaintext_to_latex(var_doc.name) + '}') + out(' ' + '\\item[%s]' % _hyperlink(var_doc.target, + var_doc.name)) if doc.summary not in (None, UNKNOWN): out(': %s\n' % self.docstring_to_latex(doc.summary)) - if self._crossref: - out(('\n \\textit{(Section \\ref{%s}' % self.label(doc))) - out((', p.~\\pageref{%s})}\n\n' % self.label(doc))) + out(self.crossref(doc) + '\n\n') #//////////////////////////////////////////////////////////// - #{ Function List + #{ Details Lists #//////////////////////////////////////////////////////////// - _FUNC_GROUP_HEADER = '\n\\large{\\textbf{\\textit{%s}}}\n\n' - def write_func_list(self, out, heading, doc, value_type, seclevel=1): + # Also used for the property list. + def write_list(self, out, heading, doc, list_type, + value_type, seclevel=1): # Divide all public variables of the given type into groups. groups = [(plaintext_to_latex(group_name), doc.select_variables(group=group_name, imported=False, @@ -634,10 +630,12 @@ self.write_start_of(out, heading) out(' '+self.section(heading, seclevel)) + out('\\begin{%s}\n' % list_type) + # Write a section for each group. grouped_inh_vars = {} for name, var_docs in groups: - self.write_func_group(out, doc, name, var_docs, grouped_inh_vars) + self.write_list_group(out, doc, name, var_docs, grouped_inh_vars) # Write a section for each inheritance pseudo-group (used if # inheritance=='grouped') @@ -646,14 +644,19 @@ if base in grouped_inh_vars: hdr = ('Inherited from %s' % plaintext_to_latex('%s' % base.canonical_name)) - if self._crossref and base in self.class_set: - hdr += ('\\textit{(Section \\ref{%s})}' % - self.label(base)) - out(self._FUNC_GROUP_HEADER % (hdr)) + out(self.crossref(base) + '\n\n') + out('\\EpydocGroup{%s}\n' % hdr) for var_doc in grouped_inh_vars[base]: - self.write_func_list_box(out, var_doc) + if isinstance(var_doc.value, RoutineDoc): + self.write_function(out, var_doc) + elif isinstance(var_doc.value, PropertyDoc): + self.write_property(out, var_doc) + else: + self.write_var(out, var_doc) + + out('\\end{%s}\n\n' % list_type) - def write_func_group(self, out, doc, name, var_docs, grouped_inh_vars): + def write_list_group(self, out, doc, name, var_docs, grouped_inh_vars): # Split up the var_docs list, according to the way each var # should be displayed: # - listed_inh_vars -- for listed inherited variables. @@ -678,15 +681,20 @@ # Write a header for the group. if name: - out(self._FUNC_GROUP_HEADER % name) - # Write an entry for each normal var: + out('\\EpydocGroup{%s}\n' % name) + # Write an entry for each object in the group: for var_doc in normal_vars: - self.write_func_list_box(out, var_doc) - # Write a subsection for inherited vars: + if isinstance(var_doc.value, RoutineDoc): + self.write_function(out, var_doc) + elif isinstance(var_doc.value, PropertyDoc): + self.write_property(out, var_doc) + else: + self.write_var(out, var_doc) + # Write a subsection for inherited objects: if listed_inh_vars: - self.write_func_inheritance_list(out, doc, listed_inh_vars) - - def write_func_inheritance_list(self, out, doc, listed_inh_vars): + self.write_inheritance_list(out, doc, listed_inh_vars) + + def write_inheritance_list(self, out, doc, listed_inh_vars): for base in doc.mro(): if base not in listed_inh_vars: continue #if str(base.canonical_name) == 'object': continue @@ -694,333 +702,324 @@ if self._public_filter: var_docs = [v for v in var_docs if v.is_public] if var_docs: - hdr = ('Inherited from %s' % - plaintext_to_latex('%s' % base.canonical_name)) - if self._crossref and base in self.class_set: - hdr += ('\\textit{(Section \\ref{%s})}' % - self.label(base)) - out(self._FUNC_GROUP_HEADER % hdr) - out('\\begin{quote}\n') - out('%s\n' % ', '.join( - ['%s()' % plaintext_to_latex(var_doc.name) - for var_doc in var_docs])) - out('\\end{quote}\n') - - def write_func_list_box(self, out, var_doc): + out('\\EpydocInheritanceList{') + out(plaintext_to_latex('%s' % base.canonical_name)) + out(self.crossref(base)) + out('}{') + out(', '.join(['%s' % plaintext_to_latex(var_doc.name) + + self._parens_if_func(var_doc) + for var_doc in var_docs])) + out('}\n') + + def _parens_if_func(self, var_doc): + if isinstance(var_doc.value, RoutineDoc): return '()' + else: return '' + + #//////////////////////////////////////////////////////////// + #{ Function Details + #//////////////////////////////////////////////////////////// + + def write_function(self, out, var_doc): func_doc = var_doc.value is_inherited = (var_doc.overrides not in (None, UNKNOWN)) - # nb: this gives the containing section, not a reference + # Add the function to the index. Note: this will actually + # select the containing section, and won't give a reference # directly to the function. if not is_inherited: - out(' \\label{%s}\n' % self.label(func_doc)) - out(' %s\n' % self.indexterm(func_doc)) + out(' %s%%\n' % self.indexterm(func_doc)) - # Start box for this function. - out(' \\vspace{0.5ex}\n\n') - out('\\hspace{.8\\funcindent}') - out('\\begin{boxedminipage}{\\funcwidth}\n\n') + # This latex command takes 8 arguments. + out('\\EpydocFunction{%\n') - # Function signature. - out(' %s\n\n' % self.function_signature(var_doc)) + # Argument 1: the function signature + out(self.function_signature(var_doc)) + out('}{%\n') - if (func_doc.docstring not in (None, UNKNOWN) and - func_doc.docstring.strip() != ''): - out(' \\vspace{-1.5ex}\n\n') - out(' \\rule{\\textwidth}{0.5\\fboxrule}\n') - - # Description - out("\\setlength{\\parskip}{2ex}\n") + # Argument 2: the function description if func_doc.descr not in (None, UNKNOWN): out(self.docstring_to_latex(func_doc.descr, 4)) + out('}{%\n') - # Parameters - out("\\setlength{\\parskip}{1ex}\n") + # Argument 3: the function parameter descriptions if func_doc.arg_descrs or func_doc.arg_types: - # Find the longest name. - longest = max([0]+[len(n) for n in func_doc.arg_types]) - for names, descrs in func_doc.arg_descrs: - longest = max([longest]+[len(n) for n in names]) - # Table header. - out(' '*6+'\\textbf{Parameters}\n') - out(' \\vspace{-1ex}\n\n') - out(' '*6+'\\begin{quote}\n') - out(' \\begin{Ventry}{%s}\n\n' % (longest*'x')) - # Add params that have @type but not @param info: - arg_descrs = list(func_doc.arg_descrs) - args = set() - for arg_names, arg_descr in arg_descrs: - args.update(arg_names) - for arg in var_doc.value.arg_types: - if arg not in args: - arg_descrs.append( ([arg],None) ) - # Display params - for (arg_names, arg_descr) in arg_descrs: - arg_name = plaintext_to_latex(', '.join(arg_names)) - out('%s\\item[%s]\n\n' % (' '*10, arg_name)) - if arg_descr: - out(self.docstring_to_latex(arg_descr, 10)) - for arg_name in arg_names: - arg_typ = func_doc.arg_types.get(arg_name) - if arg_typ is not None: - if len(arg_names) == 1: - lhs = 'type' - else: - lhs = 'type of %s' % arg_name - rhs = self.docstring_to_latex(arg_typ).strip() - out('%s{\\it (%s=%s)}\n\n' % (' '*12, lhs, rhs)) - out(' \\end{Ventry}\n\n') - out(' '*6+'\\end{quote}\n\n') - - # Returns - rdescr = func_doc.return_descr - rtype = func_doc.return_type - if rdescr not in (None, UNKNOWN) or rtype not in (None, UNKNOWN): - out(' '*6+'\\textbf{Return Value}\n') - out(' \\vspace{-1ex}\n\n') - out(' '*6+'\\begin{quote}\n') - if rdescr not in (None, UNKNOWN): - out(self.docstring_to_latex(rdescr, 6)) - if rtype not in (None, UNKNOWN): - out(' '*6+'{\\it (type=%s)}\n\n' % - self.docstring_to_latex(rtype, 6).strip()) - elif rtype not in (None, UNKNOWN): - out(self.docstring_to_latex(rtype, 6)) - out(' '*6+'\\end{quote}\n\n') + self.write_function_parameters(out, var_doc) + out('}{%\n') - # Raises + # Argument 4: The return description + if func_doc.return_descr not in (None, UNKNOWN): + out(self.docstring_to_latex(func_doc.return_descr, 6)) + out('}{%\n') + + # Argument 5: The return type + if func_doc.return_type not in (None, UNKNOWN): + out(self.docstring_to_latex(func_doc.return_type, 6).strip()) + out('}{%\n') + + # Argument 6: The raises section if func_doc.exception_descrs not in (None, UNKNOWN, [], ()): - out(' '*6+'\\textbf{Raises}\n') - out(' \\vspace{-1ex}\n\n') - out(' '*6+'\\begin{quote}\n') - out(' \\begin{description}\n\n') + out(' '*6+'\\begin{EpydocFunctionRaises}\n') for name, descr in func_doc.exception_descrs: - out(' '*10+'\\item[\\texttt{%s}]\n\n' % + out(' '*10+'\\item[%s]\n\n' % plaintext_to_latex('%s' % name)) out(self.docstring_to_latex(descr, 10)) - out(' \\end{description}\n\n') - out(' '*6+'\\end{quote}\n\n') + out(' '*6+'\\end{EpydocFunctionRaises}\n\n') + out('}{%\n') - ## Overrides + # Argument 7: The overrides section if var_doc.overrides not in (None, UNKNOWN): - out(' Overrides: ' + - plaintext_to_latex('%s'%var_doc.overrides.canonical_name)) + out('\\EpydocFunctionOverrides') if (func_doc.docstring in (None, UNKNOWN) and var_doc.overrides.value.docstring not in (None, UNKNOWN)): - out(' \textit{(inherited documentation)}') - out('\n\n') + out('[1]') + out('{%s}\n\n' + % _hyperlink(var_doc.overrides, + '%s' % var_doc.overrides.canonical_name)) + out('}{%\n') - # Add version, author, warnings, requirements, notes, etc. + # Argument 8: The metadata section self.write_standard_fields(out, func_doc) + out('}\n') + - out(' \\end{boxedminipage}\n\n') - + def write_function_parameters(self, out, var_doc): + func_doc = var_doc.value + # Find the longest name. + longest = max([0]+[len(n) for n in func_doc.arg_types]) + for names, descrs in func_doc.arg_descrs: + longest = max([longest]+[len(n) for n in names]) + # Table header. + out(' '*6+'\\begin{EpydocFunctionParameters}{%s}\n' % (longest*'x')) + # Add params that have @type but not @param info: + arg_descrs = list(func_doc.arg_descrs) + args = set() + for arg_names, arg_descr in arg_descrs: + args.update(arg_names) + for arg in var_doc.value.arg_types: + if arg not in args: + arg_descrs.append( ([arg],None) ) + # Display params + for (arg_names, arg_descr) in arg_descrs: + arg_name = plaintext_to_latex(', '.join(arg_names)) + out('%s\\item[%s]\n\n' % (' '*10, arg_name)) + if arg_descr: + out(self.docstring_to_latex(arg_descr, 10)) + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!! JEG - this loop needs abstracting + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + for arg_name in arg_names: + arg_typ = func_doc.arg_types.get(arg_name) + if arg_typ is not None: + if len(arg_names) == 1: + lhs = 'type' + else: + lhs = 'type of %s' % arg_name + rhs = self.docstring_to_latex(arg_typ).strip() + out('%s{\\it (%s=%s)}\n\n' % (' '*12, lhs, rhs)) + out(' '*6+'\\end{EpydocFunctionParameters}\n\n') + def function_signature(self, var_doc): func_doc = var_doc.value func_name = var_doc.name - + + s = ('\\begin{EpydocFunctionSignature}{%s}%%\n' % + _hypertarget(var_doc, func_name)) + # This should never happen, but just in case: - if func_doc in (None, UNKNOWN): - return ('\\raggedright \\textbf{%s}(...)' % - plaintext_to_latex(func_name)) - - if func_doc.posargs == UNKNOWN: - args = ['...'] - else: - args = [self.func_arg(name, default) for (name, default) - in zip(func_doc.posargs, func_doc.posarg_defaults)] - if func_doc.vararg: - if func_doc.vararg == '...': - args.append('\\textit{...}') + if func_doc not in (None, UNKNOWN): + if func_doc.posargs == UNKNOWN: + args = ['\\GenericArg{}'] else: - args.append('*\\textit{%s}' % - plaintext_to_latex(func_doc.vararg)) - if func_doc.kwarg: - args.append('**\\textit{%s}' % - plaintext_to_latex(func_doc.kwarg)) - return ('\\raggedright \\textbf{%s}(%s)' % - (plaintext_to_latex(func_name), ', '.join(args))) + args = [self.func_arg(name, default) for (name, default) + in zip(func_doc.posargs, func_doc.posarg_defaults)] + if func_doc.vararg: + if func_doc.vararg == '...': + args.append('\\GenericArg{}') + else: + args.append('\\VarArg{%s}' % + plaintext_to_latex(func_doc.vararg)) + if func_doc.kwarg: + args.append('\\KWArg{%s}' % plaintext_to_latex(func_doc.kwarg)) + + s += ' '+'%\n \\and'.join(args)+'%\n' + s += '\\end{EpydocFunctionSignature}%\n' + + return s def func_arg(self, name, default): - s = '\\textit{%s}' % plaintext_to_latex(self._arg_name(name)) + s = '\\Param' + if default is not None: - s += '={\\tt %s}' % default.summary_pyval_repr().to_latex(None) + s += "[%s]" % default.summary_pyval_repr().to_latex(None) + s += '{%s}' % self._arg_name(name) + return s - + def _arg_name(self, arg): if isinstance(arg, basestring): - return arg - elif len(arg) == 1: - return '(%s,)' % self._arg_name(arg[0]) + return plaintext_to_latex(arg) else: - return '(%s)' % (', '.join([self._arg_name(a) for a in arg])) + return '\\TupleArg{%s}' % '\\and '.join([self._arg_name(a) + for a in arg]) - #//////////////////////////////////////////////////////////// - #{ Variable List - #//////////////////////////////////////////////////////////// - _VAR_GROUP_HEADER = '\\multicolumn{2}{|l|}{\\textit{%s}}\\\\\n' + +# def write_func_list_box(self, out, var_doc): +# func_doc = var_doc.value +# is_inherited = (var_doc.overrides not in (None, UNKNOWN)) - # Also used for the property list. - def write_var_list(self, out, heading, doc, value_type, seclevel=1): - groups = [(plaintext_to_latex(group_name), - doc.select_variables(group=group_name, imported=False, - value_type=value_type, - public=self._public_filter)) - for group_name in doc.group_names()] +# out('\\begin{EpydocFunction}%\n') +# # Function signature. +# out(self.function_signature(var_doc)) - # Discard any empty groups; and return if they're all empty. - groups = [(g,vars) for (g,vars) in groups if vars] - if not groups: return +# # nb: this gives the containing section, not a reference +# # directly to the function. +# if not is_inherited: +# out(' %s%%\n' % self.indexterm(func_doc)) - # Write a header. - self.write_start_of(out, heading) - out(' '+self.section(heading, seclevel)) - - # [xx] without this, there's a huge gap before the table -- why?? - out(' \\vspace{-1cm}\n') +# # If we have nothing else to say, then don't create an +# # \EpydocFunctionInfo environment. +# if not (func_doc.descr not in (None, UNKNOWN) or +# func_doc.arg_descrs or func_doc.arg_types or +# func_doc.return_descr not in (None, UNKNOWN) or +# func_doc.return_type not in (None, UNKNOWN) or +# func_doc.exception_descrs not in (None, UNKNOWN, [], ()) or +# var_doc.overrides not in (None, UNKNOWN) or +# func_doc.metadata not in (None, UNKNOWN, [], ())): +# out(' \\end{EpydocFunction}\n\n') +# return - out('\\hspace{\\varindent}') - out('\\begin{longtable}') - out('{|p{\\varnamewidth}|') - out('p{\\vardescrwidth}|l}\n') - out('\\cline{1-2}\n') +# out('\\begin{EpydocFunctionInfo}%\n') + +# # Description +# if func_doc.descr not in (None, UNKNOWN): +# out(' '*4 + '\\begin{EpydocFunctionDescription}\n') +# out(self.docstring_to_latex(func_doc.descr, 4)) +# out(' '*4 + '\\end{EpydocFunctionDescription}\n') - # Set up the headers & footer (this makes the table span - # multiple pages in a happy way). - out('\\cline{1-2} ') - out('\\centering \\textbf{Name} & ') - out('\\centering \\textbf{Description}& \\\\\n') - out('\\cline{1-2}\n') - out('\\endhead') - out('\\cline{1-2}') - out('\\multicolumn{3}{r}{\\small\\textit{') - out('continued on next page}}\\\\') - out('\\endfoot') - out('\\cline{1-2}\n') - out('\\endlastfoot') +# # Parameters +# if func_doc.arg_descrs or func_doc.arg_types: +# # Find the longest name. +# longest = max([0]+[len(n) for n in func_doc.arg_types]) +# for names, descrs in func_doc.arg_descrs: +# longest = max([longest]+[len(n) for n in names]) +# # Table header. +# out(' '*6+'\\begin{EpydocFunctionParameters}{%s}\n' % (longest*'x')) +# # Add params that have @type but not @param info: +# arg_descrs = list(func_doc.arg_descrs) +# args = set() +# for arg_names, arg_descr in arg_descrs: +# args.update(arg_names) +# for arg in var_doc.value.arg_types: +# if arg not in args: +# arg_descrs.append( ([arg],None) ) +# # Display params +# for (arg_names, arg_descr) in arg_descrs: +# arg_name = plaintext_to_latex(', '.join(arg_names)) +# out('%s\\item[%s]\n\n' % (' '*10, arg_name)) +# if arg_descr: +# out(self.docstring_to_latex(arg_descr, 10)) +# # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# # !!! JEG - this loop needs abstracting +# # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# for arg_name in arg_names: +# arg_typ = func_doc.arg_types.get(arg_name) +# if arg_typ is not None: +# if len(arg_names) == 1: +# lhs = 'type' +# else: +# lhs = 'type of %s' % arg_name +# rhs = self.docstring_to_latex(arg_typ).strip() +# out('%s{\\it (%s=%s)}\n\n' % (' '*12, lhs, rhs)) +# out(' '*6+'\\end{EpydocFunctionParameters}\n\n') + +# # Returns +# rdescr = func_doc.return_descr +# rtype = func_doc.return_type +# if rdescr not in (None, UNKNOWN) or rtype not in (None, UNKNOWN): +# out(' '*6+'\\EpydocFunctionReturns') +# if rtype not in (None, UNKNOWN): +# out('[%s]' % self.docstring_to_latex(rtype, 6).strip()) +# if rdescr not in (None, UNKNOWN): +# out('{%s}' % self.docstring_to_latex(rdescr, 6)) +# else: +# out('{}') +# out('\n\n') - # Write a section for each group. - grouped_inh_vars = {} - for name, var_docs in groups: - self.write_var_group(out, doc, name, var_docs, grouped_inh_vars) +# # Raises +# if func_doc.exception_descrs not in (None, UNKNOWN, [], ()): +# out(' '*6+'\\begin{EpydocFunctionRaises}\n') +# for name, descr in func_doc.exception_descrs: +# out(' '*10+'\\item[%s]\n\n' % +# plaintext_to_latex('%s' % name)) +# out(self.docstring_to_latex(descr, 10)) +# out(' '*6+'\\end{EpydocFunctionRaises}\n\n') - # Write a section for each inheritance pseudo-group (used if - # inheritance=='grouped') - if grouped_inh_vars: - for base in doc.mro(): - if base in grouped_inh_vars: - hdr = ('Inherited from %s' % - plaintext_to_latex('%s' % base.canonical_name)) - if self._crossref and base in self.class_set: - hdr += (' \\textit{(Section \\ref{%s})}' % - self.label(base)) - out(self._VAR_GROUP_HEADER % (hdr)) - out('\\cline{1-2}\n') - for var_doc in grouped_inh_vars[base]: - if isinstance(var_doc.value3, PropertyDoc): - self.write_property_list_line(out, var_doc) - else: - self.write_var_list_line(out, var_doc) - - out('\\end{longtable}\n\n') - - def write_var_group(self, out, doc, name, var_docs, grouped_inh_vars): - # Split up the var_docs list, according to the way each var - # should be displayed: - # - listed_inh_vars -- for listed inherited variables. - # - grouped_inh_vars -- for grouped inherited variables. - # - normal_vars -- for all other variables. - listed_inh_vars = {} - normal_vars = [] - for var_doc in var_docs: - if var_doc.container != doc: - base = var_doc.container - if (base not in self.class_set or - self._inheritance == 'listed'): - listed_inh_vars.setdefault(base,[]).append(var_doc) - elif self._inheritance == 'grouped': - grouped_inh_vars.setdefault(base,[]).append(var_doc) - elif self._inheritance == 'hidden': - pass - else: - normal_vars.append(var_doc) - else: - normal_vars.append(var_doc) - - # Write a header for the group. - if name: - out(self._VAR_GROUP_HEADER % name) - out('\\cline{1-2}\n') - # Write an entry for each normal var: - for var_doc in normal_vars: - if isinstance(var_doc.value, PropertyDoc): - self.write_property_list_line(out, var_doc) - else: - self.write_var_list_line(out, var_doc) - # Write a subsection for inherited vars: - if listed_inh_vars: - self.write_var_inheritance_list(out, doc, listed_inh_vars) +# ## Overrides +# if var_doc.overrides not in (None, UNKNOWN): +# out('\\EpydocFunctionOverrides') +# if (func_doc.docstring in (None, UNKNOWN) and +# var_doc.overrides.value.docstring not in (None, UNKNOWN)): +# out('[1]') +# out('{%s}\n\n' +# % _hyperlink(var_doc.overrides, +# '%s' % var_doc.overrides.canonical_name)) - def write_var_inheritance_list(self, out, doc, listed_inh_vars): - for base in doc.mro(): - if base not in listed_inh_vars: continue - #if str(base.canonical_name) == 'object': continue - var_docs = listed_inh_vars[base] - if self._public_filter: - var_docs = [v for v in var_docs if v.is_public] - if var_docs: - hdr = ('Inherited from %s' % - plaintext_to_latex('%s' % base.canonical_name)) - if self._crossref and base in self.class_set: - hdr += (' \\textit{(Section \\ref{%s})}' % - self.label(base)) - out(self._VAR_GROUP_HEADER % hdr) - out('\\multicolumn{2}{|p{\\varwidth}|}{' - '\\raggedright %s}\\\\\n' % - ', '.join(['%s' % plaintext_to_latex(var_doc.name) - for var_doc in var_docs])) - out('\\cline{1-2}\n') +# # Add version, author, warnings, requirements, notes, etc. +# self.write_standard_fields(out, func_doc) - - def write_var_list_line(self, out, var_doc): - out('\\raggedright ') - out(plaintext_to_latex(var_doc.name, nbsp=True, breakany=True)) - out(' & ') +# out(' \\end{EpydocFunctionInfo}\n') +# out(' \\end{EpydocFunction}\n\n') + + #//////////////////////////////////////////////////////////// + #{ Variable Details + #//////////////////////////////////////////////////////////// + + def write_var(self, out, var_doc): has_descr = var_doc.descr not in (None, UNKNOWN) has_type = var_doc.type_descr not in (None, UNKNOWN) - has_value = var_doc.value is not UNKNOWN - if has_type or has_value: - out('\\raggedright ') + 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)) + + out('\\EpydocVariable{%s}{' % _hypertarget(var_doc, var_doc.name)) if has_descr: out(self.docstring_to_latex(var_doc.descr, 10).strip()) - if has_type or has_value: out('\n\n') - if has_value: - out('\\textbf{Value:} \n{\\tt %s}' % - var_doc.value.summary_pyval_repr().to_latex(None)) + out('}{') if has_type: - ptype = self.docstring_to_latex(var_doc.type_descr, 12).strip() - out('%s{\\it (type=%s)}' % (' '*12, ptype)) - out('&\\\\\n') - out('\\cline{1-2}\n') + out(self.docstring_to_latex(var_doc.type_descr, 12).strip()) + out('}{') + if has_repr: + out(var_doc.value.summary_pyval_repr().to_latex(None)) + out('}\n') - def write_property_list_line(self, out, var_doc): + #//////////////////////////////////////////////////////////// + #{ Property Details + #//////////////////////////////////////////////////////////// + + def write_property(self, out, var_doc): prop_doc = var_doc.value - out('\\raggedright ') - out(plaintext_to_latex(var_doc.name, nbsp=True, breakany=True)) - out(' & ') has_descr = prop_doc.descr not in (None, UNKNOWN) has_type = prop_doc.type_descr not in (None, UNKNOWN) - if has_descr or has_type: - out('\\raggedright ') + out('\\EpydocProperty{%s}{' % _hypertarget(var_doc, var_doc.name)) if has_descr: out(self.docstring_to_latex(prop_doc.descr, 10).strip()) - if has_type: out('\n\n') + out('}{') if has_type: - ptype = self.docstring_to_latex(prop_doc.type_descr, 12).strip() - out('%s{\\it (type=%s)}' % (' '*12, ptype)) - # [xx] List the fget/fset/fdel functions? - out('&\\\\\n') - out('\\cline{1-2}\n') + out(self.docstring_to_latex(prop_doc.type_descr, 12).strip()) + out('}{') + # [xx] What if the accessor is private and show_private=False? + if (prop_doc.fget not in (None, UNKNOWN) and + not prop_doc.fget.canonical_name[0].startswith('??')): + out(_dotted(prop_doc.fget.canonical_name)) + out('}{') + if (prop_doc.fset not in (None, UNKNOWN) and + not prop_doc.fset.canonical_name[0].startswith('??')): + out(_dotted(prop_doc.fset.canonical_name)) + out('}{') + if (prop_doc.fdel not in (None, UNKNOWN) and + not prop_doc.fdel.canonical_name[0].startswith('??')): + out(_dotted(prop_doc.fdel.canonical_name)) + out('}\n') #//////////////////////////////////////////////////////////// #{ Standard Fields @@ -1063,18 +1062,18 @@ if plural is None: plural = singular if len(items) == 0: return '' if len(items) == 1 and singular is not None: - return '\\textbf{%s:} %s\n\n' % (singular, items[0]) + return ('\\EpydocMetadataSingleValue{%s}{%s}\n\n' % + (singular, items[0])) if short: - s = '\\textbf{%s:}\n' % plural - items = [item.strip() for item in items] - return s + ',\n '.join(items) + '\n\n' + s = '\\begin{EpydocMetadataShortList}{%s}%%\n ' % plural + s += '%\n \\and '.join([item.strip() for item in items]) + s += '%\n\\end{EpydocMetadataShortList}\n\n' + return s else: - s = '\\textbf{%s:}\n' % plural - s += '\\begin{quote}\n' - s += ' \\begin{itemize}\n\n \item\n' - s += ' \\setlength{\\parskip}{0.6ex}\n' - s += '\n\n \item '.join(items) - return s + '\n\n\\end{itemize}\n\n\\end{quote}\n\n' + s = '\\begin{EpydocMetadataLongList}{%s}%%\n' % plural + s += '\n\n'.join([' \item %s%%' % item for item in items]) + s += '\n\\end{EpydocMetadataLongList}\n\n' + return s #//////////////////////////////////////////////////////////// @@ -1089,12 +1088,32 @@ def translate_identifier_xref(self, identifier, label=None): if label is None: label = markup.plaintext_to_latex(identifier) return '\\texttt{%s}' % label + # [xx] Should this be added to the DocstringLinker interface??? + # Currently, this is *only* used by dotgraph. + def url_for(self, identifier): + return None +## if isinstance(identifier, (basestring, DottedName)): +## doc = self.docindex.find(identifier, self.container) +## if doc: +## return identifier +## else: +## return None +## +## elif isinstance(identifier, APIDoc): +## return ':'.join(identifier.canonical_name) +## doc = identifier +## +## else: +## raise TypeError('Expected string or APIDoc') _docstring_linker = _LatexDocstringLinker() def docstring_to_latex(self, docstring, indent=0, breakany=0): if docstring is None: return '' - return docstring.to_latex(self._docstring_linker, indent=indent, - hyperref=self._hyperref) + s = docstring.to_latex(self._docstring_linker, indent=indent, + hyperref=self._hyperref) + return (' '*indent + '\\begin{EpydocDescription}%\n' + + s.strip() + '%\n' + + ' '*indent + '\\end{EpydocDescription}\n\n') #//////////////////////////////////////////////////////////// #{ Helpers @@ -1112,18 +1131,23 @@ def write_start_of(self, out, section_name): out('\n' + 75*'%' + '\n') - out('%%' + ((71-len(section_name))/2)*' ') - out(section_name) - out(((72-len(section_name))/2)*' ' + '%%\n') + out('%%' + section_name.center(71) + '%%\n') out(75*'%' + '\n\n') - def section(self, title, depth=0): + def section(self, title, depth=0, ref=None): sec = self.SECTIONS[depth+self._top_section] - return (('%s\n\n' % sec) % plaintext_to_latex(title)) - - def sectionstar(self, title, depth): + text = (sec % title) + '%\n' + if ref: + text += _hypertarget(ref, "") + '%\n' + return text + + # [xx] not used: + def sectionstar(self, title, depth, ref=None): sec = self.STARSECTIONS[depth+self._top_section] - return (('%s\n\n' % sec) % plaintext_to_latex(title)) + text = (sec % title) + '%\n' + if ref: + text += _hypertarget(ref, "") + '%\n' + return text def doc_kind(self, doc): if isinstance(doc, ModuleDoc) and doc.is_package == True: @@ -1154,28 +117... [truncated message content] |
From: <ed...@us...> - 2008-02-23 06:00:31
|
Revision: 1746 http://epydoc.svn.sourceforge.net/epydoc/?rev=1746&view=rev Author: edloper Date: 2008-02-22 22:00:30 -0800 (Fri, 22 Feb 2008) Log Message: ----------- - Added url_for() to the DocstringLinker interface Modified Paths: -------------- trunk/epydoc/src/epydoc/docwriter/html.py trunk/epydoc/src/epydoc/markup/__init__.py Modified: trunk/epydoc/src/epydoc/docwriter/html.py =================================================================== --- trunk/epydoc/src/epydoc/docwriter/html.py 2008-02-23 05:59:54 UTC (rev 1745) +++ trunk/epydoc/src/epydoc/docwriter/html.py 2008-02-23 06:00:30 UTC (rev 1746) @@ -3487,8 +3487,6 @@ else: return self.htmlwriter.href(doc, label, 'link') - # [xx] Should this be added to the DocstringLinker interface??? - # Currently, this is *only* used by dotgraph. def url_for(self, identifier): if isinstance(identifier, (basestring, DottedName)): doc = self.docindex.find(identifier, self.container) Modified: trunk/epydoc/src/epydoc/markup/__init__.py =================================================================== --- trunk/epydoc/src/epydoc/markup/__init__.py 2008-02-23 05:59:54 UTC (rev 1745) +++ trunk/epydoc/src/epydoc/markup/__init__.py 2008-02-23 06:00:30 UTC (rev 1746) @@ -474,6 +474,14 @@ """ raise NotImplementedError, 'DocstringLinker.translate_xref()' + def url_for(self, identifier): + """ + Given an identifier, return a URL pointing at that identifier. + This is used to create hyperlinks in dotgraphs. + """ + raise NotImplementedError, 'DocstringLinker.url_for()' + + ################################################## ## ParseError exceptions ################################################## This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |