[Epydoc-commits] SF.net SVN: epydoc: [1473] trunk/epydoc/src/epydoc
Brought to you by:
edloper
|
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.
|