From jan at codespeak.net Thu Dec 1 15:33:05 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Thu, 1 Dec 2005 15:33:05 +0100 (CET) Subject: [py-svn] r20499 - py/dist/py/path/local Message-ID: <20051201143305.0326627B5B@code1.codespeak.net> Author: jan Date: Thu Dec 1 15:33:03 2005 New Revision: 20499 Modified: py/dist/py/path/local/local.py Log: py.path.local.pyimport: be more defensive when importing modules with symbolic links Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Thu Dec 1 15:33:03 2005 @@ -372,7 +372,8 @@ if ensuresyspath: self._prependsyspath(pkgpath.dirpath()) pkg = __import__(pkgpath.basename, None, None, []) - assert py.path.local(pkg.__file__).relto(pkgpath) + assert py.path.local(pkg.__file__).realpath().relto( + pkgpath.realpath()) if hasattr(pkg, '__package__'): modname = pkg.__package__.getimportname(self) assert modname is not None, "package %s doesn't know %s" % ( From cfbolz at codespeak.net Thu Dec 1 18:18:03 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 1 Dec 2005 18:18:03 +0100 (CET) Subject: [py-svn] r20513 - py/dist/py/bin Message-ID: <20051201171803.EDDC127B5B@code1.codespeak.net> Author: cfbolz Date: Thu Dec 1 18:18:02 2005 New Revision: 20513 Modified: py/dist/py/bin/rst2pdf.py Log: make passing the stylesheet option really work. Modified: py/dist/py/bin/rst2pdf.py ============================================================================== --- py/dist/py/bin/rst2pdf.py (original) +++ py/dist/py/bin/rst2pdf.py Thu Dec 1 18:18:02 2005 @@ -20,7 +20,7 @@ parser = optparse.OptionParser(usage=docstring) parser.add_option("-c", "--config", dest="configfile", help="use config file") -parser.add_option("--stylesheet", dest="stylesheet", default="rest.sty", +parser.add_option("--stylesheet", dest="stylesheet", default=None, help="use style sheet") parser.add_option("--debug", action="store_true", dest="debug", default=False, @@ -38,5 +38,6 @@ else: f = py.path.local(args[0]) graphvizdirective.path = f.dirpath() - process_rest_file(args[0], options.debug) + process_rest_file(args[0], options.stylesheet, options.debug) + From cfbolz at codespeak.net Thu Dec 1 18:19:02 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 1 Dec 2005 18:19:02 +0100 (CET) Subject: [py-svn] r20514 - in py/dist/py: bin misc Message-ID: <20051201171902.AF2A527B5B@code1.codespeak.net> Author: cfbolz Date: Thu Dec 1 18:19:01 2005 New Revision: 20514 Modified: py/dist/py/bin/py.rest py/dist/py/misc/rest.py Log: move graphviz directive to misc/rest.py to make it also usable when using py.test for a rest file Modified: py/dist/py/bin/py.rest ============================================================================== --- py/dist/py/bin/py.rest (original) +++ py/dist/py/bin/py.rest Thu Dec 1 18:19:01 2005 @@ -15,9 +15,7 @@ from py.__.misc import rest if __name__=='__main__': - from py.__.rest import restgraphviz basedir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) - graphvizdirective = restgraphviz.GraphvizDirective("png") sys.path.insert(0, basedir) if len(sys.argv) == 1: @@ -34,9 +32,7 @@ def rec(p): return p.check(dotfile=0) if p.check(dir=1): - graphvizdirective.path = p for x in p.visit(fil, rec): rest.process(x) elif p.check(file=1): - graphvizdirective.path = p.dirpath() rest.process(p) Modified: py/dist/py/misc/rest.py ============================================================================== --- py/dist/py/misc/rest.py (original) +++ py/dist/py/misc/rest.py Thu Dec 1 18:19:01 2005 @@ -1,3 +1,4 @@ +from py.__.rest import restgraphviz import sys, os, traceback import re @@ -16,6 +17,8 @@ stylesheet path (to be used if any) """ from docutils.core import publish_string + graphvizdirective = restgraphviz.GraphvizDirective( + "png", source_path.dirpath()) kwargs = { 'stylesheet' : stylesheet, 'stylesheet_path': None, From cfbolz at codespeak.net Sun Dec 4 12:50:11 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 4 Dec 2005 12:50:11 +0100 (CET) Subject: [py-svn] r20634 - py/dist/py/documentation Message-ID: <20051204115011.50BC627B56@code1.codespeak.net> Author: cfbolz Date: Sun Dec 4 12:50:10 2005 New Revision: 20634 Modified: py/dist/py/documentation/conftest.py Log: skip tests if docutils are not there Modified: py/dist/py/documentation/conftest.py ============================================================================== --- py/dist/py/documentation/conftest.py (original) +++ py/dist/py/documentation/conftest.py Sun Dec 4 12:50:10 2005 @@ -14,6 +14,11 @@ ) ) +try: + import docutils +except ImportError: + docutils = None + def checkdocutils(): try: import docutils @@ -52,6 +57,8 @@ class ReSTSyntaxTest(py.test.Item): def run(self): + if docutils is None: + py.test.skip("missing docutils") mypath = self.fspath _checkskip(mypath) restcheck(py.path.svnwc(mypath)) @@ -194,7 +201,7 @@ return results def join(self, name): - if not name.endswith('.txt'): + if not name.endswith('.txt'): return super(DocDirectory, self).join(name) p = self.fspath.join(name) if p.check(file=1): From cfbolz at codespeak.net Sun Dec 4 12:56:47 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 4 Dec 2005 12:56:47 +0100 (CET) Subject: [py-svn] r20635 - py/dist/py/misc Message-ID: <20051204115647.3E1D527B56@code1.codespeak.net> Author: cfbolz Date: Sun Dec 4 12:56:46 2005 New Revision: 20635 Modified: py/dist/py/misc/rest.py Log: make this import later to not require docutils installed for py.test Modified: py/dist/py/misc/rest.py ============================================================================== --- py/dist/py/misc/rest.py (original) +++ py/dist/py/misc/rest.py Sun Dec 4 12:56:46 2005 @@ -1,5 +1,3 @@ -from py.__.rest import restgraphviz - import sys, os, traceback import re @@ -11,6 +9,7 @@ pass def convert_rest_html(source, source_path, stylesheet=None, encoding='latin1'): + from py.__.rest import restgraphviz """ return html latin1-encoded document for the given input. source a ReST-string sourcepath where to look for includes (basically) From hpk at codespeak.net Sun Dec 4 13:25:09 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 4 Dec 2005 13:25:09 +0100 (CET) Subject: [py-svn] r20636 - py/dist/py/documentation Message-ID: <20051204122509.AAAD527B56@code1.codespeak.net> Author: hpk Date: Sun Dec 4 13:25:08 2005 New Revision: 20636 Modified: py/dist/py/documentation/test_conftest.py Log: the test should pass even if docutils is not present Modified: py/dist/py/documentation/test_conftest.py ============================================================================== --- py/dist/py/documentation/test_conftest.py (original) +++ py/dist/py/documentation/test_conftest.py Sun Dec 4 13:25:08 2005 @@ -34,4 +34,5 @@ l = session.getitemoutcomepairs(py.test.Item.Failed) assert len(l) == 0 l = session.getitemoutcomepairs(py.test.Item.Passed) - assert len(l) == 2 + l2 = session.getitemoutcomepairs(py.test.Item.Skipped) + assert len(l+l2) == 2 From cfbolz at codespeak.net Sun Dec 4 13:28:53 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 4 Dec 2005 13:28:53 +0100 (CET) Subject: [py-svn] r20637 - py/dist/py/documentation Message-ID: <20051204122853.0113627B56@code1.codespeak.net> Author: cfbolz Date: Sun Dec 4 13:28:53 2005 New Revision: 20637 Modified: py/dist/py/documentation/conftest.py Log: revert 20634. this was not the real problem with missing docutils Modified: py/dist/py/documentation/conftest.py ============================================================================== --- py/dist/py/documentation/conftest.py (original) +++ py/dist/py/documentation/conftest.py Sun Dec 4 13:28:53 2005 @@ -14,11 +14,6 @@ ) ) -try: - import docutils -except ImportError: - docutils = None - def checkdocutils(): try: import docutils @@ -57,8 +52,6 @@ class ReSTSyntaxTest(py.test.Item): def run(self): - if docutils is None: - py.test.skip("missing docutils") mypath = self.fspath _checkskip(mypath) restcheck(py.path.svnwc(mypath)) @@ -201,7 +194,7 @@ return results def join(self, name): - if not name.endswith('.txt'): + if not name.endswith('.txt'): return super(DocDirectory, self).join(name) p = self.fspath.join(name) if p.check(file=1): From cfbolz at codespeak.net Sun Dec 4 13:42:02 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 4 Dec 2005 13:42:02 +0100 (CET) Subject: [py-svn] r20638 - in py/dist/py: bin misc rest rest/testing Message-ID: <20051204124202.1DB4327B56@code1.codespeak.net> Author: cfbolz Date: Sun Dec 4 13:42:00 2005 New Revision: 20638 Modified: py/dist/py/bin/rst2pdf.py py/dist/py/misc/rest.py py/dist/py/rest/restgraphviz.py py/dist/py/rest/testing/test_restgraphviz.py Log: make the graphviz directive receive the backend as an argument preparing the embedding of latex formulas Modified: py/dist/py/bin/rst2pdf.py ============================================================================== --- py/dist/py/bin/rst2pdf.py (original) +++ py/dist/py/bin/rst2pdf.py Sun Dec 4 13:42:00 2005 @@ -27,7 +27,7 @@ help="print debug output and don't delete files") if __name__ == '__main__': - graphvizdirective = restgraphviz.GraphvizDirective("pdf") + graphvizdirective = restgraphviz.GraphvizDirective("latex") (options, args) = parser.parse_args() if options.configfile is not None: configfile = py.path.local(options.configfile) Modified: py/dist/py/misc/rest.py ============================================================================== --- py/dist/py/misc/rest.py (original) +++ py/dist/py/misc/rest.py Sun Dec 4 13:42:00 2005 @@ -17,7 +17,7 @@ """ from docutils.core import publish_string graphvizdirective = restgraphviz.GraphvizDirective( - "png", source_path.dirpath()) + "html", source_path.dirpath()) kwargs = { 'stylesheet' : stylesheet, 'stylesheet_path': None, Modified: py/dist/py/rest/restgraphviz.py ============================================================================== --- py/dist/py/rest/restgraphviz.py (original) +++ py/dist/py/rest/restgraphviz.py Sun Dec 4 13:42:00 2005 @@ -8,13 +8,16 @@ from docutils.parsers.rst.directives import images from docutils.nodes import whitespace_normalize_name +backend_to_image_format = {"html": "png", "latex": "pdf"} + class GraphvizDirective(object): #XXX this whole class should not be there: #XXX it is only used to work around the inflexibility of docutils: # a directive does not know the path of the file it looks at, nor the # format - def __init__(self, convert_to_format, path=py.path.local()): - self.convert_to_format = convert_to_format + def __init__(self, backend, path=py.path.local()): + self.backend = backend + self.convert_to_format = backend_to_image_format[backend] self.path = path directives.register_directive("graphviz", self.directive_function) Modified: py/dist/py/rest/testing/test_restgraphviz.py ============================================================================== --- py/dist/py/rest/testing/test_restgraphviz.py (original) +++ py/dist/py/rest/testing/test_restgraphviz.py Sun Dec 4 13:42:00 2005 @@ -6,7 +6,7 @@ datadir = py.magic.autopath().dirpath().join("data") def test_graphviz_html(): - graphvizdirective = restgraphviz.GraphvizDirective("png", datadir) + graphvizdirective = restgraphviz.GraphvizDirective("html", datadir) #for reasons that elude me rest.process expects svnwcs??? txt = py.path.svnwc(datadir.join("graphviz.txt")) html = txt.new(ext="html") @@ -20,7 +20,7 @@ png.remove() def test_graphviz_pdf(): - graphvizdirective = restgraphviz.GraphvizDirective("pdf", datadir) + graphvizdirective = restgraphviz.GraphvizDirective("latex", datadir) txt = py.path.local(datadir.join("graphviz.txt")) pdf = txt.new(ext="pdf") dotpdf = datadir.join("example1.pdf") From cfbolz at codespeak.net Tue Dec 6 10:47:41 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 6 Dec 2005 10:47:41 +0100 (CET) Subject: [py-svn] r20736 - in py/dist/py: bin misc rest Message-ID: <20051206094741.34AA327B48@code1.codespeak.net> Author: cfbolz Date: Tue Dec 6 10:47:39 2005 New Revision: 20736 Modified: py/dist/py/bin/rst2pdf.py py/dist/py/misc/rest.py py/dist/py/rest/restgraphviz.py Log: remove one of the hacks of the graphviz directive. I take back some of my curses against docutils (because getting at the path is actually possible) and add a whole bunch of new ones (because doing so is extremely hard). Modified: py/dist/py/bin/rst2pdf.py ============================================================================== --- py/dist/py/bin/rst2pdf.py (original) +++ py/dist/py/bin/rst2pdf.py Tue Dec 6 10:47:39 2005 @@ -31,13 +31,11 @@ (options, args) = parser.parse_args() if options.configfile is not None: configfile = py.path.local(options.configfile) - graphvizdirective.path = configfile.dirpath() process_configfile(options.configfile, options.debug) elif len(args) != 1: parser.error("please supply a file name") else: f = py.path.local(args[0]) - graphvizdirective.path = f.dirpath() process_rest_file(args[0], options.stylesheet, options.debug) Modified: py/dist/py/misc/rest.py ============================================================================== --- py/dist/py/misc/rest.py (original) +++ py/dist/py/misc/rest.py Tue Dec 6 10:47:39 2005 @@ -16,8 +16,7 @@ stylesheet path (to be used if any) """ from docutils.core import publish_string - graphvizdirective = restgraphviz.GraphvizDirective( - "html", source_path.dirpath()) + graphvizdirective = restgraphviz.GraphvizDirective("html") kwargs = { 'stylesheet' : stylesheet, 'stylesheet_path': None, Modified: py/dist/py/rest/restgraphviz.py ============================================================================== --- py/dist/py/rest/restgraphviz.py (original) +++ py/dist/py/rest/restgraphviz.py Tue Dec 6 10:47:39 2005 @@ -15,20 +15,20 @@ #XXX it is only used to work around the inflexibility of docutils: # a directive does not know the path of the file it looks at, nor the # format - def __init__(self, backend, path=py.path.local()): + def __init__(self, backend): self.backend = backend self.convert_to_format = backend_to_image_format[backend] - self.path = path directives.register_directive("graphviz", self.directive_function) - def convert(self, fn): - dot = self.path.join(fn) + def convert(self, fn, path): + path = py.path.local(path).dirpath() + dot = path.join(fn) result = convert_dot(dot, self.convert_to_format) - return result.relto(self.path) + return result.relto(path) def directive_function(self, name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): - newname = self.convert(arguments[0]) + newname = self.convert(arguments[0], state.document.settings._source) text = block_text.replace("graphviz", "image", 1) text = text.replace(arguments[0], newname, 1) return images.image(u'image', [newname], options, content, lineno, From arigo at codespeak.net Tue Dec 6 21:45:29 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 6 Dec 2005 21:45:29 +0100 (CET) Subject: [py-svn] r20815 - in py/dist/py/test: . terminal Message-ID: <20051206204529.0231C27B46@code1.codespeak.net> Author: arigo Date: Tue Dec 6 21:45:27 2005 New Revision: 20815 Modified: py/dist/py/test/defaultconftest.py py/dist/py/test/terminal/terminal.py Log: Added the --tb=long/short/no option. This is a bit messy to implement... The default is 'long', which works as previously; 'short' prints shorter Python-style tracebacks; 'no' suppresses all output at the end of the run except the single summary line (this mode is useful when performing large refactorings, as experienced in PyPy's somepbc-refactoring branch). Modified: py/dist/py/test/defaultconftest.py ============================================================================== --- py/dist/py/test/defaultconftest.py (original) +++ py/dist/py/test/defaultconftest.py Tue Dec 6 21:45:27 2005 @@ -30,6 +30,10 @@ Option('', '--pdb', action="store_true", dest="usepdb", default=False, help="start pdb (the Python debugger) on errors."), + Option('', '--tb', + action="store", dest="tbstyle", default='long', + type="choice", choices=['long', 'short', 'no'], + help="traceback verboseness (long/short/no)"), Option('', '--fulltrace', action="store_true", dest="fulltrace", default=False, help="don't cut any tracebacks (default is to cut)"), Modified: py/dist/py/test/terminal/terminal.py ============================================================================== --- py/dist/py/test/terminal/terminal.py (original) +++ py/dist/py/test/terminal/terminal.py Tue Dec 6 21:45:27 2005 @@ -243,6 +243,8 @@ self.out.line() def failures(self): + if self.config.option.tbstyle == 'no': + return # skip the detailed failure reports altogether l = self.getitemoutcomepairs(Item.Failed) if l: self.out.sep('_') @@ -264,12 +266,16 @@ if not traceback: self.out.line("empty traceback from item %r" % (item,)) return - last = traceback[-1] - first = traceback[0] + handler = getattr(self, 'repr_failure_tb%s' % self.config.option.tbstyle) + handler(item, excinfo, traceback) + + def repr_failure_tblong(self, item, excinfo, traceback): if not self.config.option.nomagic and excinfo.errisinstance(RuntimeError): recursionindex = traceback.recursionindex() else: recursionindex = None + last = traceback[-1] + first = traceback[0] for index, entry in py.builtin.enumerate(traceback): if entry == first: if item: @@ -300,6 +306,45 @@ self.out.sep("!") break + def repr_failure_tbshort(self, item, excinfo, traceback): + # print a Python-style short traceback + if not self.config.option.nomagic and excinfo.errisinstance(RuntimeError): + recursionindex = traceback.recursionindex() + else: + recursionindex = None + last = traceback[-1] + first = traceback[0] + self.out.line() + for index, entry in py.builtin.enumerate(traceback): + code = entry.frame.code + self.out.line(' File "%s", line %d, in %s' % ( + code.raw.co_filename, entry.lineno+1, code.raw.co_name)) + fullsource = entry.frame.code.fullsource + try: + source = [fullsource[entry.lineno].lstrip()] + except IndexError: + source = [] + if entry == last: + if source: + self.repr_source(source, 'E') + self.repr_failure_explanation(excinfo, source) + else: + if source: + self.repr_source(source, ' ') + self.repr_locals(entry) + + # trailing info + if entry == last: + #if item: + # self.repr_failure_info(item, entry) + self.repr_out_err(item) + self.out.sep("_") + else: + if index == recursionindex: + self.out.line("Recursion detected (same locals & position)") + self.out.sep("!") + break + def repr_failure_info(self, item, entry): root = item.fspath modpath = item.getmodpath() From jan at codespeak.net Wed Dec 7 10:26:10 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Wed, 7 Dec 2005 10:26:10 +0100 (CET) Subject: [py-svn] r20821 - py/dist/py/bin Message-ID: <20051207092610.AD70427B45@code1.codespeak.net> Author: jan Date: Wed Dec 7 10:26:09 2005 New Revision: 20821 Modified: py/dist/py/bin/py.rest Log: add missing log function, copied from py/mist/rest.py Modified: py/dist/py/bin/py.rest ============================================================================== --- py/dist/py/bin/py.rest (original) +++ py/dist/py/bin/py.rest Wed Dec 7 10:26:09 2005 @@ -14,6 +14,15 @@ from _findpy import py from py.__.misc import rest + +if hasattr(sys.stdout, 'fileno') and os.isatty(sys.stdout.fileno()): + def log(msg): + print msg +else: + def log(msg): + pass + + if __name__=='__main__': basedir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) sys.path.insert(0, basedir) From mwh at codespeak.net Fri Dec 9 12:00:11 2005 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 9 Dec 2005 12:00:11 +0100 (CET) Subject: [py-svn] r20922 - py/dist/py/documentation Message-ID: <20051209110011.66FC727DCE@code1.codespeak.net> Author: mwh Date: Fri Dec 9 12:00:10 2005 New Revision: 20922 Modified: py/dist/py/documentation/conftest.py Log: avoid spectacular explosion when confronted with a webcal: URL (this is very much a least effort solution, but a full fix requires work). Modified: py/dist/py/documentation/conftest.py ============================================================================== --- py/dist/py/documentation/conftest.py (original) +++ py/dist/py/documentation/conftest.py Fri Dec 9 12:00:10 2005 @@ -127,6 +127,8 @@ if tryfn.startswith('http:') or tryfn.startswith('https'): if option.checkremote: yield urlcheck, tryfn, path, lineno + elif tryfn.startswith('webcal:'): + continue else: i = tryfn.find('#') if i != -1: From cfbolz at codespeak.net Sat Dec 10 00:10:49 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 10 Dec 2005 00:10:49 +0100 (CET) Subject: [py-svn] r20985 - py/dist/py/rest/testing Message-ID: <20051209231049.81BCF27DF6@code1.codespeak.net> Author: cfbolz Date: Sat Dec 10 00:10:48 2005 New Revision: 20985 Modified: py/dist/py/rest/testing/test_restgraphviz.py Log: wua! I didn't run my tests for the last checkin a while ago :-( shame on me. Modified: py/dist/py/rest/testing/test_restgraphviz.py ============================================================================== --- py/dist/py/rest/testing/test_restgraphviz.py (original) +++ py/dist/py/rest/testing/test_restgraphviz.py Sat Dec 10 00:10:48 2005 @@ -6,7 +6,7 @@ datadir = py.magic.autopath().dirpath().join("data") def test_graphviz_html(): - graphvizdirective = restgraphviz.GraphvizDirective("html", datadir) + graphvizdirective = restgraphviz.GraphvizDirective("html") #for reasons that elude me rest.process expects svnwcs??? txt = py.path.svnwc(datadir.join("graphviz.txt")) html = txt.new(ext="html") @@ -20,7 +20,7 @@ png.remove() def test_graphviz_pdf(): - graphvizdirective = restgraphviz.GraphvizDirective("latex", datadir) + graphvizdirective = restgraphviz.GraphvizDirective("latex") txt = py.path.local(datadir.join("graphviz.txt")) pdf = txt.new(ext="pdf") dotpdf = datadir.join("example1.pdf") From cfbolz at codespeak.net Sat Dec 10 00:11:23 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 10 Dec 2005 00:11:23 +0100 (CET) Subject: [py-svn] r20986 - py/dist/py/rest Message-ID: <20051209231123.86A2127DF6@code1.codespeak.net> Author: cfbolz Date: Sat Dec 10 00:11:22 2005 New Revision: 20986 Modified: py/dist/py/rest/latex.py Log: fixes to prevent accidential overwriting of files Modified: py/dist/py/rest/latex.py ============================================================================== --- py/dist/py/rest/latex.py (original) +++ py/dist/py/rest/latex.py Sat Dec 10 00:11:22 2005 @@ -12,7 +12,6 @@ def merge_files(pathlist, pagebreak=False): - pathlist = [py.path.local(path) for path in pathlist] if len(pathlist) == 1: return pathlist[0].read() sectnum = False @@ -78,8 +77,12 @@ py.std.sys.path.insert(0, path) execfile(str(configfile), configfile_dic) pagebreak = configfile_dic.get("pagebreak", False) - content = merge_files(configfile_dic['rest_sources'], pagebreak) + rest_sources = [py.path.local(p) + for p in configfile_dic['rest_sources']] rest = configfile.new(ext='txt') + if len(rest_sources) > 1: + assert rest not in rest_sources + content = merge_files(rest_sources, pagebreak) rest.write(content) sty = configfile.new(ext='sty') content = create_stylesheet(configfile_dic, path) @@ -88,7 +91,8 @@ #cleanup: if not debug: sty.remove() - rest.remove() + if rest not in rest_sources: + rest.remove() old.chdir() def process_rest_file(restfile, stylesheet=None, debug=False): From jan at codespeak.net Tue Dec 13 14:07:52 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Tue, 13 Dec 2005 14:07:52 +0100 (CET) Subject: [py-svn] r21129 - in py/dist/py/rest: . testing Message-ID: <20051213130752.3423A27B68@code1.codespeak.net> Author: jan Date: Tue Dec 13 14:07:50 2005 New Revision: 21129 Added: py/dist/py/rest/rst.py py/dist/py/rest/testing/test_rst.py Log: some stuff to generate docutils ReST files not yet exported Added: py/dist/py/rest/rst.py ============================================================================== --- (empty file) +++ py/dist/py/rest/rst.py Tue Dec 13 14:07:50 2005 @@ -0,0 +1,230 @@ +import py +from py.xml import Namespace, Tag +from py.__.xmlobj.visit import SimpleUnicodeVisitor +from py.__.xmlobj.html import HtmlVisitor + +import textwrap + +def itertext(text): + """ Generator: like string.split, but ''.join(itertext(t)) == t + + >>> list(itertext('word\n second word')) + ['word', '\n', ' ', 'second', ' ', 'word'] + """ + state_word = 'not isspace()' + state_whitespace = '\t\n\x0b\x0c\r' + state_space = ' ' + def compute_state(char): + if char in state_whitespace: + return state_whitespace + if char == ' ': + return state_space + return state_word + + word = '' + state = None + for char in text: + if state is None: + # init + state = compute_state(char) + word = char + continue + + next_state = compute_state(char) + if state != state_whitespace and state == next_state: + word += char + continue + yield word + word = char + + state = next_state + yield word + + +class Out: + """ wrap text like textwarp.wrap, but preseves \n + + all lines are left aligned + arguments to write must be strings or iterable and + return strings of length 1 (chars) + """ + + def __init__(self, width=70): + self.width = width + self.lines = [''] + + def copy(self): + ' like copy, except self.lines = ['']' + return self.__class__(width = self.width) + + def write(self, arg, literal=False): + line = self.lines.pop() + for w in itertext(arg): + if w == '\n': + self.lines.append(line) + line = '' + continue + if literal or self.width is None or \ + line and not line[-1].isspace(): + line += w + continue + if len(line) + len(w) > self.width: + if line != '': + self.lines.append(line) + line = w.lstrip() + continue + line += w + + self.lines.append(line) + return self + + def writeln(self, arg='', literal=False): + self.write(arg, literal) + self.write('\n') + + def write_literal(self, arg): + self.write(arg, literal=True) + + def writeln_literal(self, arg): + self.writeln(arg, literal=True) + + def append(self, out, indent = '', join=''): + keepends = True + self.write_literal(join.join( + [indent + line + for line in out.render().splitlines(keepends)])) + #self.write_literal(indent + line) + + def extend(self, out_list, indent = '', infix = ' ', + join = '', literal = False): + l = list(out_list) + for out in l[:-1]: + self.append(out, indent, join=join) + self.write(infix, literal=literal) + self.append(l[-1], indent, join=join) + + def max_length(self): + return max([len(l) for l in self.lines]) + + def render(self): + return '\n'.join(self.lines) + +class RestTag(Tag): + start_string = '' + end_string = '' + sep = '' + + def __init__(self, *args, **kwargs): + super(RestTag, self).__init__(*args, **kwargs) + self.parse_options(self.attr) + + def parse_options(self, attr): + pass + + def text(self, width = 70): + out = Out(width = width) + self.__rest__(out) + return out.render() + + def __rest__(self, out): + out.write(self.sep) + out.write(self.start_string) + self.write_children(out, self.render_children(out)) + out.write(self.end_string) + out.write(self.sep) + + def write_children(self, out, child_outs): + out.extend(child_outs) + + def render_children(self, out): + outs = [] + for child in self: + child_out = out.copy() + if isinstance(child, RestTag): + child.__rest__(child_out) + else: + child_out.write(child) + outs.append(child_out) + return outs + + +class rest(Namespace): + __tagclass__ = RestTag + __stickname__ = True + + class paragraph(RestTag): + sep = '\n\n' + + class emph(RestTag): + start_string = '*' + end_string = start_string + + class strongemph(RestTag): + start_string = '**' + end_string = start_string + + class inline_literal(RestTag): + start_string = "``" + end_string = "``" + + class interpreted_text(RestTag): + start_string ='`' + end_string = '`' + role = '' + + def parse_options(self, attr): + self.role = getattr(attr, 'role', self.role) + if self.role: + self.start_string = ':%s:%s' % (self.role, self.start_string) + + class explicit_markup(RestTag): + sep = '\n\n' + start_string = '.. ' + + def write_children(self, out, child_outs): + out.extend(child_outs, join = ' ' * len(self.start_string)) + + class title(RestTag): + sep = '\n' + start_string = '#' + end_string = '#' + quotes = """! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~""".split() + + def parse_options(self, attr): + self.start_string = getattr(attr, 'overline', '#') + self.end_string = getattr(attr, 'underline', '#') + + def __rest__(self, out): + child_outs = self.render_children(out) + max_length = max([o.max_length() for o in child_outs]) + out.write(self.sep) + out.writeln_literal(self.start_string * max_length) + out.extend(child_outs) + out.writeln() + out.writeln_literal(self.end_string * max_length) + out.write(self.sep) + + class list_item(RestTag): + sep = '\n\n' + start_string = '* ' + + def parse_options(self, attr): + self.start_string = getattr(attr, 'bullet', '*') + ' ' + if getattr(attr, 'enumerate', False): + self.start_string = '#. ' + + def write_children(self, out, child_outs): + out.extend(child_outs, join = ' ' * len(self.start_string)) + + class literal_block(RestTag): + sep = '\n\n' + start_string = '::\n\n' + indent = ' ' + quote = ' ' + quotes = """! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~""".split() + [' '] + + def parse_options(self, attr): + self.quote = getattr(attr, 'quote', ' ') + + def write_children(self, out, child_outs): + out.extend(child_outs, indent = self.quote) Added: py/dist/py/rest/testing/test_rst.py ============================================================================== --- (empty file) +++ py/dist/py/rest/testing/test_rst.py Tue Dec 13 14:07:50 2005 @@ -0,0 +1,288 @@ +import py +from py.__.rest.rst import rest, Out, itertext, RestTag +from py.__.misc import rest as pyrest + +#temp = py.test.ensuretemp('check_rest') +temp = py.path.local.mkdtemp() + +def check_rest(content, include_dir = None): + if isinstance(content, RestTag): + content = content.text() + content = unicode(content) + print content + tempdir = py.path.local.make_numbered_dir(rootdir=temp) + if include_dir is None: + include_dir = tempdir + #logging + tempdir.ensure('input.txt').write(content) + try: + output = pyrest.convert_rest_html(content, include_dir) + except: + fail_msg = ''' + failed to convert %s to html, probably not valid reStructuredText + see recorded stderr for error message''' + + py.test.fail(fail_msg % tempdir.join('input.txt') + '\n\n' + str(py.code.ExceptionInfo())) + tempdir.ensure('output.html').write(output) + return True + +def render_xml(arg): + return arg.unicode() + +class TestSplit: + + def test_empyt_string(self): + assert list(itertext('')) == [''] + + def test_whitespace(self): + assert list(itertext(' ')) == [' '] + + def test_single_word(self): + assert list(itertext('word')) == ['word'] + + def test_word_with_whitespace(self): + assert list(itertext('word ')) == ['word', ' '] + + def test_two_words(self): + assert list(itertext('first second')) == ['first', ' ', 'second'] + + def test_trailing_newline(self): + assert list(itertext('\nfirst word')) == ['\n', 'first', ' ', 'word'] + def test_newline_and_space_are_seperated(self): + assert list(itertext('\n third_item')) == ['\n', ' ', 'third_item'] + +class TestOut: + + def test_write_nothing(self): + assert Out().write('').render() == '' + + def test_write_returns_self(self): + out = Out() + assert out.write('') is out + assert out.write('') is not Out().write('') + + def test_write_newline(self): + out = Out() + out.write('\n') + assert len(out.lines) == 2 + assert out.render() == '\n' + + def test_write_one_line(self): + text = "'[B]ut assume that I have some other use case' isn't a valid use case. - Fredrik Lundh" + out = Out(width=None) + out.write(text) + assert out.lines == [text] + assert out.render() == text + + def test_write_and_width(self): + text = "This sentence is 36 characters wide." + out = Out(width = 36) + out.write(text) + assert len(out.lines) == 1 + out = Out(width = 35) + out.write(text) + assert len(out.lines) == 2 + + def test_write_and_newline(self): + text = "1234567890\n1234567890" + out = Out(width=30) + out.write(text) + assert len(out.lines) == 2 + assert len(out.lines[0]) == 10 + assert out.render() == text + out.write(text) + assert len(out.lines) == 3 + + def test_write_with_trailing_newline(self): + text = "0123456789\n" + out = Out() + out.write(text) + assert len(out.lines) == 2 + assert out.render() == text + + def test_write_long_word(self): + text = '12345678901234567890' + out = Out(width=19) + out.write(text) + assert len(out.lines) == 1 + assert text == out.render() + out.write('1') + assert len(out.lines) == 1 + out.write(' 2') + assert len(out.lines) == 2 + + def test_long_literal_and_newline(self): + text = '12345678901234567890' + out = Out(width=10) + out.write_literal(text) + assert len(out.lines) == 1 + text += '\n1234567890' + out.write_literal(text) + assert len(out.lines) == 2 + + def test_append(self): + out = Out() + out.write('First line\n') + out.write('Second line') + + root_out = Out() + root_out.write('Root') + root_out.append(out) + + assert len(root_out.lines) == 2 + + def test_max_length(self): + out = Out() + out.write('1234567890') + out.writeln() + out.write('123456789') + assert out.max_length() == 10 + + +class TestRest: + disabled = False + def setup_method(self, method): + self.text = {} + + self.text['paragraph'] = "Paragraphs consist of blocks of left-aligned text with no markup indicating any other body element. Blank lines separate paragraphs from each other and from other body elements. Paragraphs may contain inline markup." + + def test_paragraph(self): + para = rest.paragraph(self.text['paragraph']) + print render_xml(para) + text = para.text() + check_rest(text) + assert text[0] == '\n' + assert text[-1] == '\n' + + def test_emph(self): + emph = rest.emph('strong') + assert emph.text() == '*strong*' + assert check_rest(emph.text()) + + def test_add_whitespace(self): + para = rest.paragraph('Starttext', rest.emph('EMPHASIS'), 'endtext') + assert para.text() == '\n\nStarttext *EMPHASIS* endtext\n\n' + + def test_nested_emph(self): + "Nested Inline Markup not allowed in ReST" + emph = rest.emph('start', rest.emph('middle'), 'end') + check_rest(emph.text()) + assert emph.text() == '*start *middle* end*' + + + def test_strongemph(self): + phrase = 'failure is not an option' + emph = rest.strongemph(phrase) + assert emph.text() == '**' + phrase + '**' + + def test_title(self): + phrase = 'Everything should be built top-down, except the first time.' + title = rest.title(phrase) + expected = title.sep + title.start_string * len(phrase) \ + +'\n' + phrase + '\n' + title.end_string *len(phrase)\ + + '\n' + title.sep + assert title.text() == expected + check_rest(title.text()) + +## def test_subtitle(): +## phrase = 'If your computer speaks English it was probably made in Japan' +## subtitle = rest.subtitle(phrase) +## expected = phrase + '\n' + subtitle.underline * len(phrase) + '\n' +## assert unicode(subtitle) == expected +## assert check_rest(subtitle) + + + def test_paragraph(self): + phrase = "Perhaps if we wrote programs from childhood on, as adults we'd be able to read them." + para = rest.paragraph(phrase) + assert check_rest(para) + + def test_list_item(self): + item_text = 'A short item.' + item = rest.list_item(item_text) + assert item.text() == item.sep + item.start_string + item_text \ + + item.end_string + item.sep + check_rest(item) + + def test_list_item_multiline(self): + item_text = '01234567890 1234567890' + item = rest.list_item(item_text) + assert len(item.text(width=15).splitlines()) == 5 + check_rest(item.text(width=15)) + + def test_list_item_custom_bullet(self): + item_text = '12345678901234567890' + item = rest.list_item(item_text, bullet='+') + assert item.text().strip()[0] == '+' + check_rest(item) + + def test_auto_enumerated_list(self): + item_text = '12345678901234567890' + item = rest.list_item(item_text, enumerate = True) + assert item.text().strip()[0:2] == '#.' + check_rest(item) + + def test_literal_block(self): + block_text = '''\ + This line is only 45 characters wide. + This one is even longer (two spaces). + ''' + + block = rest.literal_block(block_text) + assert block.text()[:6] == '\n\n::\n\n' + out = Out() + block.__rest__(out) + assert out.max_length() == len(block.quote) + max([len(l) for l in block_text.splitlines()]) + check_rest(block) + + block = rest.literal_block(block_text, quote= rest.literal_block.quotes[3]) + assert block.text().strip()[4] == rest.literal_block.quotes[3] + + + def test_interpreted_text(self): + + itext = rest.interpreted_text('just text') + assert itext.text() == '`just text`' + itext_role = rest.interpreted_text('just text with role', role = 'red') + assert itext_role.text().startswith(':red:`just') + + def test_directive(self): + pass + + +# create texts with rest objects + + def test_block_quote(self): + block ="""\ +This is an ordinary paragraph, introducing a block quote. + + "It is my business to know things. That is my trade." + + -- Sherlock Holmes + """ + assert check_rest(block) + + + + def test_quoted_line_block(self): + text = """\ +Take it away, Eric the Orchestra Leader! + + | A one, two, a one two three four + | + | Half a bee, philosophically, + | must, *ipso facto*, half not be. + | But half the bee has got to be, + | *vis a vis* its entity. D'you see? + | + | But can a bee be said to be + | or not to be an entire bee, + | when half the bee is not a bee, + | due to some ancient injury? + | + | Singing... + """ + assert check_rest(text) + +#def test_temdir_output(): +# py.test.skip('tempdir is %s' % temp) From jan at codespeak.net Tue Dec 13 15:29:43 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Tue, 13 Dec 2005 15:29:43 +0100 (CET) Subject: [py-svn] r21131 - py/dist/py/rest/testing Message-ID: <20051213142943.0FF7227B69@code1.codespeak.net> Author: jan Date: Tue Dec 13 15:29:42 2005 New Revision: 21131 Modified: py/dist/py/rest/testing/test_rst.py Log: keep the tempdir Modified: py/dist/py/rest/testing/test_rst.py ============================================================================== --- py/dist/py/rest/testing/test_rst.py (original) +++ py/dist/py/rest/testing/test_rst.py Tue Dec 13 15:29:42 2005 @@ -2,8 +2,8 @@ from py.__.rest.rst import rest, Out, itertext, RestTag from py.__.misc import rest as pyrest -#temp = py.test.ensuretemp('check_rest') -temp = py.path.local.mkdtemp() +temp = py.test.ensuretemp('check_rest') +#temp = py.path.local.mkdtemp() def check_rest(content, include_dir = None): if isinstance(content, RestTag): From cfbolz at codespeak.net Tue Dec 13 15:31:52 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 13 Dec 2005 15:31:52 +0100 (CET) Subject: [py-svn] r21132 - py/dist/py/rest Message-ID: <20051213143152.3EE3027B84@code1.codespeak.net> Author: cfbolz Date: Tue Dec 13 15:31:51 2005 New Revision: 21132 Modified: py/dist/py/rest/rst.py Log: tyop Modified: py/dist/py/rest/rst.py ============================================================================== --- py/dist/py/rest/rst.py (original) +++ py/dist/py/rest/rst.py Tue Dec 13 15:31:51 2005 @@ -42,7 +42,7 @@ class Out: - """ wrap text like textwarp.wrap, but preseves \n + """ wrap text like textwarp.wrap, but preserves \n all lines are left aligned arguments to write must be strings or iterable and From cfbolz at codespeak.net Tue Dec 13 15:53:33 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 13 Dec 2005 15:53:33 +0100 (CET) Subject: [py-svn] r21134 - in py/dist/py/rest: . testing testing/data Message-ID: <20051213145333.237E727DB4@code1.codespeak.net> Author: cfbolz Date: Tue Dec 13 15:53:31 2005 New Revision: 21134 Modified: py/dist/py/rest/latex.py py/dist/py/rest/testing/data/example.rst2pdfconfig py/dist/py/rest/testing/test_rst2pdf.py Log: allow passing of options into rest within a rst2pdfconfig file by using rest_options = [...]. test for this Modified: py/dist/py/rest/latex.py ============================================================================== --- py/dist/py/rest/latex.py (original) +++ py/dist/py/rest/latex.py Tue Dec 13 15:53:31 2005 @@ -87,7 +87,10 @@ sty = configfile.new(ext='sty') content = create_stylesheet(configfile_dic, path) sty.write(content) - process_rest_file(rest, sty.basename, debug) + rest_options = None + if 'rest_options' in configfile_dic: + rest_options = configfile_dic['rest_options'] + process_rest_file(rest, sty.basename, debug, rest_options) #cleanup: if not debug: sty.remove() @@ -95,7 +98,7 @@ rest.remove() old.chdir() -def process_rest_file(restfile, stylesheet=None, debug=False): +def process_rest_file(restfile, stylesheet=None, debug=False, rest_options=None): old = py.path.local() f = py.path.local(restfile) path = f.dirpath() @@ -111,6 +114,8 @@ options.append("--stylesheet=%s" % (sty, )) options.append(f.new(basename=tex)) options = map(str, options) + if rest_options is not None: + options.extend(rest_options) publish_cmdline(writer_name='latex', argv=options) for i in range(2): #XXX sometimes pdflatex has to be run several time Modified: py/dist/py/rest/testing/data/example.rst2pdfconfig ============================================================================== --- py/dist/py/rest/testing/data/example.rst2pdfconfig (original) +++ py/dist/py/rest/testing/data/example.rst2pdfconfig Tue Dec 13 15:53:31 2005 @@ -1,2 +1,3 @@ rest_sources = ['part1.txt', 'part2.txt'] +rest_options = ["--generator"] # easy to test Modified: py/dist/py/rest/testing/test_rst2pdf.py ============================================================================== --- py/dist/py/rest/testing/test_rst2pdf.py (original) +++ py/dist/py/rest/testing/test_rst2pdf.py Tue Dec 13 15:53:31 2005 @@ -13,6 +13,14 @@ def test_process_configfile(): config = data.join("example.rst2pdfconfig") pdf = config.new(ext="pdf") - process_configfile(config) + tex = data.join('example.tex') + process_configfile(config, debug=True) assert pdf.check() + assert tex.check() + texcontent = tex.read() + assert "Generated by" in texcontent + assert "Docutils" in texcontent + process_configfile(config, debug=False) + assert pdf.check() + assert not tex.check() pdf.remove() From cfbolz at codespeak.net Tue Dec 13 16:26:52 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 13 Dec 2005 16:26:52 +0100 (CET) Subject: [py-svn] r21135 - py/dist/py/rest/testing/data Message-ID: <20051213152652.DC40327DBB@code1.codespeak.net> Author: cfbolz Date: Tue Dec 13 16:26:51 2005 New Revision: 21135 Modified: py/dist/py/rest/testing/data/example.rst2pdfconfig py/dist/py/rest/testing/data/part1.txt py/dist/py/rest/testing/data/part2.txt Log: allow specification of toc depth Modified: py/dist/py/rest/testing/data/example.rst2pdfconfig ============================================================================== --- py/dist/py/rest/testing/data/example.rst2pdfconfig (original) +++ py/dist/py/rest/testing/data/example.rst2pdfconfig Tue Dec 13 16:26:51 2005 @@ -1,3 +1,5 @@ rest_sources = ['part1.txt', 'part2.txt'] -rest_options = ["--generator"] # easy to test +rest_options = ["--use-latex-toc", "--generator"] # generator is easy to test + +toc_depth = 1 Modified: py/dist/py/rest/testing/data/part1.txt ============================================================================== --- py/dist/py/rest/testing/data/part1.txt (original) +++ py/dist/py/rest/testing/data/part1.txt Tue Dec 13 16:26:51 2005 @@ -1,7 +1,19 @@ +.. contents:: + This is the first part of the example rest file =============================================== -.. sectnum:: -some content. some more. the end. +some content. + +fancy subsection heading +------------------------- + +some more content. + +really stupid document +------------------------ + +we are all thankful that it ends now. + Modified: py/dist/py/rest/testing/data/part2.txt ============================================================================== --- py/dist/py/rest/testing/data/part2.txt (original) +++ py/dist/py/rest/testing/data/part2.txt Tue Dec 13 16:26:51 2005 @@ -1,7 +1,7 @@ This is the second part of the test file ========================================= -.. sectnum:: +.. contents:: the text in it is not much more interesting. From cfbolz at codespeak.net Tue Dec 13 16:34:26 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 13 Dec 2005 16:34:26 +0100 (CET) Subject: [py-svn] r21136 - py/dist/py/rest Message-ID: <20051213153426.254A527DB7@code1.codespeak.net> Author: cfbolz Date: Tue Dec 13 16:34:24 2005 New Revision: 21136 Modified: py/dist/py/rest/latex.py py/dist/py/rest/rest.sty.template Log: damn, I checked in the tests only, not the functionality Modified: py/dist/py/rest/latex.py ============================================================================== --- py/dist/py/rest/latex.py (original) +++ py/dist/py/rest/latex.py Tue Dec 13 16:34:24 2005 @@ -62,6 +62,12 @@ fill_in["specified_font"] = "%" fill_in["sans_serif"] = "%" fill_in["font_package"] = "" + if 'toc_depth' in options: + fill_in["have_tocdepth"] = "" + fill_in["toc_depth"] = options["toc_depth"] + else: + fill_in["have_tocdepth"] = "%" + fill_in["have_tocdepth"] = "" fill_in["heading"] = options.get("heading", "") template_file = path.join("rest.sty.template") if not template_file.check(): Modified: py/dist/py/rest/rest.sty.template ============================================================================== --- py/dist/py/rest/rest.sty.template (original) +++ py/dist/py/rest/rest.sty.template Tue Dec 13 16:34:24 2005 @@ -4,6 +4,8 @@ \usepackage[pdftex]{graphicx} \usepackage{epstopdf} +%(have_tocdepth)s\setcounter{tocdepth}{%(toc_depth)s} + %(sans_serif)s\renewcommand{\familydefault}{\sfdefault} %(specified_font)s\usepackage{%(font_package)s} \lhead{ From cfbolz at codespeak.net Tue Dec 13 16:36:07 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 13 Dec 2005 16:36:07 +0100 (CET) Subject: [py-svn] r21137 - py/dist/py/rest Message-ID: <20051213153607.B147727DB7@code1.codespeak.net> Author: cfbolz Date: Tue Dec 13 16:36:06 2005 New Revision: 21137 Modified: py/dist/py/rest/latex.py Log: typo Modified: py/dist/py/rest/latex.py ============================================================================== --- py/dist/py/rest/latex.py (original) +++ py/dist/py/rest/latex.py Tue Dec 13 16:36:06 2005 @@ -67,7 +67,7 @@ fill_in["toc_depth"] = options["toc_depth"] else: fill_in["have_tocdepth"] = "%" - fill_in["have_tocdepth"] = "" + fill_in["toc_depth"] = "" fill_in["heading"] = options.get("heading", "") template_file = path.join("rest.sty.template") if not template_file.check(): From cfbolz at codespeak.net Tue Dec 13 16:56:17 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 13 Dec 2005 16:56:17 +0100 (CET) Subject: [py-svn] r21138 - in py/dist/py/rest/testing: . data Message-ID: <20051213155617.9745227B84@code1.codespeak.net> Author: cfbolz Date: Tue Dec 13 16:56:16 2005 New Revision: 21138 Added: py/dist/py/rest/testing/data/tocdepth.rst2pdfconfig Modified: py/dist/py/rest/testing/data/example.rst2pdfconfig py/dist/py/rest/testing/test_rst2pdf.py Log: add fallback test that test all rst2pdfconfig and txt files (only for the nonexistance of crashes) Modified: py/dist/py/rest/testing/data/example.rst2pdfconfig ============================================================================== --- py/dist/py/rest/testing/data/example.rst2pdfconfig (original) +++ py/dist/py/rest/testing/data/example.rst2pdfconfig Tue Dec 13 16:56:16 2005 @@ -1,5 +1,3 @@ rest_sources = ['part1.txt', 'part2.txt'] rest_options = ["--use-latex-toc", "--generator"] # generator is easy to test - -toc_depth = 1 Added: py/dist/py/rest/testing/data/tocdepth.rst2pdfconfig ============================================================================== --- (empty file) +++ py/dist/py/rest/testing/data/tocdepth.rst2pdfconfig Tue Dec 13 16:56:16 2005 @@ -0,0 +1,5 @@ +rest_sources = ['part1.txt', 'part2.txt'] + +rest_options = ["--use-latex-toc", "--generator"] # generator is easy to test + +toc_depth = 1 Modified: py/dist/py/rest/testing/test_rst2pdf.py ============================================================================== --- py/dist/py/rest/testing/test_rst2pdf.py (original) +++ py/dist/py/rest/testing/test_rst2pdf.py Tue Dec 13 16:56:16 2005 @@ -24,3 +24,12 @@ assert pdf.check() assert not tex.check() pdf.remove() + +def test_process_all(): + # fallback test: only checks that no exception is raised + def rec(p): + return p.check(dotfile=0) + for x in data.visit("*.txt", rec=rec): + yield process_rest_file, x + for x in data.visit("*.rst2pdfconfig", rec=rec): + yield process_configfile, x From cfbolz at codespeak.net Tue Dec 13 19:42:21 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 13 Dec 2005 19:42:21 +0100 (CET) Subject: [py-svn] r21142 - in py/dist/py: bin misc rest rest/testing Message-ID: <20051213184221.A119A27B69@code1.codespeak.net> Author: cfbolz Date: Tue Dec 13 19:42:18 2005 New Revision: 21142 Added: py/dist/py/rest/directive.py - copied, changed from r21130, py/dist/py/rest/restgraphviz.py Removed: py/dist/py/rest/restgraphviz.py Modified: py/dist/py/bin/rst2pdf.py py/dist/py/misc/rest.py py/dist/py/rest/testing/test_restgraphviz.py Log: rename restgraphviz to directive, since I want to use it for more than the graphviz directive. Modified: py/dist/py/bin/rst2pdf.py ============================================================================== --- py/dist/py/bin/rst2pdf.py (original) +++ py/dist/py/bin/rst2pdf.py Tue Dec 13 19:42:18 2005 @@ -12,7 +12,7 @@ from _findpy import py -from py.__.rest import restgraphviz +from py.__.rest import directive from py.__.rest.latex import process_rest_file, process_configfile optparse = py.compat.optparse @@ -27,7 +27,7 @@ help="print debug output and don't delete files") if __name__ == '__main__': - graphvizdirective = restgraphviz.GraphvizDirective("latex") + directive.BackendStore("latex") (options, args) = parser.parse_args() if options.configfile is not None: configfile = py.path.local(options.configfile) Modified: py/dist/py/misc/rest.py ============================================================================== --- py/dist/py/misc/rest.py (original) +++ py/dist/py/misc/rest.py Tue Dec 13 19:42:18 2005 @@ -9,14 +9,14 @@ pass def convert_rest_html(source, source_path, stylesheet=None, encoding='latin1'): - from py.__.rest import restgraphviz + from py.__.rest import directive """ return html latin1-encoded document for the given input. source a ReST-string sourcepath where to look for includes (basically) stylesheet path (to be used if any) """ from docutils.core import publish_string - graphvizdirective = restgraphviz.GraphvizDirective("html") + directive.BackendStore("html") kwargs = { 'stylesheet' : stylesheet, 'stylesheet_path': None, Copied: py/dist/py/rest/directive.py (from r21130, py/dist/py/rest/restgraphviz.py) ============================================================================== --- py/dist/py/rest/restgraphviz.py (original) +++ py/dist/py/rest/directive.py Tue Dec 13 19:42:18 2005 @@ -10,7 +10,7 @@ backend_to_image_format = {"html": "png", "latex": "pdf"} -class GraphvizDirective(object): +class BackendStore(object): #XXX this whole class should not be there: #XXX it is only used to work around the inflexibility of docutils: # a directive does not know the path of the file it looks at, nor the @@ -18,7 +18,7 @@ def __init__(self, backend): self.backend = backend self.convert_to_format = backend_to_image_format[backend] - directives.register_directive("graphviz", self.directive_function) + directives.register_directive("graphviz", self.graphviz_directive) def convert(self, fn, path): path = py.path.local(path).dirpath() @@ -26,18 +26,20 @@ result = convert_dot(dot, self.convert_to_format) return result.relto(path) - def directive_function(self, name, arguments, options, content, lineno, - content_offset, block_text, state, state_machine): + def graphviz_directive(self, name, arguments, options, content, + lineno, content_offset, block_text, state, + state_machine): newname = self.convert(arguments[0], state.document.settings._source) text = block_text.replace("graphviz", "image", 1) text = text.replace(arguments[0], newname, 1) return images.image(u'image', [newname], options, content, lineno, content_offset, text, state, state_machine) - directive_function.arguments = (1, 0, 1) - directive_function.options = {'alt': directives.unchanged, + graphviz_directive.arguments = (1, 0, 1) + graphviz_directive.options = {'alt': directives.unchanged, 'height': directives.nonnegative_int, 'width': directives.nonnegative_int, 'scale': directives.nonnegative_int, 'align': images.align, 'target': directives.unchanged_required, 'class': directives.class_option} + Deleted: /py/dist/py/rest/restgraphviz.py ============================================================================== --- /py/dist/py/rest/restgraphviz.py Tue Dec 13 19:42:18 2005 +++ (empty file) @@ -1,43 +0,0 @@ -import py - -from py.__.rest.convert import convert_dot - -import sys -from docutils import nodes, utils -from docutils.parsers.rst import directives, states -from docutils.parsers.rst.directives import images -from docutils.nodes import whitespace_normalize_name - -backend_to_image_format = {"html": "png", "latex": "pdf"} - -class GraphvizDirective(object): - #XXX this whole class should not be there: - #XXX it is only used to work around the inflexibility of docutils: - # a directive does not know the path of the file it looks at, nor the - # format - def __init__(self, backend): - self.backend = backend - self.convert_to_format = backend_to_image_format[backend] - directives.register_directive("graphviz", self.directive_function) - - def convert(self, fn, path): - path = py.path.local(path).dirpath() - dot = path.join(fn) - result = convert_dot(dot, self.convert_to_format) - return result.relto(path) - - def directive_function(self, name, arguments, options, content, lineno, - content_offset, block_text, state, state_machine): - newname = self.convert(arguments[0], state.document.settings._source) - text = block_text.replace("graphviz", "image", 1) - text = text.replace(arguments[0], newname, 1) - return images.image(u'image', [newname], options, content, lineno, - content_offset, text, state, state_machine) - directive_function.arguments = (1, 0, 1) - directive_function.options = {'alt': directives.unchanged, - 'height': directives.nonnegative_int, - 'width': directives.nonnegative_int, - 'scale': directives.nonnegative_int, - 'align': images.align, - 'target': directives.unchanged_required, - 'class': directives.class_option} Modified: py/dist/py/rest/testing/test_restgraphviz.py ============================================================================== --- py/dist/py/rest/testing/test_restgraphviz.py (original) +++ py/dist/py/rest/testing/test_restgraphviz.py Tue Dec 13 19:42:18 2005 @@ -1,12 +1,12 @@ import py -from py.__.rest import restgraphviz +from py.__.rest import directive from py.__.misc import rest from py.__.rest.latex import process_rest_file datadir = py.magic.autopath().dirpath().join("data") def test_graphviz_html(): - graphvizdirective = restgraphviz.GraphvizDirective("html") + directive.BackendStore("html") #for reasons that elude me rest.process expects svnwcs??? txt = py.path.svnwc(datadir.join("graphviz.txt")) html = txt.new(ext="html") @@ -20,7 +20,7 @@ png.remove() def test_graphviz_pdf(): - graphvizdirective = restgraphviz.GraphvizDirective("latex") + directive.BackendStore("latex") txt = py.path.local(datadir.join("graphviz.txt")) pdf = txt.new(ext="pdf") dotpdf = datadir.join("example1.pdf") From cfbolz at codespeak.net Tue Dec 13 21:57:27 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 13 Dec 2005 21:57:27 +0100 (CET) Subject: [py-svn] r21145 - in py/dist/py/rest: . testing Message-ID: <20051213205727.E09D527B69@code1.codespeak.net> Author: cfbolz Date: Tue Dec 13 21:57:26 2005 New Revision: 21145 Modified: py/dist/py/rest/convert.py py/dist/py/rest/testing/test_convert.py Log: added code that converts a piece of latex (should be a formula) to a png. The majority of the code was written by jan, thanks a lot! you saved me from doing annoying latex/dvips/gs stuff. Modified: py/dist/py/rest/convert.py ============================================================================== --- py/dist/py/rest/convert.py (original) +++ py/dist/py/rest/convert.py Tue Dec 13 21:57:26 2005 @@ -33,6 +33,12 @@ # XXX write a pure python version py.process.cmdexec("epstopdf %s" % eps) +def dvi2eps(dvi, dest=None): + if dest is None: + dest = eps.new(ext=".eps") + command = 'dvips -q -E -n 1 -D 600 -p 1 -o %s %s' % (dest, dvi) + py.process.cmdexec(command) + def convert_dot(fn, new_extension): result = fn.new(ext=new_extension) print result @@ -54,3 +60,93 @@ eps.remove() return result + +class latexformula2png(object): + def __init__(self, formula, dest, temp=None): + self.formula = formula + try: + import Image + self.Image = Image + self.scale = 2 # create a larger image + self.upscale = 5 # create the image upscale times larger, then scale it down + except ImportError: + self.scale = 2 + self.upscale = 5 + self.Image = None + self.output_format = ('pngmono', 'pnggray', 'pngalpha')[2] + if temp is None: + temp = py.test.ensuretemp("latexformula") + self.temp = temp + self.latex = self.temp.join('formula.tex') + self.dvi = self.temp.join('formula.dvi') + self.eps = self.temp.join('formula.eps') + self.png = self.temp.join('formula.png') + self.saveas(dest) + + def saveas(self, dest): + self.gen_latex() + self.gen_dvi() + dvi2eps(self.dvi, self.eps) + self.gen_png() + self.scale_image() + self.png.copy(dest) + + def gen_latex(self): + self.latex.write (""" + \\documentclass{article} + \\pagestyle{empty} + \\begin{document} + + %s + \\pagebreak + + \\end{document} + """ % (self.formula)) + + def gen_dvi(self): + origdir = py.path.local() + self.temp.chdir() + py.process.cmdexec('latex %s' % (self.latex)) + origdir.chdir() + + def gen_png(self): + tempdir = py.path.local.mkdtemp() + + re_bbox = py.std.re.compile('%%BoundingBox:\s*(\d+) (\d+) (\d+) (\d+)') + eps = self.eps.read() + x1, y1, x2, y2 = [int(i) for i in re_bbox.search(eps).groups()] + X = x2 - x1 + 2 + Y = y2 - y1 + 2 + mx = -x1 + my = -y1 + ps = self.temp.join('temp.ps') + source = self.eps + ps.write(""" + 1 1 1 setrgbcolor + newpath + -1 -1 moveto + %(X)d -1 lineto + %(X)d %(Y)d lineto + -1 %(Y)d lineto + closepath + fill + %(mx)d %(my)d translate + 0 0 0 setrgbcolor + (%(source)s) run + + """ % locals()) + + sx = int((x2 - x1) * self.scale * self.upscale) + sy = int((y2 - y1) * self.scale * self.upscale) + res = 72 * self.scale * self.upscale + command = 'gs -q -g%dx%d -r%dx%d -sDEVICE=%s -sOutputFile=%s -dNOPAUSE -dBATCH %s' % (sx, sy, res, res, self.output_format, self.png, ps) + py.process.cmdexec(command) + + def scale_image(self): + if self.Image is None: + return + image = self.Image.open(str(self.png)) + image.resize((image.size[0] / self.upscale, + image.size[1] / self.upscale), + self.Image.ANTIALIAS).save(str(self.png)) + Modified: py/dist/py/rest/testing/test_convert.py ============================================================================== --- py/dist/py/rest/testing/test_convert.py (original) +++ py/dist/py/rest/testing/test_convert.py Tue Dec 13 21:57:26 2005 @@ -1,5 +1,5 @@ import py -from py.__.rest.convert import convert_dot +from py.__.rest.convert import convert_dot, latexformula2png def is_on_path(name): try: @@ -12,8 +12,8 @@ datadir = py.magic.autopath().dirpath().join("data") def setup_module(mod): - if not is_on_path("gs") or not is_on_path("dot"): - py.test.skip("ghostscript and graphviz needed") + if not is_on_path("gs") or not is_on_path("dot") or not is_on_path("latex"): + py.test.skip("ghostscript, graphviz and latex needed") def test_convert_dot(): # XXX not really clear that the result is valid pdf/eps @@ -27,3 +27,11 @@ assert eps.check() eps.remove() +def test_latexformula(): + png = datadir.join("test.png") + formula = r'$$Entropy(T) = - \sum^{m}_{j=1} \frac{|T_j|}{|T|} \log \frac{|T_j|}{|T|}$$' + #does not crash + latexformula2png(formula, png) + assert png.check() + py.process.cmdexec("qiv %s" % png) + png.remove() From cfbolz at codespeak.net Tue Dec 13 23:48:13 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 13 Dec 2005 23:48:13 +0100 (CET) Subject: [py-svn] r21148 - py/dist/py/rest/testing Message-ID: <20051213224813.0A26827B69@code1.codespeak.net> Author: cfbolz Date: Tue Dec 13 23:48:11 2005 New Revision: 21148 Added: py/dist/py/rest/testing/test_directive.py - copied unchanged from r21142, py/dist/py/rest/testing/test_restgraphviz.py Removed: py/dist/py/rest/testing/test_restgraphviz.py Log: rename the test file too Deleted: /py/dist/py/rest/testing/test_restgraphviz.py ============================================================================== --- /py/dist/py/rest/testing/test_restgraphviz.py Tue Dec 13 23:48:11 2005 +++ (empty file) @@ -1,32 +0,0 @@ -import py -from py.__.rest import directive -from py.__.misc import rest -from py.__.rest.latex import process_rest_file - -datadir = py.magic.autopath().dirpath().join("data") - -def test_graphviz_html(): - directive.BackendStore("html") - #for reasons that elude me rest.process expects svnwcs??? - txt = py.path.svnwc(datadir.join("graphviz.txt")) - html = txt.new(ext="html") - png = datadir.join("example1.png") - rest.process(txt) - assert html.check() - assert png.check() - html_content = html.read() - assert png.basename in html_content - html.remove() - png.remove() - -def test_graphviz_pdf(): - directive.BackendStore("latex") - txt = py.path.local(datadir.join("graphviz.txt")) - pdf = txt.new(ext="pdf") - dotpdf = datadir.join("example1.pdf") - process_rest_file(txt) - assert pdf.check() - assert dotpdf.check() - pdf.remove() - dotpdf.remove() - From cfbolz at codespeak.net Wed Dec 14 00:50:50 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 14 Dec 2005 00:50:50 +0100 (CET) Subject: [py-svn] r21149 - in py/dist/py/rest: . testing testing/data Message-ID: <20051213235050.441E527B66@code1.codespeak.net> Author: cfbolz Date: Wed Dec 14 00:50:48 2005 New Revision: 21149 Added: py/dist/py/rest/testing/data/formula.txt Modified: py/dist/py/rest/directive.py py/dist/py/rest/testing/test_convert.py Log: add a latexformula text role for rest. now :latexformula:`$x^2$` produces the formula, in latex if the backend is latex and as an image if the backend is html. Add testfile and remove accidentially checked line. Modified: py/dist/py/rest/directive.py ============================================================================== --- py/dist/py/rest/directive.py (original) +++ py/dist/py/rest/directive.py Wed Dec 14 00:50:48 2005 @@ -1,12 +1,11 @@ import py -from py.__.rest.convert import convert_dot +from py.__.rest.convert import convert_dot, latexformula2png import sys from docutils import nodes, utils -from docutils.parsers.rst import directives, states +from docutils.parsers.rst import directives, states, roles from docutils.parsers.rst.directives import images -from docutils.nodes import whitespace_normalize_name backend_to_image_format = {"html": "png", "latex": "pdf"} @@ -19,6 +18,7 @@ self.backend = backend self.convert_to_format = backend_to_image_format[backend] directives.register_directive("graphviz", self.graphviz_directive) + roles.register_canonical_role("latexformula", self.latexformula_role) def convert(self, fn, path): path = py.path.local(path).dirpath() @@ -43,3 +43,27 @@ 'target': directives.unchanged_required, 'class': directives.class_option} + def latexformula_role(self, name, rawtext, text, lineno, inliner, + options={}, content=[]): + if self.backend == 'latex': + options['format'] = 'latex' + return roles.raw_role(name, rawtext, text, lineno, inliner, + options, content) + else: + # XXX: make the place of the image directory configurable + sourcedir = py.path.local(inliner.document.settings._source).dirpath() + imagedir = sourcedir.join("img") + if not imagedir.check(): + imagedir.mkdir() + # create halfway senseful imagename: + # use hash of formula + alphanumeric characters of it + # could + imagename = "%s_%s.png" % ( + hash(text), "".join([c for c in text if c.isalnum()])) + image = imagedir.join(imagename) + latexformula2png(text, image) + imagenode = nodes.image(image.relto(sourcedir), uri=image.relto(sourcedir)) + return [imagenode], [] + latexformula_role.content = True + latexformula_role.options = {} + Added: py/dist/py/rest/testing/data/formula.txt ============================================================================== --- (empty file) +++ py/dist/py/rest/testing/data/formula.txt Wed Dec 14 00:50:48 2005 @@ -0,0 +1,8 @@ +Euklids proof about the infinitude of primes +============================================ + +If there were only a finite amount of primes then there would be a largest +prime :latexformula:`p`. However, the number :latexformula:`p! + 1` is not +divisible by any number :latexformula:`1, ..., p`. Therefore, a prime dividing +:latexformula:`p! + 1` has to be bigger than :latexformula:`p`. Therefore there +is an infinite number of primes. Modified: py/dist/py/rest/testing/test_convert.py ============================================================================== --- py/dist/py/rest/testing/test_convert.py (original) +++ py/dist/py/rest/testing/test_convert.py Wed Dec 14 00:50:48 2005 @@ -33,5 +33,4 @@ #does not crash latexformula2png(formula, png) assert png.check() - py.process.cmdexec("qiv %s" % png) png.remove() From jan at codespeak.net Thu Dec 15 12:48:03 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Thu, 15 Dec 2005 12:48:03 +0100 (CET) Subject: [py-svn] r21168 - py/dist/py/rest Message-ID: <20051215114803.1BEE627B62@code1.codespeak.net> Author: jan Date: Thu Dec 15 12:48:02 2005 New Revision: 21168 Modified: py/dist/py/rest/latex.py Log: compile latex files enough times to resolve all references Modified: py/dist/py/rest/latex.py ============================================================================== --- py/dist/py/rest/latex.py (original) +++ py/dist/py/rest/latex.py Thu Dec 15 12:48:02 2005 @@ -123,12 +123,14 @@ if rest_options is not None: options.extend(rest_options) publish_cmdline(writer_name='latex', argv=options) - for i in range(2): - #XXX sometimes pdflatex has to be run several time - #find a cleaner way to do it + + while True: latexoutput = py.process.cmdexec("pdflatex %s" % (tex, )) if debug: print latexoutput + if py.std.re.search("LaTeX Warning:.*Rerun", latexoutput) is None: + break + old.chdir() #cleanup: if not debug: From jan at codespeak.net Thu Dec 15 15:57:44 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Thu, 15 Dec 2005 15:57:44 +0100 (CET) Subject: [py-svn] r21180 - in py/dist/py/rest: . testing Message-ID: <20051215145744.7311627B62@code1.codespeak.net> Author: jan Date: Thu Dec 15 15:57:42 2005 New Revision: 21180 Modified: py/dist/py/rest/rst.py py/dist/py/rest/testing/test_rst.py Log: more ReST tags Modified: py/dist/py/rest/rst.py ============================================================================== --- py/dist/py/rest/rst.py (original) +++ py/dist/py/rest/rst.py Thu Dec 15 15:57:42 2005 @@ -1,9 +1,8 @@ import py from py.xml import Namespace, Tag -from py.__.xmlobj.visit import SimpleUnicodeVisitor -from py.__.xmlobj.html import HtmlVisitor +#from py.__.xmlobj.visit import SimpleUnicodeVisitor +#from py.__.xmlobj.html import HtmlVisitor -import textwrap def itertext(text): """ Generator: like string.split, but ''.join(itertext(t)) == t @@ -68,13 +67,15 @@ line and not line[-1].isspace(): line += w continue + if not line and w == ' '*len(w): + continue if len(line) + len(w) > self.width: if line != '': self.lines.append(line) line = w.lstrip() continue line += w - + self.lines.append(line) return self @@ -93,11 +94,11 @@ self.write_literal(join.join( [indent + line for line in out.render().splitlines(keepends)])) - #self.write_literal(indent + line) def extend(self, out_list, indent = '', infix = ' ', join = '', literal = False): l = list(out_list) + if not l: return for out in l[:-1]: self.append(out, indent, join=join) self.write(infix, literal=literal) @@ -109,10 +110,12 @@ def render(self): return '\n'.join(self.lines) + class RestTag(Tag): start_string = '' end_string = '' sep = '' + write_literal = False def __init__(self, *args, **kwargs): super(RestTag, self).__init__(*args, **kwargs) @@ -143,18 +146,47 @@ if isinstance(child, RestTag): child.__rest__(child_out) else: - child_out.write(child) + child_out.write(child, literal = self.write_literal) outs.append(child_out) return outs +class DirectiveMetaclass(type): + def __getattr__(self, name): + if name[:1] == '_': + raise AttributeError(name) + # convert '_' to '-' + name = name.replace('_','-') + classattr = {'name': name} + cls = type(name, (self.__tagclass__,), classattr) + setattr(self, name, cls) + return cls + +class UniversalDirective(RestTag): + sep = '\n\n' + start_string = '.. ' + + def write_children(self, out, child_outs): + out.write(self.name) + out.write(':: ') + out.writeln(child_outs[0].render()) + keys = [attr for attr in dir(self.attr) if not attr.startswith('__')] + keys.sort() + for key in keys: + value = str(getattr(self.attr, key)) + out.write_literal(' ' * len(self.start_string) +':%s: %s\n' \ + % (key,value)) + + if len(child_outs) > 1: + # directive block + out.writeln(' ' * len(self.start_string)) + out.extend(child_outs[1:], indent = ' ' * len(self.start_string)) + + class rest(Namespace): __tagclass__ = RestTag __stickname__ = True - class paragraph(RestTag): - sep = '\n\n' - class emph(RestTag): start_string = '*' end_string = start_string @@ -177,6 +209,9 @@ if self.role: self.start_string = ':%s:%s' % (self.role, self.start_string) + class paragraph(RestTag): + sep = '\n\n' + class explicit_markup(RestTag): sep = '\n\n' start_string = '.. ' @@ -210,7 +245,7 @@ def parse_options(self, attr): self.start_string = getattr(attr, 'bullet', '*') + ' ' - if getattr(attr, 'enumerate', False): + if getattr(attr, 'auto_enumerate', False): self.start_string = '#. ' def write_children(self, out, child_outs): @@ -222,9 +257,16 @@ indent = ' ' quote = ' ' quotes = """! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~""".split() + [' '] + write_literal = True def parse_options(self, attr): self.quote = getattr(attr, 'quote', ' ') def write_children(self, out, child_outs): - out.extend(child_outs, indent = self.quote) + out.extend(child_outs, indent = self.quote, infix ='', literal = True) + + unidirective = UniversalDirective + + class directive: + __metaclass__ = DirectiveMetaclass + __tagclass__ = UniversalDirective Modified: py/dist/py/rest/testing/test_rst.py ============================================================================== --- py/dist/py/rest/testing/test_rst.py (original) +++ py/dist/py/rest/testing/test_rst.py Thu Dec 15 15:57:42 2005 @@ -6,6 +6,7 @@ #temp = py.path.local.mkdtemp() def check_rest(content, include_dir = None): + " try to convert content to html " if isinstance(content, RestTag): content = content.text() content = unicode(content) @@ -27,8 +28,17 @@ return True def render_xml(arg): + 'try to generate a xml representation of arg' return arg.unicode() +def strip_lines(line_list): + 'filter line_list and remove trailing whitespaces' + return [line.rstrip() for line in line_list if line.strip()] + +def print_lines(line_list): + 'pretty print line_list' + py.std.pprint.pprint(strip_lines(line_list)) + class TestSplit: def test_empyt_string(self): @@ -131,6 +141,12 @@ assert len(root_out.lines) == 2 + def test_extend_empty_list(self): + out = Out() + text = out.render() + out.extend([]) + assert text == out.render() + def test_max_length(self): out = Out() out.write('1234567890') @@ -144,7 +160,10 @@ def setup_method(self, method): self.text = {} - self.text['paragraph'] = "Paragraphs consist of blocks of left-aligned text with no markup indicating any other body element. Blank lines separate paragraphs from each other and from other body elements. Paragraphs may contain inline markup." + self.text['paragraph'] = "Paragraphs consist of blocks of " + "left-aligned text with no markup indicating any other body " + "element. Blank lines separate paragraphs from each other and " + "from other body elements. Paragraphs may contain inline markup." def test_paragraph(self): para = rest.paragraph(self.text['paragraph']) @@ -154,22 +173,29 @@ assert text[0] == '\n' assert text[-1] == '\n' + def test_paragraph_with_whitespaces(self): + phrase = "Perhaps if we wrote programs from " + "childhood on, as adults " + " we'd be able to read them." + para = rest.paragraph(phrase) + check_rest(para) + assert True not in [line.startswith(' ') for line in para.text().splitlines()] + def test_emph(self): emph = rest.emph('strong') assert emph.text() == '*strong*' assert check_rest(emph.text()) - def test_add_whitespace(self): + def test_paragraph_adds_whitespace(self): para = rest.paragraph('Starttext', rest.emph('EMPHASIS'), 'endtext') - assert para.text() == '\n\nStarttext *EMPHASIS* endtext\n\n' + assert para.text() == para.sep +'Starttext *EMPHASIS* endtext'+ para.sep def test_nested_emph(self): - "Nested Inline Markup not allowed in ReST" + "Nested Inline Markup not allowed in ReST, don't try at home ;-)" emph = rest.emph('start', rest.emph('middle'), 'end') check_rest(emph.text()) assert emph.text() == '*start *middle* end*' - def test_strongemph(self): phrase = 'failure is not an option' emph = rest.strongemph(phrase) @@ -192,10 +218,6 @@ ## assert check_rest(subtitle) - def test_paragraph(self): - phrase = "Perhaps if we wrote programs from childhood on, as adults we'd be able to read them." - para = rest.paragraph(phrase) - assert check_rest(para) def test_list_item(self): item_text = 'A short item.' @@ -207,8 +229,12 @@ def test_list_item_multiline(self): item_text = '01234567890 1234567890' item = rest.list_item(item_text) - assert len(item.text(width=15).splitlines()) == 5 - check_rest(item.text(width=15)) + text = item.text(width = 15) + assert len([l for l in text.splitlines() if l.strip()]) == 2 + check_rest(text) + out = Out(width = 15) + item.__rest__(out) + assert out.max_length() <= 15 def test_list_item_custom_bullet(self): item_text = '12345678901234567890' @@ -218,26 +244,27 @@ def test_auto_enumerated_list(self): item_text = '12345678901234567890' - item = rest.list_item(item_text, enumerate = True) + item = rest.list_item(item_text, auto_enumerate = True) assert item.text().strip()[0:2] == '#.' check_rest(item) def test_literal_block(self): - block_text = '''\ + text = '''\ This line is only 45 characters wide. - This one is even longer (two spaces). + This one is even longer (two spaces).\ ''' - - block = rest.literal_block(block_text) - assert block.text()[:6] == '\n\n::\n\n' + block = rest.literal_block(text) + assert block.text()[:6] == block.sep + '::' + block.sep out = Out() block.__rest__(out) - assert out.max_length() == len(block.quote) + max([len(l) for l in block_text.splitlines()]) + assert out.max_length() == len(block.quote) + max([len(l) for l in text.splitlines()]) check_rest(block) - - block = rest.literal_block(block_text, quote= rest.literal_block.quotes[3]) + + block = rest.literal_block(text, quote= rest.literal_block.quotes[3]) assert block.text().strip()[4] == rest.literal_block.quotes[3] - + check_rest(block) + + def test_interpreted_text(self): @@ -247,42 +274,95 @@ assert itext_role.text().startswith(':red:`just') def test_directive(self): - pass - + dir = rest.directive.image('img.png') + assert dir.text() == dir.sep + '.. image:: img.png\n' + dir.sep + check_rest(dir.text()) + + def test_directive_with_options(self): + expected = """\ +.. figure:: picture.png + :alt: map to buried treasure + :scale: 50 -# create texts with rest objects + This is the caption of the figure (a simple paragraph). - def test_block_quote(self): - block ="""\ -This is an ordinary paragraph, introducing a block quote. + The legend consists of all elements after the caption. In this + case, the legend consists of this paragraph.""" - "It is my business to know things. That is my trade." + legend = """ The legend consists of all elements after the caption. In this\n case, the legend consists of this paragraph.""" + + figure = rest.directive.figure('picture.png', rest.paragraph('This is the caption of the figure (a simple paragraph).'), rest.paragraph(legend), scale=50, alt= 'map to buried treasure') + + check_rest(expected) + check_rest(figure.text()) + print_lines(expected.splitlines()) + print_lines(figure.text().splitlines()) - -- Sherlock Holmes - """ - assert check_rest(block) + assert strip_lines(expected.splitlines()) == strip_lines(figure.text().splitlines()) + + + def test_directive_replace_underscore_in_directive_name(self): + expected = '''\ +.. csv-table:: Frozen Delights! + :header: "Treat", "Quantity", "Description" + :widths: 15, 10, 30 + + Albatross,2.99,On a stick! + Crunchy Frog,1.49,"If we took the bones out, it wouldn't be crunchy, + now would it?" + Gannet Ripple,1.99,On a stick! +''' #" + + data =[["Albatross", 2.99, "On a stick!"], + ["Crunchy Frog", 1.49, "If we took the bones out, it wouldn't be crunchy, now would it?"], + ["Gannet Ripple", 1.99, "On a stick!"] + ] + + out = Out(width = None) + py.std.csv.writer(out).writerows(data) + text = out.render() + table = rest.directive.csv_table('Frozen Delights!', text, + header = '"Treat", "Quantity", "Description"', + widths = "15, 10, 30") + + print_lines(expected.splitlines()) + print_lines(table.text().splitlines()) + check_rest(expected) + check_rest(table.text()) + assert strip_lines(expected.splitlines()) == strip_lines(table.text().splitlines()) + + +## def test_block_quote(self): +## block ="""\ +## This is an ordinary paragraph, introducing a block quote. + +## "It is my business to know things. That is my trade." + +## -- Sherlock Holmes +## """ +## assert check_rest(block) - def test_quoted_line_block(self): - text = """\ -Take it away, Eric the Orchestra Leader! - - | A one, two, a one two three four - | - | Half a bee, philosophically, - | must, *ipso facto*, half not be. - | But half the bee has got to be, - | *vis a vis* its entity. D'you see? - | - | But can a bee be said to be - | or not to be an entire bee, - | when half the bee is not a bee, - | due to some ancient injury? - | - | Singing... - """ - assert check_rest(text) +## def test_quoted_line_block(self): +## text = """\ +## Take it away, Eric the Orchestra Leader! + +## | A one, two, a one two three four +## | +## | Half a bee, philosophically, +## | must, *ipso facto*, half not be. +## | But half the bee has got to be, +## | *vis a vis* its entity. D'you see? +## | +## | But can a bee be said to be +## | or not to be an entire bee, +## | when half the bee is not a bee, +## | due to some ancient injury? +## | +## | Singing... +## """ +## assert check_rest(text) #def test_temdir_output(): # py.test.skip('tempdir is %s' % temp) From cfbolz at codespeak.net Fri Dec 16 20:35:35 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 16 Dec 2005 20:35:35 +0100 (CET) Subject: [py-svn] r21246 - py/dist/py/rest Message-ID: <20051216193535.4A75C27DBF@code1.codespeak.net> Author: cfbolz Date: Fri Dec 16 20:35:34 2005 New Revision: 21246 Modified: py/dist/py/rest/convert.py Log: hum. ExecutionFailed is not exported :-( Modified: py/dist/py/rest/convert.py ============================================================================== --- py/dist/py/rest/convert.py (original) +++ py/dist/py/rest/convert.py Fri Dec 16 20:35:34 2005 @@ -1,5 +1,6 @@ import py +from py.__.process import ExecutionFailed # utility functions to convert between various formats format_to_dotargument = {"png": "png", @@ -13,10 +14,10 @@ try: eps = ps.new(ext=".eps") py.process.cmdexec("ps2epsi %s %s" % (ps, eps)) - except py.process.ExecutionFailed: + except ExecutionFailed: try: py.process.cmdexec("ps2eps -l -f %s" % ps) - except py.process.ExecutionFailed: + except ExecutionFailed: raise OSError("neither ps2eps nor ps2epsi found") def ps2pdf(ps, compat_level="1.2"): From cfbolz at codespeak.net Fri Dec 16 20:39:48 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 16 Dec 2005 20:39:48 +0100 (CET) Subject: [py-svn] r21247 - py/dist/py/rest Message-ID: <20051216193948.04D0927DBF@code1.codespeak.net> Author: cfbolz Date: Fri Dec 16 20:39:47 2005 New Revision: 21247 Modified: py/dist/py/rest/convert.py Log: stupid me. Modified: py/dist/py/rest/convert.py ============================================================================== --- py/dist/py/rest/convert.py (original) +++ py/dist/py/rest/convert.py Fri Dec 16 20:39:47 2005 @@ -1,6 +1,6 @@ import py -from py.__.process import ExecutionFailed +from py.__.process.cmdexec import ExecutionFailed # utility functions to convert between various formats format_to_dotargument = {"png": "png", From cfbolz at codespeak.net Mon Dec 19 14:27:27 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 19 Dec 2005 14:27:27 +0100 (CET) Subject: [py-svn] r21308 - in py/dist/py: misc rest rest/testing rest/testing/data Message-ID: <20051219132727.B236027DBE@code1.codespeak.net> Author: cfbolz Date: Mon Dec 19 14:27:25 2005 New Revision: 21308 Added: py/dist/py/rest/testing/data/formula1.txt py/dist/py/rest/testing/test_htmlrest.py Modified: py/dist/py/misc/rest.py py/dist/py/rest/directive.py Log: make formulas with backslashes work for the htmlwriter: docutils replaces backslashes with \x00 for reasons that escape me. GRRRRRR Modified: py/dist/py/misc/rest.py ============================================================================== --- py/dist/py/misc/rest.py (original) +++ py/dist/py/misc/rest.py Mon Dec 19 14:27:25 2005 @@ -1,3 +1,4 @@ +import py import sys, os, traceback import re @@ -39,7 +40,9 @@ """ process a textfile """ log("processing %s" % txtpath) assert txtpath.check(ext='.txt') - htmlpath = txtpath.localpath.new(ext='.html') + if isinstance(txtpath, py.path.svnwc): + txtpath = txtpath.localpath + htmlpath = txtpath.new(ext='.html') #svninfopath = txtpath.localpath.new(ext='.svninfo') style = txtpath.dirpath('style.css') Modified: py/dist/py/rest/directive.py ============================================================================== --- py/dist/py/rest/directive.py (original) +++ py/dist/py/rest/directive.py Mon Dec 19 14:27:25 2005 @@ -61,7 +61,7 @@ imagename = "%s_%s.png" % ( hash(text), "".join([c for c in text if c.isalnum()])) image = imagedir.join(imagename) - latexformula2png(text, image) + latexformula2png(utils.unescape(text, True), image) imagenode = nodes.image(image.relto(sourcedir), uri=image.relto(sourcedir)) return [imagenode], [] latexformula_role.content = True Added: py/dist/py/rest/testing/data/formula1.txt ============================================================================== --- (empty file) +++ py/dist/py/rest/testing/data/formula1.txt Mon Dec 19 14:27:25 2005 @@ -0,0 +1,2 @@ +this formula contains a fraction, that means it also contains a backslash: +:latexformula:`$\frac{x^2}{y^2}$` Added: py/dist/py/rest/testing/test_htmlrest.py ============================================================================== --- (empty file) +++ py/dist/py/rest/testing/test_htmlrest.py Mon Dec 19 14:27:25 2005 @@ -0,0 +1,11 @@ +import py +from py.__.misc import rest + +data = py.magic.autopath().dirpath().join("data") + +def test_process_all(): + # fallback test: only checks that no exception is raised + def rec(p): + return p.check(dotfile=0) + for x in data.visit("*.txt", rec=rec): + yield rest.process, x From cfbolz at codespeak.net Mon Dec 19 14:40:43 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 19 Dec 2005 14:40:43 +0100 (CET) Subject: [py-svn] r21310 - py/dist/py/rest Message-ID: <20051219134043.7B1CF27DBE@code1.codespeak.net> Author: cfbolz Date: Mon Dec 19 14:40:42 2005 New Revision: 21310 Modified: py/dist/py/rest/convert.py Log: fix too big images if the PIL is not installed Modified: py/dist/py/rest/convert.py ============================================================================== --- py/dist/py/rest/convert.py (original) +++ py/dist/py/rest/convert.py Mon Dec 19 14:40:42 2005 @@ -72,7 +72,7 @@ self.upscale = 5 # create the image upscale times larger, then scale it down except ImportError: self.scale = 2 - self.upscale = 5 + self.upscale = 1 self.Image = None self.output_format = ('pngmono', 'pnggray', 'pngalpha')[2] if temp is None: From jan at codespeak.net Tue Dec 20 21:30:11 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Tue, 20 Dec 2005 21:30:11 +0100 (CET) Subject: [py-svn] r21365 - py/dist/py/magic Message-ID: <20051220203011.93F5627B5B@code1.codespeak.net> Author: jan Date: Tue Dec 20 21:30:10 2005 New Revision: 21365 Modified: py/dist/py/magic/assertion.py Log: issue29 Patch to avoid the SyntaxError exception, but the nice explanation of the assert statement doesn't work. The heuristic in getstatementrange in py.code.source should be tweaked to find the assert statement in compound statements or the reinterpretation should handle compound statements (if, while, for, try, def, class). Or the user should be warned not to use statement lists (http://docs.python.org/ref/compound.html) ;-) Modified: py/dist/py/magic/assertion.py ============================================================================== --- py/dist/py/magic/assertion.py (original) +++ py/dist/py/magic/assertion.py Tue Dec 20 21:30:10 2005 @@ -13,7 +13,7 @@ f = sys._getframe(1) try: source = py.code.Frame(f).statement - source = str(source).strip() + source = str(source.deindent()).strip() except py.error.ENOENT: source = None # this can also occur during reinterpretation, when the From cfbolz at codespeak.net Wed Dec 21 15:31:43 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 21 Dec 2005 15:31:43 +0100 (CET) Subject: [py-svn] r21409 - py/dist/py/rest Message-ID: <20051221143143.7053927DC3@code1.codespeak.net> Author: cfbolz Date: Wed Dec 21 15:31:39 2005 New Revision: 21409 Modified: py/dist/py/rest/latex.py Log: don't overwrite file (even if the content is same) Modified: py/dist/py/rest/latex.py ============================================================================== --- py/dist/py/rest/latex.py (original) +++ py/dist/py/rest/latex.py Wed Dec 21 15:31:39 2005 @@ -89,7 +89,8 @@ if len(rest_sources) > 1: assert rest not in rest_sources content = merge_files(rest_sources, pagebreak) - rest.write(content) + if len(rest_sources) > 1: + rest.write(content) sty = configfile.new(ext='sty') content = create_stylesheet(configfile_dic, path) sty.write(content) From cfbolz at codespeak.net Wed Dec 21 16:26:45 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 21 Dec 2005 16:26:45 +0100 (CET) Subject: [py-svn] r21414 - py/dist/py/rest Message-ID: <20051221152645.898A827B52@code1.codespeak.net> Author: cfbolz Date: Wed Dec 21 16:26:43 2005 New Revision: 21414 Modified: py/dist/py/rest/latex.py Log: use latin-1 as default-encoding Modified: py/dist/py/rest/latex.py ============================================================================== --- py/dist/py/rest/latex.py (original) +++ py/dist/py/rest/latex.py Wed Dec 21 16:26:43 2005 @@ -114,7 +114,7 @@ if pdf.check(): pdf.remove() tex = f.new(ext="tex").basename - options = [f, "--graphicx-option=auto", "--traceback"] + options = [f, "--input-encoding=latin-1", "--graphicx-option=auto", "--traceback"] if stylesheet is not None: sty = path.join(stylesheet) if sty.check(): From cfbolz at codespeak.net Wed Dec 21 23:30:48 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 21 Dec 2005 23:30:48 +0100 (CET) Subject: [py-svn] r21475 - py/dist/py/rest Message-ID: <20051221223048.75F6727B46@code1.codespeak.net> Author: cfbolz Date: Wed Dec 21 23:30:47 2005 New Revision: 21475 Modified: py/dist/py/rest/rest.sty.template Log: epstopdf should not be necessary anymore Modified: py/dist/py/rest/rest.sty.template ============================================================================== --- py/dist/py/rest/rest.sty.template (original) +++ py/dist/py/rest/rest.sty.template Wed Dec 21 23:30:47 2005 @@ -2,7 +2,6 @@ \usepackage{lastpage} \pagestyle{fancy} \usepackage[pdftex]{graphicx} -\usepackage{epstopdf} %(have_tocdepth)s\setcounter{tocdepth}{%(toc_depth)s} From cfbolz at codespeak.net Thu Dec 22 00:19:28 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 22 Dec 2005 00:19:28 +0100 (CET) Subject: [py-svn] r21481 - py/dist/py/rest Message-ID: <20051221231928.EACC227B5B@code1.codespeak.net> Author: cfbolz Date: Thu Dec 22 00:19:27 2005 New Revision: 21481 Modified: py/dist/py/rest/latex.py Log: don't rerun indefinitely Modified: py/dist/py/rest/latex.py ============================================================================== --- py/dist/py/rest/latex.py (original) +++ py/dist/py/rest/latex.py Thu Dec 22 00:19:27 2005 @@ -124,13 +124,14 @@ if rest_options is not None: options.extend(rest_options) publish_cmdline(writer_name='latex', argv=options) - - while True: + i = 0 + while i < 10: # there should never be as many as five reruns, but to be sure latexoutput = py.process.cmdexec("pdflatex %s" % (tex, )) if debug: print latexoutput if py.std.re.search("LaTeX Warning:.*Rerun", latexoutput) is None: break + i += 1 old.chdir() #cleanup: