diff --git a/py/apigen/apigen.py b/py/apigen/apigen.py index a92386a86..27a1b1264 100644 --- a/py/apigen/apigen.py +++ b/py/apigen/apigen.py @@ -17,7 +17,7 @@ def get_documentable_items(pkgdir): rootmod = __import__(pkgdir.basename) return 'py', pkg_to_dict(rootmod) -def build(pkgdir, dsa): +def build(pkgdir, dsa, capture): l = linker.Linker() proj = project.Project() @@ -32,16 +32,25 @@ def build(pkgdir, dsa): apb = htmlgen.ApiPageBuilder(targetdir, l, dsa, pkgdir, namespace_tree) spb = htmlgen.SourcePageBuilder(targetdir, l, pkgdir) + capture.writeorgerr('preparing namespace pages\n') ns_data = apb.prepare_namespace_pages() + capture.writeorgerr('preparing class pages\n') class_names = dsa.get_class_names() class_data = apb.prepare_class_pages(class_names) + capture.writeorgerr('preparing function pages\n') function_names = dsa.get_function_names() func_data = apb.prepare_function_pages(function_names) + capture.writeorgerr('preparing source pages\n') source_data = spb.prepare_pages(pkgdir) + capture.writeorgerr('building namespace pages\n') apb.build_namespace_pages(ns_data, proj) + capture.writeorgerr('building class pages\n') apb.build_class_pages(class_data, proj) - #apb.build_method_pages(method_data, proj) + apb.build_method_pages(method_data, proj) + capture.writeorgerr('building function pages\n') apb.build_function_pages(func_data, proj) + capture.writeorgerr('building source pages\n') spb.build_pages(source_data, proj, pkgdir) + capture.writeorgerr('done building documentation\n') diff --git a/py/io/capture.py b/py/io/capture.py index 695da63fc..c79f0fc5a 100644 --- a/py/io/capture.py +++ b/py/io/capture.py @@ -1,9 +1,12 @@ -import os, sys +import os +import sys +import thread import py class FDCapture: """ Capture IO to/from a given os-level filedescriptor. """ + def __init__(self, targetfd, tmpfile=None): self.targetfd = targetfd if tmpfile is None: @@ -14,16 +17,22 @@ class FDCapture: self._patched = [] def setasfile(self, name, module=sys): + """ patch . to self.tmpfile + """ key = (module, name) self._patched.append((key, getattr(module, name))) setattr(module, name, self.tmpfile) def unsetfiles(self): + """ unpatch all patched items + """ while self._patched: (module, name), value = self._patched.pop() setattr(module, name, value) def done(self): + """ unpatch and clean up, returns the self.tmpfile (file object) + """ os.dup2(self._savefd, self.targetfd) self.unsetfiles() os.close(self._savefd) @@ -31,11 +40,23 @@ class FDCapture: return self.tmpfile def maketmpfile(self): + """ create a temporary file + """ f = os.tmpfile() newf = py.io.dupfile(f) f.close() return newf + def writeorg(self, str): + """ write a string to the original file descriptor + """ + tempfp = os.tmpfile() + try: + os.dup2(self._savefd, tempfp.fileno()) + tempfp.write(str) + finally: + tempfp.close() + class OutErrCapture: """ capture Stdout and Stderr both on filedescriptor and sys.stdout/stderr level. @@ -51,6 +72,11 @@ class OutErrCapture: self.err.setasfile('stderr') def reset(self): + """ reset sys.stdout and sys.stderr + + returns a tuple of file objects (out, err) for the captured + data + """ out = err = "" if hasattr(self, 'out'): outfile = self.out.done() @@ -60,6 +86,20 @@ class OutErrCapture: err = errfile.read() return out, err + def writeorgout(self, str): + """ write something to the original stdout + """ + if not hasattr(self, 'out'): + raise IOError('stdout not patched') + self.out.writeorg(str) + + def writeorgerr(self, str): + """ write something to the original stderr + """ + if not hasattr(self, 'err'): + raise IOError('stderr not patched') + self.err.writeorg(str) + def callcapture(func, *args, **kwargs): """ call the given function with args/kwargs and return a (res, out, err) tuple where diff --git a/py/io/test/test_capture.py b/py/io/test/test_capture.py index fb524543b..686267af7 100644 --- a/py/io/test/test_capture.py +++ b/py/io/test/test_capture.py @@ -30,6 +30,33 @@ class TestFDCapture: f = cap.done() assert x == "3" + def test_writeorg(self): + tmppath = py.test.ensuretemp('test_writeorg').ensure('stderr', + file=True) + tmpfp = tmppath.open('w+b') + try: + cap = py.io.FDCapture(tmpfp.fileno()) + print >>tmpfp, 'foo' + cap.writeorg('bar\n') + finally: + tmpfp.close() + f = cap.done() + scap = f.read() + assert scap == 'foo\n' + stmp = tmppath.read() + assert stmp == "bar\n" + + def test_writeorg_wrongtype(self): + tmppath = py.test.ensuretemp('test_writeorg').ensure('stdout', + file=True) + tmpfp = tmppath.open('r') + try: + cap = py.io.FDCapture(tmpfp.fileno()) + py.test.raises(IOError, "cap.writeorg('bar\\n')") + finally: + tmpfp.close() + f = cap.done() + class TestCapturing: def getcapture(self): return py.io.OutErrCapture() diff --git a/py/test/rsession/rsession.py b/py/test/rsession/rsession.py index e373a9b7b..e71818303 100644 --- a/py/test/rsession/rsession.py +++ b/py/test/rsession/rsession.py @@ -263,7 +263,8 @@ class LSession(AbstractSession): try: pkgdir = self.getpkgdir(self.config.args[0]) apigen.build(pkgdir, - DocStorageAccessor(self.docstorage)) + DocStorageAccessor(self.docstorage), + capture) finally: capture.reset()