From arigo at codespeak.net Fri Dec 1 18:31:24 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 1 Dec 2006 18:31:24 +0100 (CET) Subject: [py-svn] r35209 - in py/dist/py: io/test misc misc/testing Message-ID: <20061201173124.A36C31007A@code0.codespeak.net> Author: arigo Date: Fri Dec 1 18:31:22 2006 New Revision: 35209 Modified: py/dist/py/io/test/test_capture.py py/dist/py/misc/simplecapture.py py/dist/py/misc/testing/test_simplecapture.py Log: SimpleCapturing now sets sys.stdin to a stub class that complains when reading (e.g. if there is a pdb.set_trace() left in the test) instead of just appearing to hang. Ideally when stdin is accessed, the capturing should be turned off, with possibly all data captured so far sent to the screen. This should be configurable, though, because in automated test runs it is better to crash than hang indefinitely. Modified: py/dist/py/io/test/test_capture.py ============================================================================== --- py/dist/py/io/test/test_capture.py (original) +++ py/dist/py/io/test/test_capture.py Fri Dec 1 18:31:22 2006 @@ -24,7 +24,9 @@ print >>f, "3" f.seek(0) cap = py.io.FDCapture(0, tmpfile=f) - x = raw_input() + # check with os.read() directly instead of raw_input(), because + # sys.stdin itself may be redirected (as py.test now does by default) + x = os.read(0, 100).strip() f = cap.done() assert x == "3" Modified: py/dist/py/misc/simplecapture.py ============================================================================== --- py/dist/py/misc/simplecapture.py (original) +++ py/dist/py/misc/simplecapture.py Fri Dec 1 18:31:22 2006 @@ -14,8 +14,10 @@ used by the unittest package to capture print-statements in tests. """ def __init__(self): + self.oldin = sys.stdin self.oldout = sys.stdout self.olderr = sys.stderr + sys.stdin = self.newin = DontReadFromInput() sys.stdout = self.newout = StringIO() sys.stderr = self.newerr = StringIO() @@ -26,13 +28,27 @@ def done(self): o,e = sys.stdout, sys.stderr - sys.stdout, sys.stderr = self.oldout, self.olderr - del self.oldout, self.olderr + sys.stdin, sys.stdout, sys.stderr = ( + self.oldin, self.oldout, self.olderr) + del self.oldin, self.oldout, self.olderr o, e = self.newout, self.newerr o.seek(0) e.seek(0) return o,e +class DontReadFromInput: + """Temporary stub class. Ideally when stdin is accessed, the + capturing should be turned off, with possibly all data captured + so far sent to the screen. This should be configurable, though, + because in automated test runs it is better to crash than + hang indefinitely. + """ + def read(self, *args): + raise IOError("reading from stdin while output is captured") + readline = read + readlines = read + __iter__ = read + def callcapture(func, *args, **kwargs): so = SimpleOutErrCapture() try: Modified: py/dist/py/misc/testing/test_simplecapture.py ============================================================================== --- py/dist/py/misc/testing/test_simplecapture.py (original) +++ py/dist/py/misc/testing/test_simplecapture.py Fri Dec 1 18:31:22 2006 @@ -66,6 +66,13 @@ assert out1 == "cap1\n" assert out2 == "cap2\n" + def test_reading_stdin_while_captured_doesnt_hang(self): + cap = self.getcapture() + try: + py.test.raises(IOError, raw_input) + finally: + cap.reset() + def test_callcapture(): def func(x, y): print x From fijal at codespeak.net Sun Dec 3 23:31:15 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 3 Dec 2006 23:31:15 +0100 (CET) Subject: [py-svn] r35236 - py/dist/py/test/rsession Message-ID: <20061203223115.B677A1007B@code0.codespeak.net> Author: fijal Date: Sun Dec 3 23:31:14 2006 New Revision: 35236 Modified: py/dist/py/test/rsession/hostmanage.py Log: Forgotten to check that in. Modified: py/dist/py/test/rsession/hostmanage.py ============================================================================== --- py/dist/py/test/rsession/hostmanage.py (original) +++ py/dist/py/test/rsession/hostmanage.py Sun Dec 3 23:31:14 2006 @@ -59,6 +59,7 @@ else: gw = py.execnet.PopenGateway(remotepython=remote_python) gw.hostid = 'localhost' + str(num) + gw.sshaddress = 'localhost' hosts.append((num, host, gw, str(pkgdir.dirpath()))) return hosts From fijal at codespeak.net Mon Dec 4 15:36:51 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 4 Dec 2006 15:36:51 +0100 (CET) Subject: [py-svn] r35254 - in py/dist/py/apigen/rest: . testing Message-ID: <20061204143651.5173910070@code0.codespeak.net> Author: fijal Date: Mon Dec 4 15:36:49 2006 New Revision: 35254 Modified: py/dist/py/apigen/rest/genrest.py py/dist/py/apigen/rest/testing/test_rest.py Log: Fixed method resolution + origin. Modified: py/dist/py/apigen/rest/genrest.py ============================================================================== --- py/dist/py/apigen/rest/genrest.py (original) +++ py/dist/py/apigen/rest/genrest.py Mon Dec 4 15:36:49 2006 @@ -356,7 +356,7 @@ lst = [title, LiteralBlock(self.dsa.get_doc(functionname)), LiteralBlock(self.dsa.get_function_definition(functionname))] - opar = Paragraph('origin: ') + opar = Paragraph(Em('origin'), ":") if origin: linktarget = self.writer.getlink('class', origin.name, 'class_%s' % (origin.name,)) @@ -365,7 +365,7 @@ opar.add(Text('')) lst.append(opar) - lst.append(Paragraph("where:")) + lst.append(Paragraph(Em("where"), ":")) args, retval = self.dsa.get_function_signature(functionname) for name, _type in args + [('return value', retval)]: l = self.process_type_link(_type) @@ -385,14 +385,14 @@ local_changes = self.dsa.get_function_local_changes(functionname) if local_changes: - lst.append(Paragraph('changes in __dict__ after execution:')) + lst.append(Paragraph(Em('changes in __dict__ after execution'), ":")) for k, changeset in local_changes.iteritems(): lst.append(ListItem('%s: %s' % (k, ', '.join(changeset)))) exceptions = self.dsa.get_function_exceptions(functionname) if exceptions: - lst.append(Paragraph('exceptions that might appear during ' - 'execution:')) + lst.append(Paragraph(Em('exceptions that might appear during ' + 'execution'), ":")) for exc in exceptions: lst.append(ListItem(exc.__name__)) # XXX: right now we leave it alone @@ -406,7 +406,7 @@ #else: source = self.dsa.get_function_source(functionname) if source: - lst.append(Paragraph('function source:')) + lst.append(Paragraph(Em('function source'), ":")) lst.append(LiteralBlock(source)) # call sites.. Modified: py/dist/py/apigen/rest/testing/test_rest.py ============================================================================== --- py/dist/py/apigen/rest/testing/test_rest.py (original) +++ py/dist/py/apigen/rest/testing/test_rest.py Mon Dec 4 15:36:49 2006 @@ -199,8 +199,8 @@ 'method_SomeSubClass.method.txt', 'module_Unknown module.txt', 'traceback_SomeClass.__init__.0.txt', - 'traceback_SomeClass.method.0.txt', 'traceback_SomeSubClass.__init__.0.txt', + 'traceback_SomeSubClass.method.0.txt', 'traceback_fun.0.txt', 'traceback_fun.1.txt', ] @@ -374,7 +374,7 @@ assert -1 < source.find("x \:\: ") < call_point source = tempdir.join('method_B.a.txt').read() - assert source.find('origin\: `A`_') > -1 + assert source.find('*origin* \: `A`_') > -1 self.check_rest(tempdir) def test_exc_raising(self): From fijal at codespeak.net Mon Dec 4 15:40:58 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 4 Dec 2006 15:40:58 +0100 (CET) Subject: [py-svn] r35255 - py/dist/py/apigen/tracer Message-ID: <20061204144058.42C0C10070@code0.codespeak.net> Author: fijal Date: Mon Dec 4 15:40:55 2006 New Revision: 35255 Modified: py/dist/py/apigen/tracer/docstorage.py Log: Add another possible exception (no __class__) Modified: py/dist/py/apigen/tracer/docstorage.py ============================================================================== --- py/dist/py/apigen/tracer/docstorage.py (original) +++ py/dist/py/apigen/tracer/docstorage.py Mon Dec 4 15:40:55 2006 @@ -48,7 +48,7 @@ try: # argh, very fragile specialcasing return self.desc_cache[(code.raw, locals[code.raw.co_varnames[0]].__class__)] - except (KeyError, IndexError): + except (KeyError, IndexError, AttributeError): return self.desc_cache.get(code.raw, None) #for desc in self.descs.values(): # if desc.has_code(frame.code.raw): From fijal at codespeak.net Mon Dec 4 16:20:42 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 4 Dec 2006 16:20:42 +0100 (CET) Subject: [py-svn] r35257 - in py/dist/py/apigen/rest: . testing Message-ID: <20061204152042.6E8A21007A@code0.codespeak.net> Author: fijal Date: Mon Dec 4 16:20:39 2006 New Revision: 35257 Modified: py/dist/py/apigen/rest/genrest.py py/dist/py/apigen/rest/testing/test_rest.py Log: s/Em/Strong/ Modified: py/dist/py/apigen/rest/genrest.py ============================================================================== --- py/dist/py/apigen/rest/genrest.py (original) +++ py/dist/py/apigen/rest/genrest.py Mon Dec 4 16:20:39 2006 @@ -356,7 +356,7 @@ lst = [title, LiteralBlock(self.dsa.get_doc(functionname)), LiteralBlock(self.dsa.get_function_definition(functionname))] - opar = Paragraph(Em('origin'), ":") + opar = Paragraph(Strong('origin'), ":") if origin: linktarget = self.writer.getlink('class', origin.name, 'class_%s' % (origin.name,)) @@ -365,7 +365,7 @@ opar.add(Text('')) lst.append(opar) - lst.append(Paragraph(Em("where"), ":")) + lst.append(Paragraph(Strong("where"), ":")) args, retval = self.dsa.get_function_signature(functionname) for name, _type in args + [('return value', retval)]: l = self.process_type_link(_type) @@ -385,13 +385,13 @@ local_changes = self.dsa.get_function_local_changes(functionname) if local_changes: - lst.append(Paragraph(Em('changes in __dict__ after execution'), ":")) + lst.append(Paragraph(Strong('changes in __dict__ after execution'), ":")) for k, changeset in local_changes.iteritems(): lst.append(ListItem('%s: %s' % (k, ', '.join(changeset)))) exceptions = self.dsa.get_function_exceptions(functionname) if exceptions: - lst.append(Paragraph(Em('exceptions that might appear during ' + lst.append(Paragraph(Strong('exceptions that might appear during ' 'execution'), ":")) for exc in exceptions: lst.append(ListItem(exc.__name__)) @@ -406,7 +406,7 @@ #else: source = self.dsa.get_function_source(functionname) if source: - lst.append(Paragraph(Em('function source'), ":")) + lst.append(Paragraph(Strong('function source'), ":")) lst.append(LiteralBlock(source)) # call sites.. Modified: py/dist/py/apigen/rest/testing/test_rest.py ============================================================================== --- py/dist/py/apigen/rest/testing/test_rest.py (original) +++ py/dist/py/apigen/rest/testing/test_rest.py Mon Dec 4 16:20:39 2006 @@ -374,7 +374,7 @@ assert -1 < source.find("x \:\: ") < call_point source = tempdir.join('method_B.a.txt').read() - assert source.find('*origin* \: `A`_') > -1 + assert source.find('**origin** \: `A`_') > -1 self.check_rest(tempdir) def test_exc_raising(self): From fijal at codespeak.net Tue Dec 5 11:23:57 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 11:23:57 +0100 (CET) Subject: [py-svn] r35282 - in py/dist/py/apigen: rest rest/testing tracer tracer/testing Message-ID: <20061205102357.391A31006F@code0.codespeak.net> Author: fijal Date: Tue Dec 5 11:23:54 2006 New Revision: 35282 Modified: py/dist/py/apigen/rest/genrest.py py/dist/py/apigen/rest/testing/test_rest.py py/dist/py/apigen/tracer/description.py py/dist/py/apigen/tracer/docstorage.py py/dist/py/apigen/tracer/testing/test_docgen.py Log: Added origins + bases of classes that are not in desc. This allows to link directly to a source ie. Right now not really used, just displayed. Modified: py/dist/py/apigen/rest/genrest.py ============================================================================== --- py/dist/py/apigen/rest/genrest.py (original) +++ py/dist/py/apigen/rest/genrest.py Tue Dec 5 11:23:54 2006 @@ -228,7 +228,7 @@ rest.append(Title('classes:', belowchar='^')) for cls, bases, cfunclist in classes: linktarget = self.writer.getlink('class', cls, - 'class_%s' % (cls,)) + 'class_%s' % (cls,)) rest.append(ListItem(Link(cls, linktarget))) classrest = self.build_classes(classes) if functions: @@ -252,9 +252,7 @@ if bases: rest.append(Title('base classes:', belowchar='^')), for base in bases: - linktarget = self.writer.getlink('class', base.name, - 'class_%s' % (base.name,)) - rest.append(ListItem(Link(base.name, linktarget))) + rest.append(ListItem(self.make_class_link(base))) if functions: rest.append(Title('functions:', belowchar='^')) for (func, origin) in functions: @@ -337,10 +335,14 @@ else: lst += self.process_type_link(i) return lst - name, _desc_type = data - linktarget = self.writer.getlink(_desc_type, name, - '%s_%s' % (_desc_type, name)) - lst.append(Link(str(_type), linktarget)) + name, _desc_type, is_degenerated = data + if not is_degenerated: + linktarget = self.writer.getlink(_desc_type, name, + '%s_%s' % (_desc_type, name)) + lst.append(Link(str(_type), linktarget)) + else: + # we should provide here some way of linking to sourcegen directly + lst.append(name) return lst def write_function(self, functionname, origin=None, ismethod=False, @@ -358,9 +360,7 @@ opar = Paragraph(Strong('origin'), ":") if origin: - linktarget = self.writer.getlink('class', origin.name, - 'class_%s' % (origin.name,)) - opar.add(Link(origin.name, linktarget)) + opar.add(self.make_class_link(origin)) else: opar.add(Text('')) lst.append(opar) @@ -465,3 +465,11 @@ tbrest.append(LiteralBlock('\n'.join(mangled))) return tbid, tbrest + def make_class_link(self, desc): + if not desc or desc.is_degenerated: + # create dummy link here, or no link at all + return Strong(desc.name) + else: + linktarget = self.writer.getlink('class', desc.name, + 'class_%s' % (desc.name,)) + return Link(desc.name, linktarget) Modified: py/dist/py/apigen/rest/testing/test_rest.py ============================================================================== --- py/dist/py/apigen/rest/testing/test_rest.py (original) +++ py/dist/py/apigen/rest/testing/test_rest.py Tue Dec 5 11:23:54 2006 @@ -397,3 +397,23 @@ source = tempdir.join('function_x.txt').open().read() assert source.find('ZeroDivisionError') < source.find('call sites\:') + + def test_nonexist_origin(self): + class A: + def method(self): + pass + + class B(A): + pass + + descs = {'B':B} + ds = DocStorage().from_dict(descs) + t = Tracer(ds) + t.start_tracing() + B().method() + t.end_tracing() + lg = DirectPaste() + tempdir = temppath.ensure("nonexit_origin", dir=True) + r = RestGen(ds, lg, DirWriter(tempdir)) + r.write() + self.check_rest(tempdir) Modified: py/dist/py/apigen/tracer/description.py ============================================================================== --- py/dist/py/apigen/tracer/description.py (original) +++ py/dist/py/apigen/tracer/description.py Tue Dec 5 11:23:54 2006 @@ -91,6 +91,7 @@ class Desc(object): def __init__(self, name, pyobj, **kwargs): self.pyobj = pyobj + self.is_degenerated = False self.name = name if type(self) is Desc: # do not override property... Modified: py/dist/py/apigen/tracer/docstorage.py ============================================================================== --- py/dist/py/apigen/tracer/docstorage.py (original) +++ py/dist/py/apigen/tracer/docstorage.py Tue Dec 5 11:23:54 2006 @@ -86,7 +86,7 @@ else: return None - def make_desc(self, key, value, **kwargs): + def make_desc(self, key, value, add_desc=True, **kwargs): if isinstance(value, types.FunctionType): desc = FunctionDesc(key, value, **kwargs) elif isinstance(value, (types.ObjectType, types.ClassType)): @@ -99,7 +99,8 @@ isinstance(field.im_func, types.FunctionType): real_name = key + '.' + name md = MethodDesc(real_name, field) - self.descs[real_name] = md + if add_desc: # XXX hack + self.descs[real_name] = md desc.add_method_desc(name, md) # Some other fields as well? elif isinstance(value, types.MethodType): @@ -230,13 +231,13 @@ return sorted(desc.getfields()) def get_type_desc(self, _type): - # XXX We provice only classes here + # XXX We provide only classes here if not isinstance(_type, model.SomeClass): return None # XXX we might want to cache it at some point for key, desc in self.ds.descs.iteritems(): if desc.pyobj == _type.cls: - return key, 'class' + return key, 'class', desc.is_degenerated return None #def get_object_info(self, key): @@ -261,7 +262,7 @@ method = self.ds.descs[name].pyobj cls = method.im_class if not cls.__bases__: - return self.desc_from_pyobj(cls) + return self.desc_from_pyobj(cls, cls.__name__) curr = cls while curr: for base in curr.__bases__: @@ -274,7 +275,7 @@ break else: break - return self.desc_from_pyobj(curr) + return self.desc_from_pyobj(curr, curr.__name__) def get_possible_base_classes(self, name): cls = self.ds.descs[name].pyobj @@ -282,13 +283,19 @@ return [] retval = [] for base in cls.__bases__: - desc = self.desc_from_pyobj(base) + desc = self.desc_from_pyobj(base, base.__name__) if desc is not None: retval.append(desc) return retval - def desc_from_pyobj(self, pyobj): + def desc_from_pyobj(self, pyobj, name): for desc in self.ds.descs.values(): if isinstance(desc, ClassDesc) and desc.pyobj is pyobj: return desc + # otherwise create empty desc + key, desc = self.ds.make_desc(name, pyobj, False) + #self.ds.descs[key] = desc + desc.is_degenerated = True + # and make sure we'll not try to link to it directly + return desc Modified: py/dist/py/apigen/tracer/testing/test_docgen.py ============================================================================== --- py/dist/py/apigen/tracer/testing/test_docgen.py (original) +++ py/dist/py/apigen/tracer/testing/test_docgen.py Tue Dec 5 11:23:54 2006 @@ -254,7 +254,8 @@ ds = DocStorage().from_dict({'C':C, 'B':B}) dsa = DocStorageAccessor(ds) - assert dsa.get_possible_base_classes('C') == [ds.descs['B']] + for desc in dsa.get_possible_base_classes('C'): + assert desc is ds.descs['B'] or desc.is_degenerated def test_desc_from_pyobj(): class A: @@ -265,7 +266,7 @@ ds = DocStorage().from_dict({'A': A, 'B': B}) dsa = DocStorageAccessor(ds) - assert dsa.desc_from_pyobj(A) is ds.descs['A'] + assert dsa.desc_from_pyobj(A, 'A') is ds.descs['A'] def test_method_origin(): class A: @@ -283,7 +284,6 @@ dsa = DocStorageAccessor(ds) origin = dsa.get_method_origin('C.bar') assert origin is ds.descs['B'] - assert dsa.get_method_origin('C.foo') is None def test_multiple_methods(): class A(object): From fijal at codespeak.net Tue Dec 5 12:20:52 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 12:20:52 +0100 (CET) Subject: [py-svn] r35284 - py/dist/py/apigen/source Message-ID: <20061205112052.1A34010070@code0.codespeak.net> Author: fijal Date: Tue Dec 5 12:20:51 2006 New Revision: 35284 Modified: py/dist/py/apigen/source/html.py Log: Intermediate checkin. Modified: py/dist/py/apigen/source/html.py ============================================================================== --- py/dist/py/apigen/source/html.py (original) +++ py/dist/py/apigen/source/html.py Tue Dec 5 12:20:51 2006 @@ -6,6 +6,8 @@ from compiler import ast class HtmlEnchanter(object): + reserved_words = {} + def __init__(self, mod): self.mod = mod self.create_caches() @@ -17,6 +19,13 @@ linecache[item.firstlineno] = item self.linecache = linecache + def colors(self, text): + words = text.split() + for num, word in enumerate(words): + if word in self.reserved_words: + pass + return [text] + def enchant_row(self, num, row): # add some informations to row, like functions defined in that # line, etc. @@ -27,10 +36,10 @@ pos = row.find(item.name) assert pos != -1 end = len(item.name) + pos - return [row[:pos], html.a(row[pos:end], href="#" + item.name, - name=item.name), row[end:]] + return self.colors(row[:pos]) + [html.a(row[pos:end], href="#" + item.name, + name=item.name)] + self.colors(row[end:]) except KeyError: - return [row] # no more info + return self.colors(row) # no more info def make_code(lst): # I HATE HTML, I HATE HTML From fijal at codespeak.net Tue Dec 5 12:52:07 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 12:52:07 +0100 (CET) Subject: [py-svn] r35287 - py/dist/py/apigen/source Message-ID: <20061205115207.7DABE1007E@code0.codespeak.net> Author: fijal Date: Tue Dec 5 12:52:06 2006 New Revision: 35287 Modified: py/dist/py/apigen/source/browser.py Log: Added some exception checks Modified: py/dist/py/apigen/source/browser.py ============================================================================== --- py/dist/py/apigen/source/browser.py (original) +++ py/dist/py/apigen/source/browser.py Tue Dec 5 12:52:06 2006 @@ -116,6 +116,9 @@ mod_dict = dict([(i.name, function_from_ast(i)) for i in function_ast] + [(i.name, class_from_ast(i)) for i in classes_ast]) # we check all the elements, if they're really there - mod = path.pyimport() - update_mod_dict(mod, mod_dict) + try: + mod = path.pyimport() + update_mod_dict(mod, mod_dict) + except (ImportError, AttributeError): + pass return Module(path, mod_dict) From fijal at codespeak.net Tue Dec 5 12:52:22 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 12:52:22 +0100 (CET) Subject: [py-svn] r35288 - py/dist/py/apigen/source Message-ID: <20061205115222.7585D1007F@code0.codespeak.net> Author: fijal Date: Tue Dec 5 12:52:20 2006 New Revision: 35288 Added: py/dist/py/apigen/source/server.py (contents, props changed) Log: Added simple server (uses pypy's server base) Added: py/dist/py/apigen/source/server.py ============================================================================== --- (empty file) +++ py/dist/py/apigen/source/server.py Tue Dec 5 12:52:20 2006 @@ -0,0 +1,32 @@ + +""" web server for displaying source +""" + +import py +from pypy.translator.js.examples import server +from py.__.apigen.source.browser import parse_path +from py.__.apigen.source.html import create_html + +class Handler(server.TestHandler): + BASE_URL='http://codespeak.net/svn/py/dist' + + def __getattr__(self, attr): + url = self.BASE_URL + "/" + attr + if url.endswith('_py'): + url = url[:-3] + '.py' + path = py.path.svnurl(url) + if not path.check(): + raise AttributeError() + def f(self, rev='HEAD'): + path = py.path.svnurl(url, rev) + # some try.. except.. here + return unicode(create_html(parse_path(path))) + f.exposed = True + f.func_name = attr + return f + +def _main(): + server.start_server(handler=Handler, start_new=False) + +if __name__ == '__main__': + _main() From fijal at codespeak.net Tue Dec 5 13:09:10 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 13:09:10 +0100 (CET) Subject: [py-svn] r35289 - py/dist/py/test/rsession Message-ID: <20061205120910.D7E2B1007D@code0.codespeak.net> Author: fijal Date: Tue Dec 5 13:09:09 2006 New Revision: 35289 Modified: py/dist/py/test/rsession/rsession.py py/dist/py/test/rsession/web.py Log: Added session option to ensure pypy will be imported. Samuele suggestion. Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Tue Dec 5 13:09:09 2006 @@ -38,6 +38,7 @@ 'runner_policy' : 'plain_runner', 'nice_level' : 0, 'waittime' : 100.0, + 'import_pypy' : False, } config = None @@ -178,6 +179,7 @@ except: rsync_roots = None # all files and directories in the pkgdir + session_options.bind_config(self.config) reporter, checkfun, startserverflag = self.init_reporter(reporter, sshhosts, RemoteReporter) reporter(report.TestStarted(sshhosts)) @@ -188,7 +190,6 @@ except: remotepython = None - session_options.bind_config(self.config) nodes = init_hosts(reporter, sshhosts, directories, pkgdir, rsync_roots, remotepython, remote_options=remote_options.d, optimise_localhost=self.optimise_localhost) @@ -225,6 +226,7 @@ if not self.config.option.nomagic: py.magic.invoke(assertion=1) + session_options.bind_config(self.config) reporter, checkfun, startserverflag = self.init_reporter(reporter, sshhosts, LocalReporter, args[0]) if shouldstop: @@ -234,7 +236,6 @@ pkgdir = self.getpkgdir(args[0]) colitems = self.make_colitems(args, baseon=pkgdir.dirpath()) reporter(report.RsyncFinished()) - session_options.bind_config(self.config) if runner is None and self.config.option.apigen: from py.__.apigen.tracer.tracer import Tracer Modified: py/dist/py/test/rsession/web.py ============================================================================== --- py/dist/py/test/rsession/web.py (original) +++ py/dist/py/test/rsession/web.py Tue Dec 5 13:09:09 2006 @@ -13,7 +13,7 @@ import sys import py -from py.__.test.rsession.rsession import RSession +from py.__.test.rsession.rsession import RSession, session_options from py.__.test.rsession import report from py.__.test import collect @@ -29,6 +29,8 @@ # replace("'", "\\'").replace(" ", " ").replace("\n", "
") try: + if not session_options.import_pypy: + raise ImportError from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal,\ described from pypy.translator.js.main import rpython2javascript, Options From fijal at codespeak.net Tue Dec 5 13:11:51 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 13:11:51 +0100 (CET) Subject: [py-svn] r35290 - py/dist/py/documentation Message-ID: <20061205121151.EAC741007D@code0.codespeak.net> Author: fijal Date: Tue Dec 5 13:11:50 2006 New Revision: 35290 Modified: py/dist/py/documentation/test.txt Log: Updated docs. Modified: py/dist/py/documentation/test.txt ============================================================================== --- py/dist/py/documentation/test.txt (original) +++ py/dist/py/documentation/test.txt Tue Dec 5 13:11:50 2006 @@ -758,6 +758,8 @@ * `waittime` - Default waiting time for remote host to finish tests (after that period we consider node as dead, default to 100s). * `max_tasks_per_node` - Maximum number of tasks which can be send to one node. +* `import_pypy` - Flag to control pypy importing for js regeneration (defaults + to False) Development Notes ----------------- From fijal at codespeak.net Tue Dec 5 13:33:57 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 13:33:57 +0100 (CET) Subject: [py-svn] r35293 - in py/dist/py/test/rsession: . testing webdata Message-ID: <20061205123357.D86491007D@code0.codespeak.net> Author: fijal Date: Tue Dec 5 13:33:55 2006 New Revision: 35293 Modified: py/dist/py/test/rsession/hostmanage.py py/dist/py/test/rsession/testing/test_webjs.py py/dist/py/test/rsession/webdata/source.js Log: Fix the redness of the localhost and fix some tests. Modified: py/dist/py/test/rsession/hostmanage.py ============================================================================== --- py/dist/py/test/rsession/hostmanage.py (original) +++ py/dist/py/test/rsession/hostmanage.py Tue Dec 5 13:33:55 2006 @@ -83,6 +83,8 @@ for num, host, gw, remoterootpath in hosts: if (host, remoterootpath) in rsynced or (host == 'localhost' \ and optimise_localhost): + key = host + str(num) + reporter(report.HostReady(host, key)) continue rsynced[(host, remoterootpath)] = True def done(host=host, num=num): Modified: py/dist/py/test/rsession/testing/test_webjs.py ============================================================================== --- py/dist/py/test/rsession/testing/test_webjs.py (original) +++ py/dist/py/test/rsession/testing/test_webjs.py Tue Dec 5 13:33:55 2006 @@ -3,15 +3,22 @@ import pypy except ImportError: py.test.skip('missing PyPy') -from pypy.translator.js.modules import dom -from py.__.test.rsession import webjs + here = py.magic.autopath().dirpath() def setup_module(mod): # load HTML into window object html = here.join('../webdata/index.html').read() + from pypy.translator.js.modules import dom + mod.dom = dom dom.window = dom.Window(html) + config, args = py.test.Config.parse([]) + from py.__.test.rsession.rsession import session_options + session_options.bind_config(config) + session_options.import_pypy = True + from py.__.test.rsession import webjs + mod.webjs = webjs def test_html_loaded(): body = dom.window.document.getElementsByTagName('body')[0] Modified: py/dist/py/test/rsession/webdata/source.js ============================================================================== Binary files. No diff available. From guido at codespeak.net Tue Dec 5 15:41:47 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Tue, 5 Dec 2006 15:41:47 +0100 (CET) Subject: [py-svn] r35303 - in py/dist/py/apigen/source: . testing Message-ID: <20061205144147.4C3E71007B@code0.codespeak.net> Author: guido Date: Tue Dec 5 15:41:44 2006 New Revision: 35303 Added: py/dist/py/apigen/source/color.py py/dist/py/apigen/source/testing/test_color.py Log: Added simple tokenizer for syntax coloring. Tokenizer has support for stuff like multiline strings. Added: py/dist/py/apigen/source/color.py ============================================================================== --- (empty file) +++ py/dist/py/apigen/source/color.py Tue Dec 5 15:41:44 2006 @@ -0,0 +1,150 @@ +""" simple Python syntax coloring """ + +import re + +class PythonSchema(object): + """ contains information for syntax coloring """ + comment = [('#', '\n')] + multiline_string = ['"""', "'''"] + string = ['"""', "'''", '"', "'"] + # XXX not complete + keyword = ['for', 'if', 'not', 'then', 'else', 'while', 'from', 'import', + 'try', 'except', 'finally', 'raise', 'print', 'exec', 'eval', + 'break', 'in', 'assert', 'None'] + alt_keyword = ['def', 'class', 'return'] + +class Token(object): + data = None + type = 'unknown' + + def __init__(self, data, type='unknown'): + self.data = data + self.type = type + + def __repr__(self): + return '' % (self.type, self.data) + + def __eq__(self, other): + return self.data == other.data and self.type == other.type + + def __ne__(self, other): + return not self.__eq__(other) + +class Tokenizer(object): + """ when fed lists strings, it will return tokens with type info + + very simple tokenizer, state is recorded for multi-line strings, etc. + """ + + _re_word = re.compile('[\w_]+') + _re_space = re.compile('\s+') + _re_number = re.compile('[\d\.]*\d+') + _re_rest = re.compile('[^\w\s\d]+') + + # these will be filled using the schema + _re_strings_full = None + _re_strings_multiline = None + _re_strings_comments = None + + def __init__(self, schema): + self.schema = schema + self._inside_multiline = False + + self._re_strings_full = [] + self._re_strings_multiline = [] + for d in schema.string + schema.multiline_string: + self._re_strings_full.append(re.compile('%s.*?%s' % (d, d))) + for d in schema.multiline_string: + self._re_strings_multiline.append((re.compile('%s.*' % (d,), re.S), + re.compile('.*?%s' % (d,)))) + # no multi-line comments in Python... phew :) + self._re_comments = [] + for start, end in schema.comment: + self._re_comments.append(re.compile('%s.*?%s' % (start, end))) + + def tokenize(self, data): + if self._inside_multiline: + m = self._inside_multiline.match(data) + if not m: + yield Token(data, 'string') + data = '' + else: + s = m.group(0) + data = data[len(s):] + self._inside_multiline = False + yield Token(s, 'string') + while data: + for f in [self._check_multiline_strings, self._check_full_strings, + self._check_comments, self._check_word, + self._check_space, self._check_number, self._check_rest]: + data, t = f(data) + if t: + yield t + break + else: + raise ValueError( + 'no token found in %r (bug in tokenizer)' % (data,)) + + def _check_full_strings(self, data): + token = None + for r in self._re_strings_full: + m = r.match(data) + if m: + s = m.group(0) + data = data[len(s):] + token = Token(s, type='string') + break + return data, token + + def _check_multiline_strings(self, data): + token = None + for start, end in self._re_strings_multiline: + m = start.match(data) + if m: + s = m.group(0) + data = '' + self._inside_multiline = end + token = Token(s, 'string') + break + return data, token + + def _check_comments(self, data): + # fortunately we don't have to deal with multi-line comments + token = None + for r in self._re_comments: + m = r.match(data) + if m: + s = m.group(0) + data = data[len(s):] + token = Token(s, 'comment') + break + return data, token + + def _check_word(self, data): + m = self._re_word.match(data) + if m: + s = m.group(0) + return data[len(s):], Token(s, 'word') + return data, None + + def _check_space(self, data): + m = self._re_space.match(data) + if m: + s = m.group(0) + return data[len(s):], Token(s, 'whitespace') + return data, None + + def _check_number(self, data): + m = self._re_number.match(data) + if m: + s = m.group(0) + return data[len(s):], Token(s, 'number') + return data, None + + def _check_rest(self, data): + m = self._re_rest.match(data) + if m: + s = m.group(0) + return data[len(s):], Token(s, 'unknown') + return data, None + Added: py/dist/py/apigen/source/testing/test_color.py ============================================================================== --- (empty file) +++ py/dist/py/apigen/source/testing/test_color.py Tue Dec 5 15:41:44 2006 @@ -0,0 +1,47 @@ +import py +from py.__.apigen.source.color import Tokenizer, Token, PythonSchema + +class TestTokenizer(object): + def tokens(self, data): + t = Tokenizer(PythonSchema) + return list(t.tokenize(data)) + + def test_word(self): + assert self.tokens('foo') == [Token('foo', type='word')] + assert self.tokens('_1_word') == [Token('_1_word', type='word')] + + def test_space(self): + assert self.tokens(' ') == [Token(' ', type='whitespace')] + assert self.tokens(' \n') == [Token(' \n', type='whitespace')] + + def test_printable(self): + assert self.tokens('.') == [Token('.', 'unknown')] + assert self.tokens(';#$@\n') == [Token(';#$@', type='unknown'), + Token('\n', type='whitespace')] + + def test_comment(self): + assert self.tokens('# foo\n') == [Token('# foo\n', type='comment')] + assert self.tokens('foo # bar\n') == [Token('foo', type='word'), + Token(' ', type='whitespace'), + Token('# bar\n', type='comment')] + + def test_string_simple(self): + assert self.tokens('"foo"') == [Token('"foo"', type='string')] + assert self.tokens('"foo"\'bar\'') == [Token('"foo"', type='string'), + Token("'bar'", type='string')] + + def test_string_escape(self): + py.test.skip('not yet implemented') + assert self.tokens('"foo \\" bar"') == [Token('"foo \\" bar"', + type='string')] + def test_string_multiline(self): + t = Tokenizer(PythonSchema) + res = list(t.tokenize('"""foo\n')) + assert res == [Token('"""foo\n', type='string')] + res = list(t.tokenize('bar\n')) + print res + assert res == [Token('bar\n', type='string')] + res = list(t.tokenize('"""\n')) + assert res == [Token('"""', type='string'), + Token('\n', type='whitespace')] + From guido at codespeak.net Tue Dec 5 16:32:03 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Tue, 5 Dec 2006 16:32:03 +0100 (CET) Subject: [py-svn] r35305 - in py/dist/py/apigen/source: . testing Message-ID: <20061205153203.08D5010081@code0.codespeak.net> Author: guido Date: Tue Dec 5 16:32:01 2006 New Revision: 35305 Modified: py/dist/py/apigen/source/color.py py/dist/py/apigen/source/html.py py/dist/py/apigen/source/testing/test_color.py py/dist/py/apigen/source/testing/test_html.py Log: Fixed some small bugs in the tokenizer, added a methods to HTMLDocument that uses the tokenizer to colour lines (although not in use yet). Modified: py/dist/py/apigen/source/color.py ============================================================================== --- py/dist/py/apigen/source/color.py (original) +++ py/dist/py/apigen/source/color.py Tue Dec 5 16:32:01 2006 @@ -33,12 +33,12 @@ class Tokenizer(object): """ when fed lists strings, it will return tokens with type info - very simple tokenizer, state is recorded for multi-line strings, etc. + very naive tokenizer, state is recorded for multi-line strings, etc. """ _re_word = re.compile('[\w_]+') _re_space = re.compile('\s+') - _re_number = re.compile('[\d\.]*\d+') + _re_number = re.compile('[\d\.]*\d[\d\.]*l?', re.I) _re_rest = re.compile('[^\w\s\d]+') # these will be filled using the schema @@ -75,8 +75,8 @@ yield Token(s, 'string') while data: for f in [self._check_multiline_strings, self._check_full_strings, - self._check_comments, self._check_word, - self._check_space, self._check_number, self._check_rest]: + self._check_comments, self._check_number, + self._check_space, self._check_word, self._check_rest]: data, t = f(data) if t: yield t @@ -124,7 +124,12 @@ m = self._re_word.match(data) if m: s = m.group(0) - return data[len(s):], Token(s, 'word') + type = 'word' + if s in self.schema.keyword: + type = 'keyword' + elif s in self.schema.alt_keyword: + type = 'alt_keyword' + return data[len(s):], Token(s, type) return data, None def _check_space(self, data): @@ -148,3 +153,4 @@ return data[len(s):], Token(s, 'unknown') return data, None + Modified: py/dist/py/apigen/source/html.py ============================================================================== --- py/dist/py/apigen/source/html.py (original) +++ py/dist/py/apigen/source/html.py Tue Dec 5 16:32:01 2006 @@ -4,6 +4,7 @@ from py.xml import html, raw from compiler import ast +from py.__.apigen.source.color import Tokenizer, PythonSchema class HtmlEnchanter(object): reserved_words = {} @@ -36,8 +37,9 @@ pos = row.find(item.name) assert pos != -1 end = len(item.name) + pos - return self.colors(row[:pos]) + [html.a(row[pos:end], href="#" + item.name, - name=item.name)] + self.colors(row[end:]) + chunk = [html.a(row[pos:end], href="#" + item.name, + name=item.name)] + return self.colors(row[:pos]) + chunk + self.colors(row[end:]) except KeyError: return self.colors(row) # no more info @@ -52,7 +54,7 @@ return output class HTMLDocument(object): - def __init__(self): + def __init__(self, tokenizer=None): self.html = root = html.html() self.head = head = self.create_head() root.append(head) @@ -61,6 +63,10 @@ self.table, self.tbody = table, tbody = self.create_table() body.append(table) + if tokenizer is None: + tokenizer = Tokenizer(PythonSchema) + self.tokenizer = tokenizer + def create_head(self): return html.head( html.title('source view'), @@ -102,6 +108,26 @@ table.append(tbody) return table, tbody + def prepare_line(self, text): + """ adds html formatting to text items (list) + + only processes items if they're of a string type (or unicode) + """ + ret = [] + for item in text: + if type(item) in [str, unicode]: + tokens = self.tokenizer.tokenize(item) + for t in tokens: + print t.type + if t.type in ['keyword', 'alt_keyword', 'number', + 'string']: + ret.append(html.span(t.data, class_=t.type)) + else: + ret.append(t.data) + else: + ret.append(item) + return ret + def add_row(self, lineno, text): if text == ['']: text = [raw(' ')] @@ -109,7 +135,9 @@ html.td(class_='code', *text))) def __unicode__(self): - return self.html.unicode() + # XXX don't like to use indent=0 here, but else py.xml's indentation + # messes up the html inside the table cells (which displays formatting) + return self.html.unicode(indent=0) def create_html(mod): # out is some kind of stream Modified: py/dist/py/apigen/source/testing/test_color.py ============================================================================== --- py/dist/py/apigen/source/testing/test_color.py (original) +++ py/dist/py/apigen/source/testing/test_color.py Tue Dec 5 16:32:01 2006 @@ -10,10 +10,31 @@ assert self.tokens('foo') == [Token('foo', type='word')] assert self.tokens('_1_word') == [Token('_1_word', type='word')] + def test_keyword(self): + assert 'if' in PythonSchema.keyword + assert self.tokens('see if it works') == [Token('see', type='word'), + Token(' ', + type='whitespace'), + Token('if', type='keyword'), + Token(' ', + type='whitespace'), + Token('it', type='word'), + Token(' ', + type='whitespace'), + Token('works', type='word')] + def test_space(self): assert self.tokens(' ') == [Token(' ', type='whitespace')] assert self.tokens(' \n') == [Token(' \n', type='whitespace')] + def test_number(self): + # XXX incomplete + assert self.tokens('1') == [Token('1', type='number')] + assert self.tokens('1.1') == [Token('1.1', type='number')] + assert self.tokens('.1') == [Token('.1', type='number')] + assert self.tokens('1.') == [Token('1.', type='number')] + assert self.tokens('1.1l') == [Token('1.1l', type='number')] + def test_printable(self): assert self.tokens('.') == [Token('.', 'unknown')] assert self.tokens(';#$@\n') == [Token(';#$@', type='unknown'), @@ -34,14 +55,18 @@ py.test.skip('not yet implemented') assert self.tokens('"foo \\" bar"') == [Token('"foo \\" bar"', type='string')] + def test_string_multiline(self): t = Tokenizer(PythonSchema) res = list(t.tokenize('"""foo\n')) assert res == [Token('"""foo\n', type='string')] res = list(t.tokenize('bar\n')) - print res assert res == [Token('bar\n', type='string')] res = list(t.tokenize('"""\n')) assert res == [Token('"""', type='string'), Token('\n', type='whitespace')] + # tricky problem: the following line must not put the tokenizer in + # 'multiline state'... + assert self.tokens('"""foo"""') == [Token('"""foo"""', type='string')] + assert self.tokens('bar') == [Token('bar', type='word')] Modified: py/dist/py/apigen/source/testing/test_html.py ============================================================================== --- py/dist/py/apigen/source/testing/test_html.py (original) +++ py/dist/py/apigen/source/testing/test_html.py Tue Dec 5 16:32:01 2006 @@ -72,6 +72,49 @@ assert isinstance(tbody, html.tbody) assert tbody == table[0] + def prepare_line(self, line, doc=None): + if doc is None: + doc = HTMLDocument() + l = doc.prepare_line(line) + return ''.join(unicode(i) for i in l) + + def test_prepare_line_basic(self): + result = self.prepare_line(['see if this works']) + assert result == 'see if this works' + result = self.prepare_line(['see if this ', + html.a('works', name='works'),' too']) + assert result == ('see if this ' + 'works too') + result = self.prepare_line(['see if something else works']) + assert result == ('see if something ' + 'else works') + result = self.prepare_line(['see if something ', + html.a('else', name='else'), ' works too']) + assert result == ('see if something ' + 'else works too') + + def test_prepare_line_strings(self): + result = self.prepare_line(['foo = "bar"']) + assert result == 'foo = "bar"' + + result = self.prepare_line(['"spam"']) + assert result == '"spam"' + + # test multiline strings + doc = HTMLDocument() + result = self.prepare_line(['"""start of multiline'], doc) + assert result == ('"""start of ' + 'multiline') + # doc should now be in 'string mode' + result = self.prepare_line(['see if it doesn\'t touch this'], doc) + assert result == ('see if it doesn't touch ' + 'this') + result = self.prepare_line(['"""'], doc) + assert result == '"""' + result = self.prepare_line(['see if it colours this again'], doc) + assert result == ('see if it colours ' + 'this again') + def test_add_row(self): doc = HTMLDocument() doc.add_row(1, ['""" this is a foo implementation """']) @@ -92,6 +135,6 @@ doc = HTMLDocument() h = unicode(doc) print h - assert py.std.re.match(r'\s+\s+[^<]+' + assert py.std.re.match(r'\s*\s*[^<]+' '.*\w*$', h, py.std.re.S) From guido at codespeak.net Tue Dec 5 16:59:29 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Tue, 5 Dec 2006 16:59:29 +0100 (CET) Subject: [py-svn] r35307 - in py/dist/py/apigen/source: . testing Message-ID: <20061205155929.1D7AF1005A@code0.codespeak.net> Author: guido Date: Tue Dec 5 16:59:27 2006 New Revision: 35307 Modified: py/dist/py/apigen/source/color.py py/dist/py/apigen/source/html.py py/dist/py/apigen/source/testing/test_color.py py/dist/py/apigen/source/testing/test_html.py Log: Integrated syntax coloring. Note that, after some discussion with cfbolz, I may replace the tokenizer with the one in the Python core. Modified: py/dist/py/apigen/source/color.py ============================================================================== --- py/dist/py/apigen/source/color.py (original) +++ py/dist/py/apigen/source/color.py Tue Dec 5 16:59:27 2006 @@ -11,7 +11,7 @@ keyword = ['for', 'if', 'not', 'then', 'else', 'while', 'from', 'import', 'try', 'except', 'finally', 'raise', 'print', 'exec', 'eval', 'break', 'in', 'assert', 'None'] - alt_keyword = ['def', 'class', 'return'] + alt_keyword = ['def', 'class', 'return', 'pass', 'yield'] class Token(object): data = None @@ -52,8 +52,10 @@ self._re_strings_full = [] self._re_strings_multiline = [] + self._re_strings_empty = [] for d in schema.string + schema.multiline_string: - self._re_strings_full.append(re.compile('%s.*?%s' % (d, d))) + self._re_strings_full.append(re.compile('%s[^%s]+%s' % (d, d, d))) + self._re_strings_empty.append(re.compile('%s%s' % (d, d))) for d in schema.multiline_string: self._re_strings_multiline.append((re.compile('%s.*' % (d,), re.S), re.compile('.*?%s' % (d,)))) @@ -74,9 +76,10 @@ self._inside_multiline = False yield Token(s, 'string') while data: - for f in [self._check_multiline_strings, self._check_full_strings, - self._check_comments, self._check_number, - self._check_space, self._check_word, self._check_rest]: + for f in [self._check_full_strings, self._check_multiline_strings, + self._check_empty_strings, self._check_comments, + self._check_number, self._check_space, self._check_word, + self._check_rest]: data, t = f(data) if t: yield t @@ -108,6 +111,18 @@ break return data, token + def _check_empty_strings(self, data): + token = None + for r in self._re_strings_empty: + m = r.match(data) + if m: + s = m.group(0) + data = data[len(s):] + token = Token(s, type='string') + break + return data, token + + def _check_comments(self, data): # fortunately we don't have to deal with multi-line comments token = None Modified: py/dist/py/apigen/source/html.py ============================================================================== --- py/dist/py/apigen/source/html.py (original) +++ py/dist/py/apigen/source/html.py Tue Dec 5 16:59:27 2006 @@ -82,6 +82,11 @@ padding: 0px; border-width: 0px; } + + a { + color: blue; + text-decoration: none; + } .lineno { text-align: right; @@ -96,6 +101,23 @@ padding-left: 1em; white-space: pre; } + + .comment { + color: purple; + } + + .string { + color: red; + } + + .keyword { + color: blue; + } + + .alt_keyword { + color: green; + } + """, type='text/css'), ) @@ -118,7 +140,6 @@ if type(item) in [str, unicode]: tokens = self.tokenizer.tokenize(item) for t in tokens: - print t.type if t.type in ['keyword', 'alt_keyword', 'number', 'string']: ret.append(html.span(t.data, class_=t.type)) @@ -131,6 +152,8 @@ def add_row(self, lineno, text): if text == ['']: text = [raw(' ')] + else: + text = self.prepare_line(text) self.tbody.append(html.tr(html.td(str(lineno), class_='lineno'), html.td(class_='code', *text))) Modified: py/dist/py/apigen/source/testing/test_color.py ============================================================================== --- py/dist/py/apigen/source/testing/test_color.py (original) +++ py/dist/py/apigen/source/testing/test_color.py Tue Dec 5 16:59:27 2006 @@ -67,6 +67,8 @@ Token('\n', type='whitespace')] # tricky problem: the following line must not put the tokenizer in # 'multiline state'... - assert self.tokens('"""foo"""') == [Token('"""foo"""', type='string')] - assert self.tokens('bar') == [Token('bar', type='word')] + res = list(t.tokenize('"""foo"""')) + assert res == [Token('"""foo"""', type='string')] + res = list(t.tokenize('bar')) + assert res == [Token('bar', type='word')] Modified: py/dist/py/apigen/source/testing/test_html.py ============================================================================== --- py/dist/py/apigen/source/testing/test_html.py (original) +++ py/dist/py/apigen/source/testing/test_html.py Tue Dec 5 16:59:27 2006 @@ -124,12 +124,20 @@ tbody = doc.tbody assert len(tbody) == 4 assert unicode(tbody[0][0]) == '1' - assert unicode(tbody[0][1]) == ('""" ' + assert unicode(tbody[0][1]) == ('' + '' + '""" ' 'this is a foo implementation ' - '"""') + '"""' + '') assert unicode(tbody[1][1]) == ' ' - assert unicode(tbody[2][1]) == ('class ' + assert unicode(tbody[2][1]) == ('' + 'class' + ' ' 'Foo:') + assert unicode(tbody[3][1]) == (' ' + 'pass' + '') def test_unicode(self): doc = HTMLDocument() From guido at codespeak.net Tue Dec 5 17:22:48 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Tue, 5 Dec 2006 17:22:48 +0100 (CET) Subject: [py-svn] r35310 - py/dist/py/apigen/source Message-ID: <20061205162248.D842A10075@code0.codespeak.net> Author: guido Date: Tue Dec 5 17:22:47 2006 New Revision: 35310 Modified: py/dist/py/apigen/source/color.py Log: Added nasty little hack to fix the 'rest' regexp (for printable stuff) eating quotes. Modified: py/dist/py/apigen/source/color.py ============================================================================== --- py/dist/py/apigen/source/color.py (original) +++ py/dist/py/apigen/source/color.py Tue Dec 5 17:22:47 2006 @@ -39,7 +39,7 @@ _re_word = re.compile('[\w_]+') _re_space = re.compile('\s+') _re_number = re.compile('[\d\.]*\d[\d\.]*l?', re.I) - _re_rest = re.compile('[^\w\s\d]+') + _re_rest = re.compile('[^\w\s\d\'"]+') # XXX cheating a bit with the quotes # these will be filled using the schema _re_strings_full = None From guido at codespeak.net Tue Dec 5 17:25:06 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Tue, 5 Dec 2006 17:25:06 +0100 (CET) Subject: [py-svn] r35311 - py/dist/py/apigen/source/testing Message-ID: <20061205162506.35DD110077@code0.codespeak.net> Author: guido Date: Tue Dec 5 17:25:04 2006 New Revision: 35311 Modified: py/dist/py/apigen/source/testing/test_color.py Log: Missing test. :) Modified: py/dist/py/apigen/source/testing/test_color.py ============================================================================== --- py/dist/py/apigen/source/testing/test_color.py (original) +++ py/dist/py/apigen/source/testing/test_color.py Tue Dec 5 17:25:04 2006 @@ -72,3 +72,7 @@ res = list(t.tokenize('bar')) assert res == [Token('bar', type='word')] + def test_string_following_printable(self): + assert self.tokens('."foo"') == [Token('.', type='unknown'), + Token('"foo"', type='string')] + From guido at codespeak.net Tue Dec 5 17:26:49 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Tue, 5 Dec 2006 17:26:49 +0100 (CET) Subject: [py-svn] r35313 - py/dist/py/apigen/source Message-ID: <20061205162649.BBEAB10078@code0.codespeak.net> Author: guido Date: Tue Dec 5 17:26:48 2006 New Revision: 35313 Modified: py/dist/py/apigen/source/html.py Log: Was accidentally filtering out comments. Modified: py/dist/py/apigen/source/html.py ============================================================================== --- py/dist/py/apigen/source/html.py (original) +++ py/dist/py/apigen/source/html.py Tue Dec 5 17:26:48 2006 @@ -141,7 +141,7 @@ tokens = self.tokenizer.tokenize(item) for t in tokens: if t.type in ['keyword', 'alt_keyword', 'number', - 'string']: + 'string', 'comment']: ret.append(html.span(t.data, class_=t.type)) else: ret.append(t.data) From pedronis at codespeak.net Tue Dec 5 20:12:38 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 5 Dec 2006 20:12:38 +0100 (CET) Subject: [py-svn] r35328 - py/dist/py/test/rsession Message-ID: <20061205191238.0A6C810077@code0.codespeak.net> Author: pedronis Date: Tue Dec 5 20:12:36 2006 New Revision: 35328 Modified: py/dist/py/test/rsession/rsession.py Log: use a complete url, makes open happier for example on Mac OS X. Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Tue Dec 5 20:12:36 2006 @@ -125,7 +125,7 @@ start_server() if self.config.option.runbrowser: import webbrowser - webbrowser.open("localhost:8000") + webbrowser.open("http://localhost:8000") elif reporter is None: if restflag: from py.__.test.rsession.rest import RestReporter From fijal at codespeak.net Tue Dec 5 20:16:35 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 20:16:35 +0100 (CET) Subject: [py-svn] r35330 - py/dist/py/apigen/source Message-ID: <20061205191635.AF50D10079@code0.codespeak.net> Author: fijal Date: Tue Dec 5 20:16:34 2006 New Revision: 35330 Modified: py/dist/py/apigen/source/server.py Log: Fixed a bit (test test test test!!!) Modified: py/dist/py/apigen/source/server.py ============================================================================== --- py/dist/py/apigen/source/server.py (original) +++ py/dist/py/apigen/source/server.py Tue Dec 5 20:16:34 2006 @@ -17,7 +17,7 @@ path = py.path.svnurl(url) if not path.check(): raise AttributeError() - def f(self, rev='HEAD'): + def f(rev='HEAD'): path = py.path.svnurl(url, rev) # some try.. except.. here return unicode(create_html(parse_path(path))) From fijal at codespeak.net Tue Dec 5 20:45:12 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 20:45:12 +0100 (CET) Subject: [py-svn] r35333 - py/dist/py/apigen/source Message-ID: <20061205194512.89FF010080@code0.codespeak.net> Author: fijal Date: Tue Dec 5 20:45:11 2006 New Revision: 35333 Modified: py/dist/py/apigen/source/html.py Log: Fixed style a bit. Modified: py/dist/py/apigen/source/html.py ============================================================================== --- py/dist/py/apigen/source/html.py (original) +++ py/dist/py/apigen/source/html.py Tue Dec 5 20:45:11 2006 @@ -7,7 +7,7 @@ from py.__.apigen.source.color import Tokenizer, PythonSchema class HtmlEnchanter(object): - reserved_words = {} + reserved_words = ['if', 'for', 'return', 'yield'] def __init__(self, mod): self.mod = mod @@ -20,13 +20,6 @@ linecache[item.firstlineno] = item self.linecache = linecache - def colors(self, text): - words = text.split() - for num, word in enumerate(words): - if word in self.reserved_words: - pass - return [text] - def enchant_row(self, num, row): # add some informations to row, like functions defined in that # line, etc. @@ -37,21 +30,11 @@ pos = row.find(item.name) assert pos != -1 end = len(item.name) + pos - chunk = [html.a(row[pos:end], href="#" + item.name, - name=item.name)] - return self.colors(row[:pos]) + chunk + self.colors(row[end:]) + chunk = html.a(row[pos:end], href="#" + item.name, + name=item.name) + return [row[:pos], chunk, row[end:]] except KeyError: - return self.colors(row) # no more info - -def make_code(lst): - # I HATE HTML, I HATE HTML - output = [] - for elem in lst: - if isinstance(elem, str): - output.append(html.code(elem)) - else: - output.append(elem) - return output + return [row] # no more info class HTMLDocument(object): def __init__(self, tokenizer=None): @@ -72,7 +55,7 @@ html.title('source view'), html.style(""" body, td { - background-color: #FFC; + background-color: #FFF; color: black; font-family: monospace; } @@ -85,18 +68,23 @@ a { color: blue; + font-weight: bold; text-decoration: none; } + a:hover { + color: #005; + } + .lineno { text-align: right; - color: blue; + color: #555; width: 3em; padding-right: 1em; border: 0px solid black; border-right-width: 1px; } - + .code { padding-left: 1em; white-space: pre; @@ -107,7 +95,7 @@ } .string { - color: red; + color: #777; } .keyword { From fijal at codespeak.net Tue Dec 5 21:08:40 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 21:08:40 +0100 (CET) Subject: [py-svn] r35334 - in py/dist/py/test/rsession: . testing webdata Message-ID: <20061205200840.6C4CA1007C@code0.codespeak.net> Author: fijal Date: Tue Dec 5 21:08:36 2006 New Revision: 35334 Modified: py/dist/py/test/rsession/testing/test_web.py py/dist/py/test/rsession/web.py py/dist/py/test/rsession/webdata/source.js py/dist/py/test/rsession/webjs.py Log: Fixed issues regardin js_optiondescr and friends Added new status line (arigo's suggestion) Modified: py/dist/py/test/rsession/testing/test_web.py ============================================================================== --- py/dist/py/test/rsession/testing/test_web.py (original) +++ py/dist/py/test/rsession/testing/test_web.py Tue Dec 5 21:08:36 2006 @@ -5,23 +5,28 @@ import py try: - from pypy.translator.js.main import rpython2javascript, Options + from pypy.translator.js.main import rpython2javascript from pypy.translator.js import commproxy commproxy.USE_MOCHIKIT = False - Options.debug_transform = True - Options.use_pdb = False except ImportError: py.test.skip("No PyPy detected") -from py.__.test.rsession.web import TestHandler as _TestHandler -from py.__.test.rsession.web import MultiQueue +def setup_module(mod): + config, args = py.test.Config.parse([]) + from py.__.test.rsession.rsession import session_options + session_options.bind_config(config) + session_options.import_pypy = True + from py.__.test.rsession.web import TestHandler as _TestHandler + from py.__.test.rsession.web import MultiQueue + mod._TestHandler = _TestHandler + mod.MultiQueue = MultiQueue def test_js_generate(): from py.__.test.rsession import webjs from py.__.test.rsession.web import FUNCTION_LIST - source = rpython2javascript(webjs, FUNCTION_LIST, Options, use_pdb=False) + source = rpython2javascript(webjs, FUNCTION_LIST) assert source def test_parse_args(): Modified: py/dist/py/test/rsession/web.py ============================================================================== --- py/dist/py/test/rsession/web.py (original) +++ py/dist/py/test/rsession/web.py Tue Dec 5 21:08:36 2006 @@ -33,10 +33,9 @@ raise ImportError from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal,\ described - from pypy.translator.js.main import rpython2javascript, Options + from pypy.translator.js.main import rpython2javascript from pypy.translator.js import commproxy - Options.debug_transform = False commproxy.USE_MOCHIKIT = False IMPORTED_PYPY = True except ImportError: @@ -128,6 +127,7 @@ self.fail_reasons = {} self.stdout = {} self.stderr = {} + self.all = 0 def findmodule(self, item): # find the most outwards parent which is module @@ -215,6 +215,11 @@ args['hostkey'] = '' elif isinstance(event, report.ItemStart): args = add_item(event) + elif isinstance(event, report.TestFinished): + args = {} + args['run'] = str(self.all) + args['fails'] = str(len(self.fail_reasons)) + args['skips'] = str(len(self.skip_reasons)) elif isinstance(event, report.SendItem): args = add_item(event) args['hostkey'] = event.channel.gateway.hostid @@ -251,6 +256,7 @@ return lines def report_ReceivedItemOutcome(self, event): + self.all += 1 self.pending_events.put(event) def report_ItemStart(self, event): @@ -353,7 +359,7 @@ from py.__.test.rsession import webjs javascript_source = rpython2javascript(webjs, - FUNCTION_LIST, Options) + FUNCTION_LIST, use_pdb=False) # XXX: This did not work for some reason, no idea why open(str(js_name), "w").write(javascript_source) self.serve_data("text/javascript", javascript_source) @@ -374,6 +380,7 @@ if start_new: thread.start_new_thread(httpd.serve_forever, ()) print "Server started, listening on %s" % (server_address,) + return httpd else: print "Server started, listening on %s" % (server_address,) httpd.serve_forever() Modified: py/dist/py/test/rsession/webdata/source.js ============================================================================== Binary files. No diff available. Modified: py/dist/py/test/rsession/webjs.py ============================================================================== --- py/dist/py/test/rsession/webjs.py (original) +++ py/dist/py/test/rsession/webjs.py Tue Dec 5 21:08:36 2006 @@ -158,9 +158,10 @@ counter_part.childNodes[0].nodeValue = newcontent module_part.childNodes[-1].appendChild(td) elif msg['type'] == 'TestFinished': - dom.get_document().title = "Py.test [FINISHED]" + text = "FINISHED %s run, %s failures, %s skipped" % (msg['run'], msg['fails'], msg['skips']) + dom.get_document().title = "Py.test %s" % text dom.get_document().getElementById("Tests").childNodes[0].nodeValue = \ - "Tests [FINISHED]" + "Tests [%s]" % text elif msg['type'] == 'FailedTryiter': module_part = get_elem(msg['fullitemname']) if not module_part: From fijal at codespeak.net Tue Dec 5 21:20:27 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 21:20:27 +0100 (CET) Subject: [py-svn] r35337 - in py/dist/py/test/rsession: . testing Message-ID: <20061205202027.6999B10077@code0.codespeak.net> Author: fijal Date: Tue Dec 5 21:20:23 2006 New Revision: 35337 Modified: py/dist/py/test/rsession/testing/test_web.py py/dist/py/test/rsession/web.py Log: Added stuff which prevents strange errors when reloading and closing browser window (thx samuele and armin). Modified: py/dist/py/test/rsession/testing/test_web.py ============================================================================== --- py/dist/py/test/rsession/testing/test_web.py (original) +++ py/dist/py/test/rsession/testing/test_web.py Tue Dec 5 21:20:23 2006 @@ -89,4 +89,3 @@ result = mq.get(4567) assert result == 2 assert mq.empty() - Modified: py/dist/py/test/rsession/web.py ============================================================================== --- py/dist/py/test/rsession/web.py (original) +++ py/dist/py/test/rsession/web.py Tue Dec 5 21:20:23 2006 @@ -11,6 +11,7 @@ import Queue import os import sys +import socket import py from py.__.test.rsession.rsession import RSession, session_options @@ -87,6 +88,13 @@ q.put(item) finally: self._lock.release() + + def _del(self, sessid): + self._lock.acquire() + try: + del self._session_queues[sessid] + finally: + self._lock.release() def get(self, sessid): self._lock.acquire() @@ -178,6 +186,18 @@ return json.write(sessid) show_sessid = described(retval="aa")(show_sessid) + def failed(self, **kwargs): + if not 'sessid' in kwargs: + return + sessid = kwargs['sessid'] + to_del = -1 + for num, i in enumerate(self._sessids): + if i == sessid: + to_del = num + if to_del != -1: + del self._sessids[to_del] + self.pending_events._del(kwargs['sessid']) + def show_all_statuses(self, sessid=-1): retlist = [self.show_status_change(sessid)] while not self.pending_events.empty_queue(sessid): @@ -321,8 +341,12 @@ if exec_meth is None: self.send_error(404, "File %s not found" % path) else: - self.serve_data('text/json', + try: + self.serve_data('text/json', exec_meth(**self.parse_args(getargs))) + except socket.error: + # client happily disconnected + exported_methods.failed(**self.parse_args(getargs)) else: method_to_call() From fijal at codespeak.net Tue Dec 5 22:42:12 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 22:42:12 +0100 (CET) Subject: [py-svn] r35344 - in py/dist/py/test/rsession: . testing webdata Message-ID: <20061205214212.3FCB510079@code0.codespeak.net> Author: fijal Date: Tue Dec 5 22:42:06 2006 New Revision: 35344 Modified: py/dist/py/test/rsession/testing/test_webjs.py py/dist/py/test/rsession/web.py py/dist/py/test/rsession/webdata/source.js py/dist/py/test/rsession/webjs.py Log: A bit of fixes and refactoring. Broken tests though :-( Modified: py/dist/py/test/rsession/testing/test_webjs.py ============================================================================== --- py/dist/py/test/rsession/testing/test_webjs.py (original) +++ py/dist/py/test/rsession/testing/test_webjs.py Tue Dec 5 22:42:06 2006 @@ -4,7 +4,7 @@ except ImportError: py.test.skip('missing PyPy') - +from pypy.translator.js.tester import schedule_callbacks here = py.magic.autopath().dirpath() def setup_module(mod): @@ -18,7 +18,9 @@ session_options.bind_config(config) session_options.import_pypy = True from py.__.test.rsession import webjs + from py.__.test.rsession.web import exported_methods mod.webjs = webjs + mod.exported_methods = exported_methods def test_html_loaded(): body = dom.window.document.getElementsByTagName('body')[0] @@ -96,3 +98,25 @@ assert html == 'foo.py[1/10]' assert tds[2].innerHTML == '.' +def test_signal(): + main_t = dom.window.document.getElementById('main_table') + msg = {'type': 'ItemStart', + 'itemtype': 'Module', + 'itemname': 'foo.py', + 'fullitemname': 'modules/foo.py', + 'length': 10, + } + webjs.process(msg) + msg = {'type': 'ReceivedItemOutcome', + 'fullmodulename': 'modules/foo.py', + 'passed' : 'False', + 'fullitemname' : 'modules/foo.py/test_item', + 'hostkey': None, + 'signal': '10', + 'skipped': 'False', + } + webjs.process(msg) + print '%s' % (dom.get_document().documentElement.innerHTML,) + schedule_callbacks(exported_methods) + import pdb;pdb.set_trace() + assert main_t.getElementById('modules/foo.py') Modified: py/dist/py/test/rsession/web.py ============================================================================== --- py/dist/py/test/rsession/web.py (original) +++ py/dist/py/test/rsession/web.py Tue Dec 5 22:42:06 2006 @@ -229,6 +229,10 @@ event.item, outcome.excinfo, outcome.excinfo.traceback) self.stdout[fullitemname] = outcome.stdout self.stderr[fullitemname] = outcome.stderr + elif outcome.signal: + self.fail_reasons[fullitemname] = "Received signal %d" % outcome.signal + self.stdout[fullitemname] = outcome.stdout + self.stderr[fullitemname] = outcome.stderr if event.channel: args['hostkey'] = event.channel.gateway.hostid else: Modified: py/dist/py/test/rsession/webdata/source.js ============================================================================== Binary files. No diff available. Modified: py/dist/py/test/rsession/webjs.py ============================================================================== --- py/dist/py/test/rsession/webjs.py (original) +++ py/dist/py/test/rsession/webjs.py Tue Dec 5 22:42:06 2006 @@ -62,6 +62,76 @@ info = dom.get_document().getElementById("info") info.style.visibility = "hidden" +def make_module_box(msg): + tr = create_elem("tr") + td = create_elem("td") + tr.appendChild(td) + td.appendChild(create_text_elem("%s[0/%s]" % (msg['itemname'], + msg['length']))) + max_items[msg['fullitemname']] = int(msg['length']) + short_item_names[msg['fullitemname']] = msg['itemname'] + td.id = '_txt_' + msg['fullitemname'] + #tr.setAttribute("id", msg['fullitemname']) + td.setAttribute("onmouseover", + "show_info('%s')" % (msg['fullitemname'],)) + td.setAttribute("onmouseout", "hide_info()") + + td2 = create_elem('td') + tr.appendChild(td2) + table = create_elem("table") + td2.appendChild(table) + tbody = create_elem('tbody') + tbody.id = msg['fullitemname'] + table.appendChild(tbody) + counters[msg['fullitemname']] = 0 + return tr + +def add_received_item_outcome(msg, module_part): + if msg['hostkey']: + host_elem = dom.get_document().getElementById(msg['hostkey']) + glob.host_pending[msg['hostkey']].pop() + count = len(glob.host_pending[msg['hostkey']]) + host_elem.childNodes[0].nodeValue = '%s[%s]' % ( + glob.host_dict[msg['hostkey']], count) + + td = create_elem("td") + td.setAttribute("onmouseover", "show_info('%s')" % ( + msg['fullitemname'],)) + td.setAttribute("onmouseout", "hide_info()") + item_name = msg['fullitemname'] + # TODO: dispatch output + if msg["passed"] == 'True': + txt = create_text_elem(".") + td.appendChild(txt) + elif msg["skipped"] != 'None' and msg["skipped"] != "False": + exported_methods.show_skip(item_name, skip_come_back) + link = create_elem("a") + link.setAttribute("href", "javascript:show_skip('%s')" % ( + msg['fullitemname'],)) + txt = create_text_elem('s') + link.appendChild(txt) + td.appendChild(link) + else: + link = create_elem("a") + link.setAttribute("href", "javascript:show_traceback('%s')" % ( + msg['fullitemname'],)) + txt = create_text_elem('F') + link.appendChild(txt) + td.appendChild(link) + exported_methods.show_fail(item_name, fail_come_back) + + if counters[msg['fullmodulename']] % MAX_COUNTER == 0: + tr = create_elem("tr") + module_part.appendChild(tr) + + name = msg['fullmodulename'] + counters[name] += 1 + counter_part = get_elem('_txt_' + name) + newcontent = "%s[%d/%d]" % (short_item_names[name], counters[name], + max_items[name]) + counter_part.childNodes[0].nodeValue = newcontent + module_part.childNodes[-1].appendChild(td) + def process(msg): if len(msg) == 0: return False @@ -71,28 +141,7 @@ if msg['type'] == 'ItemStart': # we start a new directory or what if msg['itemtype'] == 'Module': - tr = create_elem("tr") - td = create_elem("td") - tr.appendChild(td) - td.appendChild(create_text_elem("%s[0/%s]" % (msg['itemname'], - msg['length']))) - max_items[msg['fullitemname']] = int(msg['length']) - short_item_names[msg['fullitemname']] = msg['itemname'] - td.id = '_txt_' + msg['fullitemname'] - #tr.setAttribute("id", msg['fullitemname']) - td.setAttribute("onmouseover", - "show_info('%s')" % (msg['fullitemname'],)) - td.setAttribute("onmouseout", "hide_info()") - - td2 = create_elem('td') - tr.appendChild(td2) - table = create_elem("table") - td2.appendChild(table) - tbody = create_elem('tbody') - tbody.id = msg['fullitemname'] - table.appendChild(tbody) - counters[msg['fullitemname']] = 0 - + tr = make_module_box(msg) main_t.appendChild(tr) elif msg['type'] == 'SendItem': host_elem = dom.get_document().getElementById(msg['hostkey']) @@ -113,50 +162,7 @@ glob.pending.append(msg) return True - if msg['hostkey']: - host_elem = dom.get_document().getElementById(msg['hostkey']) - glob.host_pending[msg['hostkey']].pop() - count = len(glob.host_pending[msg['hostkey']]) - host_elem.childNodes[0].nodeValue = '%s[%s]' % ( - glob.host_dict[msg['hostkey']], count) - - td = create_elem("td") - td.setAttribute("onmouseover", "show_info('%s')" % ( - msg['fullitemname'],)) - td.setAttribute("onmouseout", "hide_info()") - item_name = msg['fullitemname'] - # TODO: dispatch output - if msg["passed"] == 'True': - txt = create_text_elem(".") - td.appendChild(txt) - elif msg["skipped"] != 'None': - exported_methods.show_skip(item_name, skip_come_back) - link = create_elem("a") - link.setAttribute("href", "javascript:show_skip('%s')" % ( - msg['fullitemname'],)) - txt = create_text_elem('s') - link.appendChild(txt) - td.appendChild(link) - else: - link = create_elem("a") - link.setAttribute("href", "javascript:show_traceback('%s')" % ( - msg['fullitemname'],)) - txt = create_text_elem('F') - link.appendChild(txt) - td.appendChild(link) - exported_methods.show_fail(item_name, fail_come_back) - - if counters[msg['fullmodulename']] % MAX_COUNTER == 0: - tr = create_elem("tr") - module_part.appendChild(tr) - - name = msg['fullmodulename'] - counters[name] += 1 - counter_part = get_elem('_txt_' + name) - newcontent = "%s[%d/%d]" % (short_item_names[name], counters[name], - max_items[name]) - counter_part.childNodes[0].nodeValue = newcontent - module_part.childNodes[-1].appendChild(td) + add_received_item_outcome(msg, module_part) elif msg['type'] == 'TestFinished': text = "FINISHED %s run, %s failures, %s skipped" % (msg['run'], msg['fails'], msg['skips']) dom.get_document().title = "Py.test %s" % text From fijal at codespeak.net Tue Dec 5 23:06:19 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Dec 2006 23:06:19 +0100 (CET) Subject: [py-svn] r35347 - in py/dist/py/test/rsession: . testing Message-ID: <20061205220619.DF8C210077@code0.codespeak.net> Author: fijal Date: Tue Dec 5 23:06:12 2006 New Revision: 35347 Modified: py/dist/py/test/rsession/testing/test_webjs.py py/dist/py/test/rsession/web.py Log: Fix tests, add new and increase testability a bit. Modified: py/dist/py/test/rsession/testing/test_webjs.py ============================================================================== --- py/dist/py/test/rsession/testing/test_webjs.py (original) +++ py/dist/py/test/rsession/testing/test_webjs.py Tue Dec 5 23:06:12 2006 @@ -115,8 +115,12 @@ 'signal': '10', 'skipped': 'False', } + exported_methods.fail_reasons['modules/foo.py/test_item'] = 'Received signal 10' + exported_methods.stdout['modules/foo.py/test_item'] = '' + exported_methods.stderr['modules/foo.py/test_item'] = '' webjs.process(msg) print '%s' % (dom.get_document().documentElement.innerHTML,) schedule_callbacks(exported_methods) - import pdb;pdb.set_trace() - assert main_t.getElementById('modules/foo.py') + # ouch + assert dom.get_document().getElementById('modules/foo.py').childNodes[1].\ + childNodes[0].childNodes[0].childNodes[0].nodeValue == 'F' Modified: py/dist/py/test/rsession/web.py ============================================================================== --- py/dist/py/test/rsession/web.py (original) +++ py/dist/py/test/rsession/web.py Tue Dec 5 23:06:12 2006 @@ -152,19 +152,19 @@ def show_hosts(self): self.start_event.wait() - return json.write(self.hosts) + return self.hosts show_hosts = described(retval={"aa": "aa"})(show_hosts) def show_skip(self, item_name="aa"): - return json.write({'item_name': item_name, - 'reason': escape(self.skip_reasons[item_name])}) + return {'item_name': item_name, + 'reason': escape(self.skip_reasons[item_name])} show_skip = described(retval={"aa": "aa"})(show_skip) def show_fail(self, item_name="aa"): - return json.write({'item_name':item_name, + return {'item_name':item_name, 'traceback':escape(str(self.fail_reasons[item_name])), 'stdout':self.stdout[item_name], - 'stderr':self.stderr[item_name]}) + 'stderr':self.stderr[item_name]} show_fail = described(retval={"aa": "aa"})(show_fail) _sessids = None @@ -183,7 +183,7 @@ break finally: self._sesslock.release() - return json.write(sessid) + return sessid show_sessid = described(retval="aa")(show_sessid) def failed(self, **kwargs): @@ -202,7 +202,7 @@ retlist = [self.show_status_change(sessid)] while not self.pending_events.empty_queue(sessid): retlist.append(self.show_status_change(sessid)) - retval = json.write(retlist) + retval = retlist return retval show_all_statuses = described(retval=[{"aa": "aa"}])(show_all_statuses) @@ -347,7 +347,7 @@ else: try: self.serve_data('text/json', - exec_meth(**self.parse_args(getargs))) + json.write(exec_meth(**self.parse_args(getargs)))) except socket.error: # client happily disconnected exported_methods.failed(**self.parse_args(getargs)) From guido at codespeak.net Wed Dec 6 12:11:46 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Wed, 6 Dec 2006 12:11:46 +0100 (CET) Subject: [py-svn] r35370 - py/dist/py/apigen/source Message-ID: <20061206111146.217E710075@code0.codespeak.net> Author: guido Date: Wed Dec 6 12:11:44 2006 New Revision: 35370 Modified: py/dist/py/apigen/source/server.py Log: Added support for browsing directories (not yet styled and such). Modified: py/dist/py/apigen/source/server.py ============================================================================== --- py/dist/py/apigen/source/server.py (original) +++ py/dist/py/apigen/source/server.py Wed Dec 6 12:11:44 2006 @@ -3,9 +3,66 @@ """ import py +import time from pypy.translator.js.examples import server from py.__.apigen.source.browser import parse_path from py.__.apigen.source.html import create_html +from py.xml import html + +def create_dir_html(path): + h = html.html( + html.head( + html.title('directory listing of %s' % (path,)), + ), + ) + body = html.body( + html.h1('directory listing of %s' % (path,)), + ) + h.append(body) + table = html.table() + body.append(table) + tbody = html.tbody() + table.append(tbody) + items = list(path.listdir()) + items.sort(key=lambda p: p.basename) + items.sort(key=lambda p: not p.check(dir=True)) + for fpath in items: + tr = html.tr() + tbody.append(tr) + td1 = html.td(fpath.check(dir=True) and 'D' or 'F') + tr.append(td1) + href = fpath.basename + if fpath.check(dir=True): + href += '/' + td2 = html.td(html.a(fpath.basename, href=href)) + tr.append(td2) + td3 = html.td(time.strftime('%Y-%m-%d %H:%M:%S', + time.gmtime(fpath.mtime()))) + tr.append(td3) + if fpath.check(dir=True): + size = '-' + unit = '' + else: + size = fpath.size() + unit = 'B' + for u in ['kB', 'MB', 'GB', 'TB']: + if size > 1024: + size = round(size / 1024.0, 2) + unit = u + td4 = html.td('%s %s' % (size, unit)) + tr.append(td4) + return unicode(h) + +def create_unknown_html(path): + h = html.html( + html.head( + html.title('Can not display page'), + ), + html.body( + html.p('The data URL (%s) does not contain Python code.' % (path,)) + ), + ) + return h.unicode() class Handler(server.TestHandler): BASE_URL='http://codespeak.net/svn/py/dist' @@ -16,11 +73,20 @@ url = url[:-3] + '.py' path = py.path.svnurl(url) if not path.check(): - raise AttributeError() + def f(rev=None): + return create_unknown_html(path) + f.exposed = True + f.func_name = attr + return f def f(rev='HEAD'): path = py.path.svnurl(url, rev) # some try.. except.. here - return unicode(create_html(parse_path(path))) + if path.check(file=True): + return unicode(create_html(parse_path(path))) + elif path.check(dir=True): + return create_dir_html(path) + else: + return create_unknown_html(path) f.exposed = True f.func_name = attr return f From guido at codespeak.net Wed Dec 6 12:23:08 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Wed, 6 Dec 2006 12:23:08 +0100 (CET) Subject: [py-svn] r35372 - py/dist/py/apigen/source Message-ID: <20061206112308.5D28810079@code0.codespeak.net> Author: guido Date: Wed Dec 6 12:23:07 2006 New Revision: 35372 Modified: py/dist/py/apigen/source/server.py Log: Improved the looks of the dir listing pages a bit. Modified: py/dist/py/apigen/source/server.py ============================================================================== --- py/dist/py/apigen/source/server.py (original) +++ py/dist/py/apigen/source/server.py Wed Dec 6 12:23:07 2006 @@ -9,10 +9,37 @@ from py.__.apigen.source.html import create_html from py.xml import html +style = html.style(""" + + body, p, td { + background-color: #FFF; + color: black; + font-family: monospace; + } + + td.type { + width: 2em; + } + + td.name { + width: 30em; + } + + td.mtime { + width: 13em; + } + + td.size { + text-alignment: right; + } + +""") + def create_dir_html(path): h = html.html( html.head( html.title('directory listing of %s' % (path,)), + style, ), ) body = html.body( @@ -29,18 +56,18 @@ for fpath in items: tr = html.tr() tbody.append(tr) - td1 = html.td(fpath.check(dir=True) and 'D' or 'F') + td1 = html.td(fpath.check(dir=True) and 'D' or 'F', class_='type') tr.append(td1) href = fpath.basename if fpath.check(dir=True): href += '/' - td2 = html.td(html.a(fpath.basename, href=href)) + td2 = html.td(html.a(fpath.basename, href=href), class_='name') tr.append(td2) td3 = html.td(time.strftime('%Y-%m-%d %H:%M:%S', - time.gmtime(fpath.mtime()))) + time.gmtime(fpath.mtime())), class_='mtime') tr.append(td3) if fpath.check(dir=True): - size = '-' + size = '' unit = '' else: size = fpath.size() @@ -49,7 +76,7 @@ if size > 1024: size = round(size / 1024.0, 2) unit = u - td4 = html.td('%s %s' % (size, unit)) + td4 = html.td('%s %s' % (size, unit), class_='size') tr.append(td4) return unicode(h) @@ -57,6 +84,7 @@ h = html.html( html.head( html.title('Can not display page'), + style, ), html.body( html.p('The data URL (%s) does not contain Python code.' % (path,)) From guido at codespeak.net Wed Dec 6 12:37:20 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Wed, 6 Dec 2006 12:37:20 +0100 (CET) Subject: [py-svn] r35375 - py/dist/py/apigen/source Message-ID: <20061206113720.3E01E1007B@code0.codespeak.net> Author: guido Date: Wed Dec 6 12:37:19 2006 New Revision: 35375 Modified: py/dist/py/apigen/source/server.py Log: Now also capable of displaying /. Modified: py/dist/py/apigen/source/server.py ============================================================================== --- py/dist/py/apigen/source/server.py (original) +++ py/dist/py/apigen/source/server.py Wed Dec 6 12:37:19 2006 @@ -96,6 +96,8 @@ BASE_URL='http://codespeak.net/svn/py/dist' def __getattr__(self, attr): + if attr == 'index': + attr = '' url = self.BASE_URL + "/" + attr if url.endswith('_py'): url = url[:-3] + '.py' From fijal at codespeak.net Wed Dec 6 12:38:02 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 6 Dec 2006 12:38:02 +0100 (CET) Subject: [py-svn] r35376 - in py/dist/py/apigen/source: . testing Message-ID: <20061206113802.6A14A1007B@code0.codespeak.net> Author: fijal Date: Wed Dec 6 12:38:01 2006 New Revision: 35376 Modified: py/dist/py/apigen/source/browser.py py/dist/py/apigen/source/testing/test_browser.py Log: A fix and a test. Modified: py/dist/py/apigen/source/browser.py ============================================================================== --- py/dist/py/apigen/source/browser.py (original) +++ py/dist/py/apigen/source/browser.py Wed Dec 6 12:38:01 2006 @@ -60,7 +60,7 @@ return cls(ast.name, startline, endline) def class_from_ast(cls_ast): - bases = [i.name for i in cls_ast.bases] + bases = [i.name for i in cls_ast.bases if isinstance(i, ast.Name)] # XXX methods = {} startline = cls_ast.lineno Modified: py/dist/py/apigen/source/testing/test_browser.py ============================================================================== --- py/dist/py/apigen/source/testing/test_browser.py (original) +++ py/dist/py/apigen/source/testing/test_browser.py Wed Dec 6 12:38:01 2006 @@ -52,3 +52,13 @@ mod = parse_path(tmp.join("b.py")) assert isinstance(mod.f, Function) py.test.raises(AttributeError, 'mod.g') + +def test_bases(): + tmp = py.test.ensuretemp("sourcebrowser") + tmp.ensure("c.py").write(py.code.Source(""" + import py + class Dir(py.test.collect.Directory): + pass + """)) + mod = parse_path(tmp.join("c.py")) + # if it does not rise it's ok for now From fijal at codespeak.net Wed Dec 6 12:45:53 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 6 Dec 2006 12:45:53 +0100 (CET) Subject: [py-svn] r35379 - py/dist/py/documentation Message-ID: <20061206114553.ADD4E10077@code0.codespeak.net> Author: fijal Date: Wed Dec 6 12:45:52 2006 New Revision: 35379 Modified: py/dist/py/documentation/source-viewer.txt Log: Make more human-readable format Modified: py/dist/py/documentation/source-viewer.txt ============================================================================== --- py/dist/py/documentation/source-viewer.txt (original) +++ py/dist/py/documentation/source-viewer.txt Wed Dec 6 12:45:52 2006 @@ -2,44 +2,43 @@ Source viewer for pylib ======================= -Random notes: -------------- +Purpose: +-------- -* We want to construct this using an AST. Introspection is somehow better in - many many places, but an AST is more sticked to source (which is by - conincidence what we actually want to see). Additional stuff like things - attached to the module might be nice if we want to document them, but - they do not appear in source. - -* We want to have rather free (without all AST hassle) access to basic - info about classess, functions variables etc. So we can get all the - necessary informations even if the module has changed a bit. - -* We want this access for both SVN and file based sources. - -* We want to have html backend of those - which means at least syntax - highlightning with possibility of linking to those items. - -* Some crosslinking might be cool, variables are resolved syntactically, - so in 95% cases we can crossling to at least module.function, module.class - etc. - -* First: We don't want to have *ANY* type inference there. Two: If at - any point we want such thing, we make it through introspection, but better - not at all. - -Implementation notes: ---------------------- - -Let's use compiler package and if at any point there will be sth better, -like pypy's compiler package we'll move. We create out of AST stuff which -can be accessed by dot. Like module.function.firstlineno, with interface -to py.code.Source as well. - -We can use introspection for some aspects. Right now only top-level functions -and classes (not laying inside if and such) are exposed. We can use -introspection to check which functions are exposed at a module level -(all the ifs and such are executed ususally during initialisation of -module, so we'll have all of necessary informations). Also we can check -if elements was not overwritten, or has changed name by compiling code -and checking. +As usual, main driving force to develop sth new is lack of several +possibilities between existing solutions. Major lack of features are: + +* Impossible to link to certain function like http://filename#function_name + +* Impossible to properly link - most informations coming from AST + +* We want this to nicely integrate with apigen - so crosslinking from + one to another makes sense (also backwards - like info for a function) + +Idea: +----- + +Basic idea is to take module as a py.path object, compile it (using compiler +module), than try to get some information and eventually import it and +get even some more information. Importing is optional and can be not performed +at all, but:: + + if 1: + def f(x): + pass + if 0: + def g(x): + pass + +could be only parsed well in case of importing stuff. There are also plans for +integrating more features ie. caching it by code and attaching a name to a code +generated by some magic functions. + +Status: +------- + +Right now there is ready `server`_ and along with an `API viewer`_. Next step +is to improve a look & feel of API viewer and to link one to another. + +.. _`server`: http://johnnydebris.net:8000/py/test/collect.py#Collector +.. _`API viewer`: http://johnnydebris.net/xxx From fijal at codespeak.net Wed Dec 6 12:47:08 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 6 Dec 2006 12:47:08 +0100 (CET) Subject: [py-svn] r35380 - py/dist/py/documentation Message-ID: <20061206114708.CE7F010079@code0.codespeak.net> Author: fijal Date: Wed Dec 6 12:47:07 2006 New Revision: 35380 Modified: py/dist/py/documentation/apigen.txt Log: Reviewed a bit, quite ok for me. Modified: py/dist/py/documentation/apigen.txt ============================================================================== --- py/dist/py/documentation/apigen.txt (original) +++ py/dist/py/documentation/apigen.txt Wed Dec 6 12:47:07 2006 @@ -99,11 +99,11 @@ class called 'ApiGen' in your conftest (see the `py.test documentation`_ for more details about conftest files) that implements a set of special methods called 'get_doc_storage()' and 'write_docs()', that essentially implement the -functionality discussed above. Calling py.test with an --apigen (only works -when --session is used) argument will cause the methods to be called. +functionality discussed above. Calling py.test with an --apigen + argument will cause the methods to be called. For an example, see the 'conftest.py' file in the py lib itself. To see it in -action you run `py.test --session=L --apigen` in the root of the py lib; this +action you run `py.test --apigen` in the root of the py lib; this will result in documentation (in HTML) being written to /tmp/output. Comparison with other documentation generation tools From guido at codespeak.net Wed Dec 6 14:32:23 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Wed, 6 Dec 2006 14:32:23 +0100 (CET) Subject: [py-svn] r35393 - in py/dist/py/apigen: . rest Message-ID: <20061206133223.BF24510083@code0.codespeak.net> Author: guido Date: Wed Dec 6 14:32:22 2006 New Revision: 35393 Modified: py/dist/py/apigen/apigen.js py/dist/py/apigen/rest/htmlhandlers.py Log: Added small hack to allow bookmarking individual pages (using # in urls). Modified: py/dist/py/apigen/apigen.js ============================================================================== --- py/dist/py/apigen/apigen.js (original) +++ py/dist/py/apigen/apigen.js Wed Dec 6 14:32:22 2006 @@ -26,3 +26,25 @@ }; }; }; + +function set_location(el) { + var currloc = document.location.toString(); + var url = currloc; + if (currloc.indexOf('#') > -1) { + var chunks = currloc.split('#'); + url = chunks[0]; + }; + document.location = url + '#' + escape(el.getAttribute('href')); +}; + +function loadloc() { + /* load iframe content using # part of the url */ + var loc = document.location.toString(); + if (loc.indexOf('#') == -1) { + return; + }; + var chunks = loc.split('#'); + var anchor = chunks[chunks.length - 1]; + var iframe = document.getElementsByTagName('iframe')[0]; + iframe.src = anchor; +}; Modified: py/dist/py/apigen/rest/htmlhandlers.py ============================================================================== --- py/dist/py/apigen/rest/htmlhandlers.py (original) +++ py/dist/py/apigen/rest/htmlhandlers.py Wed Dec 6 14:32:22 2006 @@ -10,7 +10,8 @@ def handleLink(self, text, target): self.tagstack[-1].append(html.a(text, href=target, - onclick='parent.set_breadcrumb(this)', + onclick=('parent.set_breadcrumb(this);' + 'parent.set_location(this);'), target='content')) @@ -21,7 +22,8 @@ super(IndexHandler, self).startDocument() self.head.append(html.script(type='text/javascript', src='apigen.js')) self.body.attr.onload = ('set_breadcrumb(' - 'document.getElementsByTagName("a")[0])') + 'document.getElementsByTagName("a")[0]);' + 'loadloc();') self._push(html.div(id='sidebar')) def endDocument(self): From guido at codespeak.net Wed Dec 6 16:26:04 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Wed, 6 Dec 2006 16:26:04 +0100 (CET) Subject: [py-svn] r35400 - py/dist/py/documentation Message-ID: <20061206152604.014F410087@code0.codespeak.net> Author: guido Date: Wed Dec 6 16:26:04 2006 New Revision: 35400 Modified: py/dist/py/documentation/source-viewer.txt Log: Fixed links. Modified: py/dist/py/documentation/source-viewer.txt ============================================================================== --- py/dist/py/documentation/source-viewer.txt (original) +++ py/dist/py/documentation/source-viewer.txt Wed Dec 6 16:26:04 2006 @@ -40,5 +40,5 @@ Right now there is ready `server`_ and along with an `API viewer`_. Next step is to improve a look & feel of API viewer and to link one to another. -.. _`server`: http://johnnydebris.net:8000/py/test/collect.py#Collector -.. _`API viewer`: http://johnnydebris.net/xxx +.. _`server`: http://johnnydebris.net:8000/ +.. _`API viewer`: http://johnnydebris.net/pyapi From fijal at codespeak.net Wed Dec 6 18:27:59 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 6 Dec 2006 18:27:59 +0100 (CET) Subject: [py-svn] r35406 - py/dist/py/test/rsession Message-ID: <20061206172759.9507910080@code0.codespeak.net> Author: fijal Date: Wed Dec 6 18:27:56 2006 New Revision: 35406 Modified: py/dist/py/test/rsession/rest.py Log: Don't show unknow results when verbose is not on. Modified: py/dist/py/test/rsession/rest.py ============================================================================== --- py/dist/py/test/rsession/rest.py (original) +++ py/dist/py/test/rsession/rest.py Wed Dec 6 18:27:56 2006 @@ -22,7 +22,8 @@ return self.linkwriter def report_unknown(self, what): - self.add_rest(Paragraph("Unknown report: %s" % what)) + if self.config.option.verbose: + self.add_rest(Paragraph("Unknown report: %s" % what)) def report_SendItem(self, item): address = self.get_host(item) From fijal at codespeak.net Wed Dec 6 18:29:40 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 6 Dec 2006 18:29:40 +0100 (CET) Subject: [py-svn] r35407 - py/dist/py/test/rsession/testing Message-ID: <20061206172940.DB0F810080@code0.codespeak.net> Author: fijal Date: Wed Dec 6 18:29:39 2006 New Revision: 35407 Modified: py/dist/py/test/rsession/testing/test_rest.py Log: And fix a test. Modified: py/dist/py/test/rsession/testing/test_rest.py ============================================================================== --- py/dist/py/test/rsession/testing/test_rest.py (original) +++ py/dist/py/test/rsession/testing/test_rest.py Wed Dec 6 18:29:39 2006 @@ -27,6 +27,7 @@ def setup_method(self, method): config, args = py.test.Config.parse(["some_sub"]) config.option.verbose = False + self.config = config method.im_func.func_globals['reporter'] = r = RestReporter(config, ['localhost']) method.im_func.func_globals['stdout'] = s = py.std.StringIO.StringIO() @@ -34,8 +35,10 @@ r.linkwriter = NoLinkWriter() def test_report_unknown(self): + self.config.option.verbose = True reporter.report_unknown('foo') assert stdout.getvalue() == 'Unknown report\\: foo\n\n' + self.config.option.verbose = False def test_report_SendItem(self): item = Container(item='foo/bar.py', channel=False) From guido at codespeak.net Thu Dec 7 12:50:18 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Thu, 7 Dec 2006 12:50:18 +0100 (CET) Subject: [py-svn] r35428 - py/dist/py/rest Message-ID: <20061207115018.B129B10089@code0.codespeak.net> Author: guido Date: Thu Dec 7 12:50:16 2006 New Revision: 35428 Modified: py/dist/py/rest/transform.py Log: Added missing handleStrong() method on html handler. Modified: py/dist/py/rest/transform.py ============================================================================== --- py/dist/py/rest/transform.py (original) +++ py/dist/py/rest/transform.py Thu Dec 7 12:50:16 2006 @@ -151,6 +151,9 @@ def handleEm(self, text): self.tagstack[-1].append(html.em(text)) + def handleStrong(self, text): + self.tagstack[-1].append(html.strong(text)) + def startListItem(self, type, startlist): if startlist: nodename = type == 'o' and 'ol' or 'ul' From fijal at codespeak.net Thu Dec 7 16:04:47 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 7 Dec 2006 16:04:47 +0100 (CET) Subject: [py-svn] r35439 - in py/dist/py/apigen/rest: . testing Message-ID: <20061207150447.DF8F91009B@code0.codespeak.net> Author: fijal Date: Thu Dec 7 16:04:45 2006 New Revision: 35439 Modified: py/dist/py/apigen/rest/genrest.py py/dist/py/apigen/rest/testing/test_rest.py Log: Added SourceView link viewer Modified: py/dist/py/apigen/rest/genrest.py ============================================================================== --- py/dist/py/apigen/rest/genrest.py (original) +++ py/dist/py/apigen/rest/genrest.py Thu Dec 7 16:04:45 2006 @@ -17,16 +17,9 @@ There should exist various classes for that, different for Trac, different for CVSView, etc. """ - def getlink(self, filename, lineno): + def getlink(self, filename, lineno, funcname): raise NotImplementedError("Abstract link writer") -class ViewVC(AbstractLinkWriter): - """ Link writer for ViewVC version control viewer - """ - def __init__(self, basepath): - # XXX: should try to guess from a working copy of svn - self.basepath = basepath - def getpkgpath(self, filename): # XXX: very simple thing path = py.path.local(filename).dirpath() @@ -37,7 +30,14 @@ except py.error.ENOENT: return path - def getlink(self, filename, lineno): +class ViewVC(AbstractLinkWriter): + """ Link writer for ViewVC version control viewer + """ + def __init__(self, basepath): + # XXX: should try to guess from a working copy of svn + self.basepath = basepath + + def getlink(self, filename, lineno, funcname): path = str(self.getpkgpath(filename)) assert filename.startswith(path), ( "%s does not belong to package %s" % (filename, path)) @@ -49,17 +49,34 @@ relname = relname.replace(sep, '/') return ('%s:%s' % (filename, lineno), self.basepath + relname[1:] + '?view=markup') + +class SourceView(AbstractLinkWriter): + def __init__(self, baseurl): + self.baseurl = baseurl + + def getlink(self, filename, lineno, funcname): + pkgpath = self.getpkgpath(filename) + assert filename.startswith(str(pkgpath)), ( + "%s does not belong to package %s" % (filename, pkgpath)) + relname = filename[len(str(pkgpath)):] + if relname.endswith('.pyc'): + relname = relname[:-1] + sep = py.std.os.sep + if sep != '/': + relname = relname.replace(sep, '/') + return "%s:%s" % (relname, funcname),\ + "%s%s#%s" % (self.baseurl, relname, funcname) class DirectPaste(AbstractLinkWriter): """ No-link writer (inliner) """ - def getlink(self, filename, lineno): + def getlink(self, filename, lineno, funcname): return ('%s:%s' % (filename, lineno), "") class DirectFS(AbstractLinkWriter): """ Creates links to the files on the file system (for local docs) """ - def getlink(self, filename, lineno): + def getlink(self, filename, lineno, funcname): return ('%s:%s' % (filename, lineno), 'file://%s' % (filename,)) class PipeWriter(object): @@ -446,7 +463,8 @@ for line in call_site: lineno = line.lineno - line.code.firstlineno linkname, linktarget = self.linkgen.getlink(line.code.filename, - line.lineno + 1) + line.lineno + 1, + funcname) if linktarget: tbrest.append(Paragraph(Link(linkname, linktarget))) else: Modified: py/dist/py/apigen/rest/testing/test_rest.py ============================================================================== --- py/dist/py/apigen/rest/testing/test_rest.py (original) +++ py/dist/py/apigen/rest/testing/test_rest.py Thu Dec 7 16:04:45 2006 @@ -8,7 +8,7 @@ from py.__.apigen.rest.genrest import ViewVC, RestGen, PipeWriter, \ DirWriter, FileWriter, \ DirectPaste, DirectFS, \ - HTMLDirWriter + HTMLDirWriter, SourceView from py.__.apigen.tracer.tracer import Tracer from py.__.apigen.tracer.docstorage import DocStorage @@ -61,20 +61,20 @@ def test_direct_link(): fname = cut_pyc(__file__) - title, link = DirectPaste().getlink(fname, 2) + title, link = DirectPaste().getlink(fname, 2, "") assert title == '%s:%s' % (fname, 2) assert link == '' def test_viewvc_link(): vcview = ViewVC("http://codespeak.net/viewvc/") fname = cut_pyc(__file__) - title, link = vcview.getlink(fname, 0) + title, link = vcview.getlink(fname, 0, "") assert title == '%s:%s' % (fname, 0) assert link == ('http://codespeak.net/viewvc/py/apigen/rest/' 'testing/test_rest.py?view=markup') def test_fs_link(): - title, link = DirectFS().getlink('/foo/bar/baz.py', 100) + title, link = DirectFS().getlink('/foo/bar/baz.py', 100, "func") assert title == '/foo/bar/baz.py:100' assert link == 'file:///foo/bar/baz.py' @@ -417,3 +417,23 @@ r = RestGen(ds, lg, DirWriter(tempdir)) r.write() self.check_rest(tempdir) + + def test_sourceview(self): + class A: + def method(self): + pass + + descs = {'A':A} + ds = DocStorage().from_dict(descs) + t = Tracer(ds) + t.start_tracing() + A().method() + t.end_tracing() + lg = SourceView('http://localhost:8000') + tempdir = temppath.ensure("sourceview", dir=True) + r = RestGen(ds, lg, DirWriter(tempdir)) + r.write() + self.check_rest(tempdir) + assert tempdir.join('traceback_A.method.0.txt').open().read().find( + '.. _`/py/apigen/rest/testing/test\_rest.py\:A.method`: http://localhost:8000/py/apigen/rest/testing/test_rest.py#A.method') != -1 + From fijal at codespeak.net Thu Dec 7 17:26:16 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 7 Dec 2006 17:26:16 +0100 (CET) Subject: [py-svn] r35443 - py/dist/py Message-ID: <20061207162616.95FAF1008D@code0.codespeak.net> Author: fijal Date: Thu Dec 7 17:26:15 2006 New Revision: 35443 Modified: py/dist/py/conftest.py Log: Fixed to sourceview Modified: py/dist/py/conftest.py ============================================================================== --- py/dist/py/conftest.py (original) +++ py/dist/py/conftest.py Thu Dec 7 17:26:15 2006 @@ -34,10 +34,10 @@ def write_docs(ds): from py.__.apigen.rest.genrest import DirectPaste, RestGen, \ - HTMLDirWriter + HTMLDirWriter, SourceView from py.__.apigen.rest.htmlhandlers import IndexHandler, PageHandler outdir = py.path.local('/tmp/output') - RestGen(ds, DirectPaste(), + RestGen(ds, SourceView("http://johnnydebris.net:8000/"), HTMLDirWriter(IndexHandler, PageHandler, outdir)).write() if not outdir.join('style.css').check(): py.magic.autopath().dirpath().join('apigen/style.css').copy(outdir) From fijal at codespeak.net Thu Dec 7 17:26:33 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 7 Dec 2006 17:26:33 +0100 (CET) Subject: [py-svn] r35444 - py/dist/py/apigen/rest Message-ID: <20061207162633.A830B1008D@code0.codespeak.net> Author: fijal Date: Thu Dec 7 17:26:31 2006 New Revision: 35444 Modified: py/dist/py/apigen/rest/genrest.py Log: Fix Modified: py/dist/py/apigen/rest/genrest.py ============================================================================== --- py/dist/py/apigen/rest/genrest.py (original) +++ py/dist/py/apigen/rest/genrest.py Thu Dec 7 17:26:31 2006 @@ -53,11 +53,17 @@ class SourceView(AbstractLinkWriter): def __init__(self, baseurl): self.baseurl = baseurl + if self.baseurl.endswith("/"): + self.baseurl = baseurl[:-1] def getlink(self, filename, lineno, funcname): + if filename is None: + return ":%s" % funcname,"" pkgpath = self.getpkgpath(filename) - assert filename.startswith(str(pkgpath)), ( - "%s does not belong to package %s" % (filename, pkgpath)) + if not filename.startswith(str(pkgpath)): + # let's leave it + return ":%s" % funcname,"" + relname = filename[len(str(pkgpath)):] if relname.endswith('.pyc'): relname = relname[:-1] From guido at codespeak.net Thu Dec 7 21:41:15 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Thu, 7 Dec 2006 21:41:15 +0100 (CET) Subject: [py-svn] r35458 - py/dist/py/documentation Message-ID: <20061207204115.8DECE10084@code0.codespeak.net> Author: guido Date: Thu Dec 7 21:41:13 2006 New Revision: 35458 Modified: py/dist/py/documentation/apigen.txt Log: Fixed indentation error. Modified: py/dist/py/documentation/apigen.txt ============================================================================== --- py/dist/py/documentation/apigen.txt (original) +++ py/dist/py/documentation/apigen.txt Thu Dec 7 21:41:13 2006 @@ -100,7 +100,7 @@ more details about conftest files) that implements a set of special methods called 'get_doc_storage()' and 'write_docs()', that essentially implement the functionality discussed above. Calling py.test with an --apigen - argument will cause the methods to be called. +argument will cause the methods to be called. For an example, see the 'conftest.py' file in the py lib itself. To see it in action you run `py.test --apigen` in the root of the py lib; this From fijal at codespeak.net Fri Dec 8 11:40:51 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 8 Dec 2006 11:40:51 +0100 (CET) Subject: [py-svn] r35468 - in py/dist/py/test/rsession: . testing Message-ID: <20061208104051.A9A2B10070@code0.codespeak.net> Author: fijal Date: Fri Dec 8 11:40:49 2006 New Revision: 35468 Modified: py/dist/py/test/rsession/rest.py py/dist/py/test/rsession/testing/test_rest.py Log: Fixed --rest a bit, by adding links to tracebacks. Modified: py/dist/py/test/rsession/rest.py ============================================================================== --- py/dist/py/test/rsession/rest.py (original) +++ py/dist/py/test/rsession/rest.py Fri Dec 8 11:40:49 2006 @@ -15,6 +15,7 @@ def __init__(self, *args, **kwargs): super(RestReporter, self).__init__(*args, **kwargs) self.rest = Rest() + self.traceback_num = 0 def get_linkwriter(self): if self.linkwriter is None: @@ -71,14 +72,14 @@ return root.fspath def print_summary(self, total, skipped_str, failed_str): + self.skips() + self.failures() + txt = "%d tests run%s%s in %.2fs (rsync: %.2f)" % \ (total, skipped_str, failed_str, self.timeend - self.timestart, self.timersync - self.timestart) self.add_rest(Title(txt, belowchar='-')) - self.skips() - self.failures() - # since we're rendering each item, the links haven't been rendered # yet self.out.write(self.rest.render_links()) @@ -86,20 +87,22 @@ def report_ReceivedItemOutcome(self, event): host = self.get_host(event) if event.outcome.passed: - status = "PASSED" + status = [Strong("PASSED")] self.passed[host] += 1 elif event.outcome.skipped: - status = "SKIPPED" + status = [Strong("SKIPPED")] self.skipped_tests_outcome.append(event) self.skipped[host] += 1 else: - status = "FAILED" + status = [Strong("FAILED"), + InternalLink("traceback%d" % self.traceback_num)] + self.traceback_num += 1 self.failed[host] += 1 self.failed_tests_outcome.append(event) # we'll take care of them later itempath = self.get_path_from_item(event.item) - self.add_rest(ListItem(Text("%10s:" % (host[:10],)), Strong(status), - Text(itempath))) + status.append(Text(itempath)) + self.add_rest(ListItem(Text("%10s:" % (host[:10],)), *status)) def skips(self): # XXX hrmph, copied code @@ -124,6 +127,7 @@ self.add_rest(ListItem('%s: %s' % (item, text))) def failures(self): + self.traceback_num = 0 tbstyle = self.config.option.tbstyle if self.failed_tests_outcome: self.add_rest(Title('Exceptions:', belowchar='+')) @@ -189,6 +193,8 @@ def repr_traceback(self, item, excinfo, traceback, style): root = self.get_rootpath(item) + self.add_rest(LinkTarget('traceback%d' % self.traceback_num, "")) + self.traceback_num += 1 if style == 'long': for entry in traceback: link = self.get_linkwriter().get_link(root, Modified: py/dist/py/test/rsession/testing/test_rest.py ============================================================================== --- py/dist/py/test/rsession/testing/test_rest.py (original) +++ py/dist/py/test/rsession/testing/test_rest.py Fri Dec 8 11:40:49 2006 @@ -123,7 +123,7 @@ event = Container(channel=False, outcome=outcome, item=item) reporter.report_ReceivedItemOutcome(event) assert stdout.getvalue() == """\ -* localhost\: **FAILED** foo.py/bar()/baz +* localhost\: **FAILED** `traceback0`_ foo.py/bar()/baz """ @@ -184,13 +184,16 @@ ] reporter.config.option.tbstyle = 'no' reporter.failures() - assert stdout.getvalue() == """\ + expected = """\ Exceptions\: ++++++++++++ foo/bar.py/baz() on localhost +++++++++++++++++++++++++++++ +.. _`traceback0`: + + FooError ++++++++ @@ -199,18 +202,22 @@ A foo has occurred """ + assert stdout.getvalue() == expected reporter.config.option.tbstyle = 'short' stdout.seek(0) stdout.truncate() reporter.failures() - assert stdout.getvalue() == """\ + expected = """\ Exceptions\: ++++++++++++ foo/bar.py/baz() on localhost +++++++++++++++++++++++++++++ +.. _`traceback0`: + + :: foo/bar.py line 1 @@ -226,18 +233,22 @@ A foo has occurred """ + assert stdout.getvalue() == expected reporter.config.option.tbstyle = 'long' stdout.seek(0) stdout.truncate() reporter.failures() - stdout.getvalue() == """\ + expected = """\ Exceptions\: ++++++++++++ foo/bar.py/baz() on localhost +++++++++++++++++++++++++++++ +.. _`traceback0`: + + +++++++++++++++++ foo/bar.py line 1 +++++++++++++++++ @@ -262,6 +273,8 @@ A foo has occurred """ + assert stdout.getvalue() == expected + class TestRestReporter(AbstractTestReporter): reporter = RestReporter @@ -272,11 +285,11 @@ def test_report_received_item_outcome(self): val = self.report_received_item_outcome() expected = """\ -* localhost\: **FAILED** py/test/rsession/testing/test\_slave.py/funcpass +* localhost\: **FAILED** `traceback0`_\n py/test/rsession/testing/test\_slave.py/funcpass * localhost\: **SKIPPED** py/test/rsession/testing/test\_slave.py/funcpass -* localhost\: **FAILED** py/test/rsession/testing/test\_slave.py/funcpass +* localhost\: **FAILED** `traceback1`_\n py/test/rsession/testing/test\_slave.py/funcpass * localhost\: **PASSED** py/test/rsession/testing/test\_slave.py/funcpass From fijal at codespeak.net Fri Dec 8 12:06:13 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 8 Dec 2006 12:06:13 +0100 (CET) Subject: [py-svn] r35469 - py/dist/py/test/rsession/testing Message-ID: <20061208110613.1D96610070@code0.codespeak.net> Author: fijal Date: Fri Dec 8 12:06:11 2006 New Revision: 35469 Modified: py/dist/py/test/rsession/testing/test_webjs.py Log: Removed debug print. Modified: py/dist/py/test/rsession/testing/test_webjs.py ============================================================================== --- py/dist/py/test/rsession/testing/test_webjs.py (original) +++ py/dist/py/test/rsession/testing/test_webjs.py Fri Dec 8 12:06:11 2006 @@ -89,7 +89,6 @@ 'hostkey': None, } webjs.process(msg) - print '%s' % (dom.get_document().documentElement.innerHTML,) trs = main_t.getElementsByTagName('tr') tds = trs[0].getElementsByTagName('td') # two cells in the row, one in the table inside one of the cells @@ -119,7 +118,6 @@ exported_methods.stdout['modules/foo.py/test_item'] = '' exported_methods.stderr['modules/foo.py/test_item'] = '' webjs.process(msg) - print '%s' % (dom.get_document().documentElement.innerHTML,) schedule_callbacks(exported_methods) # ouch assert dom.get_document().getElementById('modules/foo.py').childNodes[1].\ From fijal at codespeak.net Fri Dec 8 12:12:31 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 8 Dec 2006 12:12:31 +0100 (CET) Subject: [py-svn] r35470 - py/dist/py/misc/testing Message-ID: <20061208111231.9A41E10070@code0.codespeak.net> Author: fijal Date: Fri Dec 8 12:12:30 2006 New Revision: 35470 Modified: py/dist/py/misc/testing/test_simplecapture.py Log: Added s[kip for hanging test Modified: py/dist/py/misc/testing/test_simplecapture.py ============================================================================== --- py/dist/py/misc/testing/test_simplecapture.py (original) +++ py/dist/py/misc/testing/test_simplecapture.py Fri Dec 8 12:12:30 2006 @@ -85,5 +85,8 @@ assert err.startswith("4") class TestCapturingOnFDs(TestCapturingOnSys): + def test_reading_stdin_while_captured_doesnt_hang(self): + py.test.skip("Hangs in py.test --session=R") + def getcapture(self): return Capture() From fijal at codespeak.net Fri Dec 8 12:14:13 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 8 Dec 2006 12:14:13 +0100 (CET) Subject: [py-svn] r35471 - py/dist/py/rest Message-ID: <20061208111413.4BF3C10070@code0.codespeak.net> Author: fijal Date: Fri Dec 8 12:14:11 2006 New Revision: 35471 Modified: py/dist/py/rest/rst.py Log: Added two simple classes. Modified: py/dist/py/rest/rst.py ============================================================================== --- py/dist/py/rest/rst.py (original) +++ py/dist/py/rest/rst.py Fri Dec 8 12:14:11 2006 @@ -351,6 +351,18 @@ next = next.parent return next +class InternalLink(AbstractText): + start = '`' + end = '`_' + +class LinkTarget(Paragraph): + def __init__(self, name, target): + self.name = name + self.target = target + + def text(self): + return ".. _`%s`:%s\n" % (self.name, self.target) + class Substitution(AbstractText): def __init__(self, text, **kwargs): raise NotImplemented('XXX') From guido at codespeak.net Fri Dec 8 13:26:06 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Fri, 8 Dec 2006 13:26:06 +0100 (CET) Subject: [py-svn] r35475 - py/dist/py/test/rsession Message-ID: <20061208122606.87E5710070@code0.codespeak.net> Author: guido Date: Fri Dec 8 13:26:04 2006 New Revision: 35475 Modified: py/dist/py/test/rsession/rsession.py Log: Doing too much work in an except body, which made that errors in apigen code got reported strangely. Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Fri Dec 8 13:26:04 2006 @@ -280,7 +280,9 @@ if self.config.option.apigen: try: - self.config.getinitialvalue('ApiGen').write_docs(self.docstorage) + apigen = self.config.getinitialvalue('ApiGen') except ValueError: raise NotImplementedError("Cannot create docs - didn't " "provided way of doing that in conftest") + else: + apigen.write_docs(self.docstorage) From guido at codespeak.net Fri Dec 8 14:02:01 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Fri, 8 Dec 2006 14:02:01 +0100 (CET) Subject: [py-svn] r35476 - in py/dist/py/apigen: . rest rest/testing Message-ID: <20061208130201.595F110077@code0.codespeak.net> Author: guido Date: Fri Dec 8 14:02:00 2006 New Revision: 35476 Added: py/dist/py/apigen/rest/testing/test_htmlhandlers.py Modified: py/dist/py/apigen/apigen.js py/dist/py/apigen/rest/htmlhandlers.py py/dist/py/apigen/style.css Log: Removed # hack (mostly, if possible I want to add something similar, but less intrusive, later), fixed breadcrumbs by generating them from the filename (on the server) instead of adding bits on navigation. Modified: py/dist/py/apigen/apigen.js ============================================================================== --- py/dist/py/apigen/apigen.js (original) +++ py/dist/py/apigen/apigen.js Fri Dec 8 14:02:00 2006 @@ -1,42 +1,3 @@ -var anchors = []; -function set_breadcrumb(el) { - var breadcrumb = document.getElementById('breadcrumb'); - var href = el.href; - if (href.indexOf('module_') > -1) { - anchors = []; - }; - for (var i=0; i < anchors.length; i++) { - if (anchors[i].href == href) { - anchors = anchors.slice(0, i); - }; - }; - var clone = el.cloneNode(true); - if (anchors.length && clone.childNodes[0].nodeValue.indexOf('.') > -1) { - var chunks = clone.childNodes[0].nodeValue.split('.'); - clone.childNodes[0].nodeValue = chunks[chunks.length - 1]; - }; - anchors.push(clone); - while (breadcrumb.hasChildNodes()) { - breadcrumb.removeChild(breadcrumb.childNodes[0]); - }; - for (var i=0; i < anchors.length; i++) { - breadcrumb.appendChild(anchors[i]); - if (i < anchors.length - 1) { - breadcrumb.appendChild(document.createTextNode('.')); - }; - }; -}; - -function set_location(el) { - var currloc = document.location.toString(); - var url = currloc; - if (currloc.indexOf('#') > -1) { - var chunks = currloc.split('#'); - url = chunks[0]; - }; - document.location = url + '#' + escape(el.getAttribute('href')); -}; - function loadloc() { /* load iframe content using # part of the url */ var loc = document.location.toString(); Modified: py/dist/py/apigen/rest/htmlhandlers.py ============================================================================== --- py/dist/py/apigen/rest/htmlhandlers.py (original) +++ py/dist/py/apigen/rest/htmlhandlers.py Fri Dec 8 14:02:00 2006 @@ -1,19 +1,60 @@ from py.__.rest.transform import HTMLHandler, entitize -from py.xml import html +from py.xml import html, raw class PageHandler(HTMLHandler): def startDocument(self): - self.title = 'api reference' super(PageHandler, self).startDocument() self.head.append(html.link(type='text/css', rel='stylesheet', href='style.css')) + title = self.title[0] + breadcrumb = ''.join([unicode(el) for el in self.breadcrumb(title)]) + self.body.append(html.div(raw(breadcrumb), class_='breadcrumb')) def handleLink(self, text, target): self.tagstack[-1].append(html.a(text, href=target, - onclick=('parent.set_breadcrumb(this);' - 'parent.set_location(this);'), target='content')) + def breadcrumb(self, title): + if title != 'index': + type, path = title.split('_', 1) + path = path.split('.') + module = None + cls = None + func = None + meth = None + if type == 'module': + module = '.'.join(path) + elif type == 'class': + module = '.'.join(path[:-1]) + cls = path[-1] + elif type == 'method': + module = '.'.join(path[:-2]) + cls = path[-2] + meth = path[-1] + else: + module = '.'.join(path[:-1]) + func = path[-1] + if module: + yield html.a(module, href='module_%s.html' % (module,)) + if type != 'module': + yield u'.' + if cls: + s = cls + if module: + s = '%s.%s' % (module, cls) + yield html.a(cls, href='class_%s.html' % (s,)) + if type != 'class': + yield u'.' + if meth: + s = '%s.%s' % (cls, meth) + if module: + s = '%s.%s.%s' % (module, cls, meth) + yield html.a(meth, href='method_%s.html' % (s,)) + if func: + s = func + if module: + s = '%s.%s' % (module, func) + yield html.a(func, href='function_%s.html' % (s,)) class IndexHandler(PageHandler): ignore_text = False @@ -21,9 +62,6 @@ def startDocument(self): super(IndexHandler, self).startDocument() self.head.append(html.script(type='text/javascript', src='apigen.js')) - self.body.attr.onload = ('set_breadcrumb(' - 'document.getElementsByTagName("a")[0]);' - 'loadloc();') self._push(html.div(id='sidebar')) def endDocument(self): @@ -44,8 +82,3 @@ return super(IndexHandler, self).handleText(text) - def handleLink(self, text, target): - self.tagstack[-1].append(html.a(text, href=target, - onclick='set_breadcrumb(this)', - target='content')) - Added: py/dist/py/apigen/rest/testing/test_htmlhandlers.py ============================================================================== --- (empty file) +++ py/dist/py/apigen/rest/testing/test_htmlhandlers.py Fri Dec 8 14:02:00 2006 @@ -0,0 +1,41 @@ +import py +from py.__.apigen.rest.htmlhandlers import PageHandler + +def test_breadcrumb(): + h = PageHandler() + for fname, expected in [ + ('module_py', 'py'), + ('module_py.test', + 'py.test'), + ('class_py.test', + ('py.' + 'test')), + ('class_py.test.foo', + ('py.test.' + 'foo')), + ('class_py.test.foo.bar', + ('py.test.foo.' + 'bar')), + ('function_foo', 'foo'), + ('function_foo.bar', + ('foo.' + 'bar')), + ('function_foo.bar.baz', + ('foo.bar.' + 'baz')), + ('method_foo.bar', + ('foo.' + 'bar')), + ('method_foo.bar.baz', + ('foo.' + 'bar.' + 'baz')), + ('method_foo.bar.baz.qux', + ('foo.bar.' + 'baz.' + 'qux')), + ]: + html = ''.join([unicode(el) for el in h.breadcrumb(fname)]) + print fname + print html + assert html == expected Modified: py/dist/py/apigen/style.css ============================================================================== --- py/dist/py/apigen/style.css (original) +++ py/dist/py/apigen/style.css Fri Dec 8 14:02:00 2006 @@ -2,7 +2,7 @@ width: 9em; float: left; vertical-align: top; - margin-top: 0px; + margin-top: 0.5em; } #main { @@ -17,6 +17,7 @@ #breadcrumb { height: 5%; + display: none; } body, div, p, h1, h2, h3, h4 { @@ -31,11 +32,11 @@ } ul { - padding-left: 2em; + padding-left: 0em; margin-top: 0px; } ul li { - list-style-type: katakana; + list-style-type: none; } From arigo at codespeak.net Fri Dec 8 19:00:03 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 8 Dec 2006 19:00:03 +0100 (CET) Subject: [py-svn] r35502 - py/dist/py/test Message-ID: <20061208180003.2A43B1007B@code0.codespeak.net> Author: arigo Date: Fri Dec 8 19:00:00 2006 New Revision: 35502 Modified: py/dist/py/test/collect.py Log: Try harder to order the classes. Now they should really have the ordering they have in their source file. Modified: py/dist/py/test/collect.py ============================================================================== --- py/dist/py/test/collect.py (original) +++ py/dist/py/test/collect.py Fri Dec 8 19:00:00 2006 @@ -425,12 +425,16 @@ teardown_class(self.obj) def getsortvalue(self): + # try to locate the class in the source - not nice, but probably + # the most useful "solution" that we have try: - for key, val in self.obj.__dict__.iteritems(): - import types - if type(val) is (types.FunctionType, types.GeneratorType): - return val.func_code.co_firstlineno - except AttributeError: + file = (py.std.inspect.getsourcefile(self.obj) or + py.std.inspect.getfile(self.obj)) + if not file: + raise IOError + lines, lineno = py.std.inspect.findsource(self.obj) + return py.path.local(file), lineno + except IOError: pass # fall back... for x in self.tryiter((py.test.collect.Generator, py.test.Item)): From fijal at codespeak.net Sun Dec 10 17:06:02 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 10 Dec 2006 17:06:02 +0100 (CET) Subject: [py-svn] r35556 - py/branch/rsession-cleanup Message-ID: <20061210160602.2B3F610063@code0.codespeak.net> Author: fijal Date: Sun Dec 10 17:06:00 2006 New Revision: 35556 Added: py/branch/rsession-cleanup/ - copied from r35555, py/dist/ Log: Created branch to experiment with rsession cleanup semantics, probably involving some execnet cooperation. From fijal at codespeak.net Mon Dec 11 14:18:45 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 11 Dec 2006 14:18:45 +0100 (CET) Subject: [py-svn] r35571 - in py/branch/rsession-cleanup/py/test/rsession: . testing Message-ID: <20061211131845.CD4971007B@code0.codespeak.net> Author: fijal Date: Mon Dec 11 14:18:42 2006 New Revision: 35571 Modified: py/branch/rsession-cleanup/py/test/rsession/box.py py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py Log: Added (a bit sophisticated) test for box having pid stored. I guess it should be refined at some point for box to return self.parent or to call some callback. Modified: py/branch/rsession-cleanup/py/test/rsession/box.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/box.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/box.py Mon Dec 11 14:18:42 2006 @@ -18,9 +18,10 @@ from StringIO import StringIO class SimpleBox(object): - def __init__(self, fun, args = [], kwargs = {}): + def __init__(self, fun, args = [], kwargs = {}, info=None): self.fun = fun self.args = args + self.info = info self.kwargs = kwargs def run(self): @@ -39,12 +40,13 @@ class FileBox(object): count = 0 - def __init__(self, fun, args=None, kwargs=None): + def __init__(self, fun, args=None, kwargs=None, info=None): if args is None: args = [] if kwargs is None: kwargs = {} self.fun = fun + self.info = info self.args = args self.kwargs = kwargs @@ -59,6 +61,8 @@ nice_level = py.test.remote.nice_level pid = os.fork() if pid: + if self.info is not None: + self.info.pid = pid self.parent(pid) else: try: Modified: py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py Mon Dec 11 14:18:42 2006 @@ -2,7 +2,7 @@ """ test boxing functionality """ -import py, sys +import py, sys, os if sys.platform == 'win32': py.test.skip("rsession is unsupported on Windows.") @@ -74,3 +74,34 @@ assert b.exitstat == 0 assert b.signal == 0 assert b.retval == 2 + +def test_box_killer(): + class A: + pass + info = A() + import time + + def box_fun(): + time.sleep(300) # we don't want to last forever here + + b = RealBox(box_fun, info=info) + import thread + def f(): + b.run() + lock.release() + lock = thread.allocate_lock() + lock.acquire() + thread.start_new_thread(f, ()) + count = 0 + while count < 3000: + # we don't want to wait forever + time.sleep(.1) + if hasattr(info, 'pid'): + os.kill(info.pid, 15) + break + count += 1 + lock.acquire() + assert count < 3000 + assert b.signal == 15 + + From fijal at codespeak.net Mon Dec 11 14:38:15 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 11 Dec 2006 14:38:15 +0100 (CET) Subject: [py-svn] r35572 - py/branch/rsession-cleanup/py/test/rsession Message-ID: <20061211133815.AE6C11007F@code0.codespeak.net> Author: fijal Date: Mon Dec 11 14:38:14 2006 New Revision: 35572 Modified: py/branch/rsession-cleanup/py/test/rsession/executor.py Log: Killed old code. Modified: py/branch/rsession-cleanup/py/test/rsession/executor.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/executor.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/executor.py Mon Dec 11 14:38:14 2006 @@ -64,28 +64,3 @@ b.stdoutrepr, b.stderrrepr) else: return (False, False, None, False, False, b.signal, b.stdoutrepr, b.stderrrepr) - -# XXX old code -class XXXExecutor(object): - def __init__(self, fun, setup=lambda: None): - self.fun = fun - self.setup = setup - - def _execute(self, fun): - try: - fun() - except: - excinfo = py.code.ExceptionInfo() - code = py.code.Code(fun) - excinfo.traceback = excinfo.traceback.cut( - path=code.path, firstlineno=code.firstlineno) - return excinfo - - def execute(self): - excinfo = self._execute(self.setup) - if excinfo is not None: - return Outcome(excinfo=excinfo, setupfailure=True) - excinfo = self._execute(self.fun) - if excinfo is not None: - return Outcome(excinfo=excinfo, setupfailure=False) - return Outcome() From fijal at codespeak.net Mon Dec 11 19:05:47 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 11 Dec 2006 19:05:47 +0100 (CET) Subject: [py-svn] r35589 - py/branch/rsession-cleanup/py/test/rsession/testing Message-ID: <20061211180547.97B6610087@code0.codespeak.net> Author: fijal Date: Mon Dec 11 19:05:46 2006 New Revision: 35589 Modified: py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py Log: Removed empty lines Modified: py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py Mon Dec 11 19:05:46 2006 @@ -103,5 +103,3 @@ lock.acquire() assert count < 3000 assert b.signal == 15 - - From fijal at codespeak.net Mon Dec 11 19:06:37 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 11 Dec 2006 19:06:37 +0100 (CET) Subject: [py-svn] r35590 - py/branch/rsession-cleanup/py/test/rsession Message-ID: <20061211180637.BB30E10069@code0.codespeak.net> Author: fijal Date: Mon Dec 11 19:06:35 2006 New Revision: 35590 Modified: py/branch/rsession-cleanup/py/test/rsession/master.py py/branch/rsession-cleanup/py/test/rsession/reporter.py py/branch/rsession-cleanup/py/test/rsession/slave.py Log: Added different behaviour for -x. Mostly that means that exit of clients is immediate (really). Modified: py/branch/rsession-cleanup/py/test/rsession/master.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/master.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/master.py Mon Dec 11 19:06:35 2006 @@ -20,11 +20,14 @@ self.channel, item, repr_outcome)) def send(self, item): - self.pending.insert(0, item) - itemspec = item.listnames()[1:] - self.channel.send(itemspec) - # send start report - self.reporter(report.SendItem(self.channel, item)) + if item is StopIteration: + self.channel.send(42) + else: + self.pending.insert(0, item) + itemspec = item.listnames()[1:] + self.channel.send(itemspec) + # send start report + self.reporter(report.SendItem(self.channel, item)) def dispatch_loop(masternodes, itemgenerator, shouldstop, waiter = lambda: py.std.time.sleep(0.1)): @@ -37,6 +40,8 @@ if len(node.pending) < max_tasks_per_node: item = itemgenerator.next() if shouldstop(): + for _node in masternodes: + _node.send(StopIteration) # magic connector return node.send(item) except StopIteration: Modified: py/branch/rsession-cleanup/py/test/rsession/reporter.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/reporter.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/reporter.py Mon Dec 11 19:06:35 2006 @@ -91,6 +91,8 @@ def hangs(self): h = [] + if self.config.option.exitfirst: + return for node in self.nodes: h += [(i, node.channel.gateway.sshaddress) for i in node.pending] if h: Modified: py/branch/rsession-cleanup/py/test/rsession/slave.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/slave.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/slave.py Mon Dec 11 19:06:35 2006 @@ -28,7 +28,7 @@ else: return outcome.make_repr() -def slave_main(receive, send, path): +def slave_main(receive, send, path, info = None): import os assert os.path.exists(path) path = os.path.abspath(path) @@ -61,9 +61,18 @@ while nextitem is not None: nextitem = receive() - + def setup(): + def callback_gen(queue): + def callback(item): + if item == 42: # magic call-cleanup + # XXX should kill a pid here + sys.exit(0) + queue.put(item) + return callback + import os, sys + from Queue import Queue pkgdir = channel.receive() # path is ready options = channel.receive() # options stuff, should be dictionary basedir = os.path.dirname(pkgdir) @@ -81,6 +90,8 @@ mod = __import__(pkgname) assert py.path.local(mod.__file__).dirpath() == py.path.local(pkgdir) from py.__.test.rsession.slave import slave_main - slave_main(channel.receive, channel.send, basedir) + queue = Queue() + channel.setcallback(callback_gen(queue)) + slave_main(queue.get, channel.send, basedir) if not py.test.remote.nomagic: py.magic.revoke(assertion=1) From fijal at codespeak.net Mon Dec 11 19:32:17 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 11 Dec 2006 19:32:17 +0100 (CET) Subject: [py-svn] r35591 - in py/branch/rsession-cleanup/py/test/rsession: . testing Message-ID: <20061211183217.3A5B710088@code0.codespeak.net> Author: fijal Date: Mon Dec 11 19:32:13 2006 New Revision: 35591 Modified: py/branch/rsession-cleanup/py/test/rsession/reporter.py py/branch/rsession-cleanup/py/test/rsession/testing/test_reporter.py py/branch/rsession-cleanup/py/test/rsession/testing/test_rsession.py py/branch/rsession-cleanup/py/test/rsession/testing/test_slave.py Log: Added a test and a comment. Modified: py/branch/rsession-cleanup/py/test/rsession/reporter.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/reporter.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/reporter.py Mon Dec 11 19:32:13 2006 @@ -92,6 +92,8 @@ def hangs(self): h = [] if self.config.option.exitfirst: + # reporting hanging nodes in that case makes no sense at all + # but we should share some code in all reporters than return for node in self.nodes: h += [(i, node.channel.gateway.sshaddress) for i in node.pending] Modified: py/branch/rsession-cleanup/py/test/rsession/testing/test_reporter.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/testing/test_reporter.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/testing/test_reporter.py Mon Dec 11 19:32:13 2006 @@ -140,7 +140,7 @@ assert self.report_received_item_outcome() == 'FsF.' def test_module(self): - assert self._test_module().endswith("test_slave.py[8] FsF."),\ + assert self._test_module().endswith("test_slave.py[9] FsF."),\ self._test_module() def test_full_module(self): Modified: py/branch/rsession-cleanup/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/testing/test_rsession.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/testing/test_rsession.py Mon Dec 11 19:32:13 2006 @@ -302,7 +302,7 @@ if isinstance(x, report.ReceivedItemOutcome)] passevents = [x for x in testevents if x.outcome.passed] assert len(passevents) == 1 - + class TestDirectories(object): def test_simple_parse(self): sshhosts = ['h1', 'h2', 'h3'] Modified: py/branch/rsession-cleanup/py/test/rsession/testing/test_slave.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/testing/test_slave.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/testing/test_slave.py Mon Dec 11 19:32:13 2006 @@ -143,6 +143,43 @@ else: py.test.fail("missing exception") +def test_slave_setup_exit(): + tmp = py.test.ensuretemp("slaveexit") + tmp.ensure("__init__.py") + from py.__.test.rsession.slave import setup + from Queue import Queue + q = Queue() + + class C: + res = [] + def __init__(self): + from py.__.test.rsession.rsession import remote_options + self.q = [str(tmp), + remote_options.d, + funcpass_spec, + 42, + funcpass_spec] + self.q.reverse() + + def receive(self): + return self.q.pop() + + def setcallback(self, callback): + import thread + def f(): + while 1: + callback(self.q.pop()) + f() + #thread.start_new_thread(f, ()) + + send = res.append + try: + exec py.code.Source(setup, "setup()").compile() in {'channel':C()} + except SystemExit: + pass + else: + py.test.fail("Did not exit") + def test_slave_setup_fails_on_missing_pkg(): from py.__.test.rsession.slave import setup tmp = py.test.ensuretemp("slavesetup2") From fijal at codespeak.net Mon Dec 11 19:39:21 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 11 Dec 2006 19:39:21 +0100 (CET) Subject: [py-svn] r35592 - in py/branch/rsession-cleanup/py/test/rsession: . testing Message-ID: <20061211183921.89BF110088@code0.codespeak.net> Author: fijal Date: Mon Dec 11 19:39:15 2006 New Revision: 35592 Modified: py/branch/rsession-cleanup/py/test/rsession/box.py py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py Log: Reviewed semantics to a more friendly async mode. Modified: py/branch/rsession-cleanup/py/test/rsession/box.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/box.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/box.py Mon Dec 11 19:39:15 2006 @@ -18,7 +18,7 @@ from StringIO import StringIO class SimpleBox(object): - def __init__(self, fun, args = [], kwargs = {}, info=None): + def __init__(self, fun, args = [], kwargs = {}): self.fun = fun self.args = args self.info = info @@ -40,17 +40,16 @@ class FileBox(object): count = 0 - def __init__(self, fun, args=None, kwargs=None, info=None): + def __init__(self, fun, args=None, kwargs=None): if args is None: args = [] if kwargs is None: kwargs = {} self.fun = fun - self.info = info self.args = args self.kwargs = kwargs - def run(self): + def run(self, continuation=False): tempdir = py.test.ensuretemp("box%d" % self.count) self.count += 1 self.tempdir = tempdir @@ -61,9 +60,10 @@ nice_level = py.test.remote.nice_level pid = os.fork() if pid: - if self.info is not None: - self.info.pid = pid - self.parent(pid) + if not continuation: + self.parent(pid) + else: + return self.parent, pid else: try: outcome = self.children(nice_level) Modified: py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/testing/test_boxing.py Mon Dec 11 19:39:15 2006 @@ -84,22 +84,8 @@ def box_fun(): time.sleep(300) # we don't want to last forever here - b = RealBox(box_fun, info=info) - import thread - def f(): - b.run() - lock.release() - lock = thread.allocate_lock() - lock.acquire() - thread.start_new_thread(f, ()) - count = 0 - while count < 3000: - # we don't want to wait forever - time.sleep(.1) - if hasattr(info, 'pid'): - os.kill(info.pid, 15) - break - count += 1 - lock.acquire() - assert count < 3000 + b = RealBox(box_fun) + par, pid = b.run(continuation=True) + os.kill(pid, 15) + par(pid) assert b.signal == 15 From fijal at codespeak.net Mon Dec 11 19:47:29 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 11 Dec 2006 19:47:29 +0100 (CET) Subject: [py-svn] r35593 - in py/branch/rsession-cleanup/py/test/rsession: . testing Message-ID: <20061211184729.CE01710079@code0.codespeak.net> Author: fijal Date: Mon Dec 11 19:47:28 2006 New Revision: 35593 Modified: py/branch/rsession-cleanup/py/test/rsession/executor.py py/branch/rsession-cleanup/py/test/rsession/testing/test_executor.py Log: Added async executor Modified: py/branch/rsession-cleanup/py/test/rsession/executor.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/executor.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/executor.py Mon Dec 11 19:47:28 2006 @@ -64,3 +64,28 @@ b.stdoutrepr, b.stderrrepr) else: return (False, False, None, False, False, b.signal, b.stdoutrepr, b.stderrrepr) + +class AsyncExecutor(RunExecutor): + """ same as box executor, but instead it returns function to continue + computations (more async mode) + """ + wraps = True + + def execute(self): + def fun(): + outcome = RunExecutor.execute(self) + return outcome.make_repr() + + b = Box(fun) + parent, pid = b.run(continuation=True) + + def cont(): + parent(pid) + if b.retval is not None: + passed, setupfailure, excinfo, skipped, critical, _, _, _ = b.retval + return (passed, setupfailure, excinfo, skipped, critical, 0, + b.stdoutrepr, b.stderrrepr) + else: + return (False, False, None, False, False, b.signal, b.stdoutrepr, b.stderrrepr) + + return cont, pid Modified: py/branch/rsession-cleanup/py/test/rsession/testing/test_executor.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/testing/test_executor.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/testing/test_executor.py Mon Dec 11 19:47:28 2006 @@ -2,13 +2,16 @@ import py import example1 -from py.__.test.rsession.executor import RunExecutor, BoxExecutor +from py.__.test.rsession.executor import RunExecutor, BoxExecutor,\ + AsyncExecutor from py.__.test.rsession.outcome import ReprOutcome from py.__.test.rsession.testing.test_slave import funcprint_spec, \ funcprintfail_spec def setup_module(mod): mod.rootdir = py.path.local(py.__file__).dirpath().dirpath() + from py.__.test.rsession.rsession import remote_options + remote_options['nice_level'] = 0 def XXXtest_executor_passing_function(): ex = Executor(example1.f1) @@ -107,3 +110,14 @@ outcome = ReprOutcome(outcome_repr) assert not outcome.passed assert outcome.stdout == "samfing elz\n" + +def test_cont_executor(): + rootcol = py.test.collect.Directory(rootdir) + item = rootcol.getitembynames(funcprintfail_spec) + ex = AsyncExecutor(item) + cont, pid = ex.execute() + assert pid + outcome_repr = cont() + outcome = ReprOutcome(outcome_repr) + assert not outcome.passed + assert outcome.stdout == "samfing elz\n" From arigo at codespeak.net Mon Dec 11 19:48:48 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 11 Dec 2006 19:48:48 +0100 (CET) Subject: [py-svn] r35594 - py/dist/py Message-ID: <20061211184848.5357C10079@code0.codespeak.net> Author: arigo Date: Mon Dec 11 19:48:47 2006 New Revision: 35594 Modified: py/dist/py/initpkg.py Log: Add an XXX about shahexdigest()'s bugs. Modified: py/dist/py/initpkg.py ============================================================================== --- py/dist/py/initpkg.py (original) +++ py/dist/py/initpkg.py Mon Dec 11 19:48:47 2006 @@ -119,6 +119,8 @@ return cache[0] from sha import sha sum = sha() + # XXX the checksum depends on the order in which visit() enumerates + # the files, and it doesn't depend on the file names and paths for x in self._iterfiles(): sum.update(x.read()) cache.append(sum.hexdigest()) From fijal at codespeak.net Mon Dec 11 20:02:26 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 11 Dec 2006 20:02:26 +0100 (CET) Subject: [py-svn] r35595 - in py/branch/rsession-cleanup/py/test/rsession: . testing Message-ID: <20061211190226.EBA131007B@code0.codespeak.net> Author: fijal Date: Mon Dec 11 20:02:24 2006 New Revision: 35595 Modified: py/branch/rsession-cleanup/py/test/rsession/slave.py py/branch/rsession-cleanup/py/test/rsession/testing/test_slave.py Log: Fixed -x semantics, so remote process really dies after receiving such signal. Modified: py/branch/rsession-cleanup/py/test/rsession/slave.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/slave.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/slave.py Mon Dec 11 20:02:24 2006 @@ -3,11 +3,14 @@ """ import py -from py.__.test.rsession.executor import RunExecutor, BoxExecutor +from py.__.test.rsession.executor import RunExecutor, BoxExecutor, AsyncExecutor from py.__.test.rsession.outcome import Outcome +class Info: + pid = None + class SlaveNode(object): - def __init__(self, rootcollector, executor=BoxExecutor): + def __init__(self, rootcollector, executor=AsyncExecutor): self.rootcollector = rootcollector self.executor = executor @@ -17,7 +20,13 @@ # ex = Executor(item.obj, setup=item.setup) #else: ex = self.executor(item) - return ex.execute() + if self.executor is AsyncExecutor: + cont, pid = ex.execute() + else: + # for tests only + return ex.execute() + Info.pid = pid + return cont() def run(self, itemspec): #outcome = self.execute(itemspec) @@ -64,9 +73,12 @@ def setup(): def callback_gen(queue): + from py.__.test.rsession.slave import Info def callback(item): if item == 42: # magic call-cleanup # XXX should kill a pid here + if Info.pid: + os.kill(Info.pid, 15) sys.exit(0) queue.put(item) return callback @@ -82,6 +94,8 @@ import py options['we_are_remote'] = True from py.__.test.rsession.rsession import RemoteOptions + from py.__.test.rsession.slave import Info + Info.pid = 0 py.test.remote = RemoteOptions(options) # XXX the following assumes that py lib is there, a bit # much of an assumtion Modified: py/branch/rsession-cleanup/py/test/rsession/testing/test_slave.py ============================================================================== --- py/branch/rsession-cleanup/py/test/rsession/testing/test_slave.py (original) +++ py/branch/rsession-cleanup/py/test/rsession/testing/test_slave.py Mon Dec 11 20:02:24 2006 @@ -40,6 +40,10 @@ def funcoptioncustom(): assert py.test.remote.custom == "custom" +def funchang(): + import time + time.sleep(1000) + BASE = "py/test/rsession/testing/test_slave.py/" funcpass_spec = (BASE + "funcpass").split("/") funcfail_spec = (BASE + "funcfail").split("/") @@ -48,6 +52,7 @@ funcprintfail_spec = (BASE + "funcprintfail").split("/") funcoption_spec = (BASE + "funcoption").split("/") funcoptioncustom_spec = (BASE + "funcoptioncustom").split("/") +funchang_spec = (BASE + "funchang").split("/") mod_spec = BASE[:-1].split("/") # ---------------------------------------------------------------------- @@ -132,7 +137,7 @@ from py.__.test.rsession.rsession import remote_options retval = remote_options.d else: - raise NotImplementedError("mora data") + raise NotImplementedError("more data") self.count += 1 return retval try: @@ -156,7 +161,7 @@ from py.__.test.rsession.rsession import remote_options self.q = [str(tmp), remote_options.d, - funcpass_spec, + funchang_spec, 42, funcpass_spec] self.q.reverse() @@ -195,7 +200,7 @@ from py.__.test.rsession.rsession import remote_options retval = remote_options.d else: - raise NotImplementedError("mora data") + raise NotImplementedError("more data") self.count += 1 return retval try: From fijal at codespeak.net Tue Dec 12 18:58:22 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 18:58:22 +0100 (CET) Subject: [py-svn] r35637 - in py/dist/py/test/rsession: . testing Message-ID: <20061212175822.C4D6F1007D@code0.codespeak.net> Author: fijal Date: Tue Dec 12 18:58:19 2006 New Revision: 35637 Modified: py/dist/py/test/rsession/box.py py/dist/py/test/rsession/executor.py py/dist/py/test/rsession/master.py py/dist/py/test/rsession/reporter.py py/dist/py/test/rsession/slave.py py/dist/py/test/rsession/testing/test_boxing.py py/dist/py/test/rsession/testing/test_executor.py py/dist/py/test/rsession/testing/test_reporter.py py/dist/py/test/rsession/testing/test_rsession.py py/dist/py/test/rsession/testing/test_slave.py Log: svn merge -r 35555:HEAD http://codespeak.net/svn/py/branch/rsession-cleanup Modified: py/dist/py/test/rsession/box.py ============================================================================== --- py/dist/py/test/rsession/box.py (original) +++ py/dist/py/test/rsession/box.py Tue Dec 12 18:58:19 2006 @@ -21,6 +21,7 @@ def __init__(self, fun, args = [], kwargs = {}): self.fun = fun self.args = args + self.info = info self.kwargs = kwargs def run(self): @@ -48,7 +49,7 @@ self.args = args self.kwargs = kwargs - def run(self): + def run(self, continuation=False): tempdir = py.test.ensuretemp("box%d" % self.count) self.count += 1 self.tempdir = tempdir @@ -59,7 +60,10 @@ nice_level = py.test.remote.nice_level pid = os.fork() if pid: - self.parent(pid) + if not continuation: + self.parent(pid) + else: + return self.parent, pid else: try: outcome = self.children(nice_level) Modified: py/dist/py/test/rsession/executor.py ============================================================================== --- py/dist/py/test/rsession/executor.py (original) +++ py/dist/py/test/rsession/executor.py Tue Dec 12 18:58:19 2006 @@ -65,27 +65,27 @@ else: return (False, False, None, False, False, b.signal, b.stdoutrepr, b.stderrrepr) -# XXX old code -class XXXExecutor(object): - def __init__(self, fun, setup=lambda: None): - self.fun = fun - self.setup = setup +class AsyncExecutor(RunExecutor): + """ same as box executor, but instead it returns function to continue + computations (more async mode) + """ + wraps = True - def _execute(self, fun): - try: - fun() - except: - excinfo = py.code.ExceptionInfo() - code = py.code.Code(fun) - excinfo.traceback = excinfo.traceback.cut( - path=code.path, firstlineno=code.firstlineno) - return excinfo - def execute(self): - excinfo = self._execute(self.setup) - if excinfo is not None: - return Outcome(excinfo=excinfo, setupfailure=True) - excinfo = self._execute(self.fun) - if excinfo is not None: - return Outcome(excinfo=excinfo, setupfailure=False) - return Outcome() + def fun(): + outcome = RunExecutor.execute(self) + return outcome.make_repr() + + b = Box(fun) + parent, pid = b.run(continuation=True) + + def cont(): + parent(pid) + if b.retval is not None: + passed, setupfailure, excinfo, skipped, critical, _, _, _ = b.retval + return (passed, setupfailure, excinfo, skipped, critical, 0, + b.stdoutrepr, b.stderrrepr) + else: + return (False, False, None, False, False, b.signal, b.stdoutrepr, b.stderrrepr) + + return cont, pid Modified: py/dist/py/test/rsession/master.py ============================================================================== --- py/dist/py/test/rsession/master.py (original) +++ py/dist/py/test/rsession/master.py Tue Dec 12 18:58:19 2006 @@ -20,11 +20,14 @@ self.channel, item, repr_outcome)) def send(self, item): - self.pending.insert(0, item) - itemspec = item.listnames()[1:] - self.channel.send(itemspec) - # send start report - self.reporter(report.SendItem(self.channel, item)) + if item is StopIteration: + self.channel.send(42) + else: + self.pending.insert(0, item) + itemspec = item.listnames()[1:] + self.channel.send(itemspec) + # send start report + self.reporter(report.SendItem(self.channel, item)) def dispatch_loop(masternodes, itemgenerator, shouldstop, waiter = lambda: py.std.time.sleep(0.1)): @@ -37,6 +40,8 @@ if len(node.pending) < max_tasks_per_node: item = itemgenerator.next() if shouldstop(): + for _node in masternodes: + _node.send(StopIteration) # magic connector return node.send(item) except StopIteration: Modified: py/dist/py/test/rsession/reporter.py ============================================================================== --- py/dist/py/test/rsession/reporter.py (original) +++ py/dist/py/test/rsession/reporter.py Tue Dec 12 18:58:19 2006 @@ -91,6 +91,10 @@ def hangs(self): h = [] + if self.config.option.exitfirst: + # reporting hanging nodes in that case makes no sense at all + # but we should share some code in all reporters than + return for node in self.nodes: h += [(i, node.channel.gateway.sshaddress) for i in node.pending] if h: Modified: py/dist/py/test/rsession/slave.py ============================================================================== --- py/dist/py/test/rsession/slave.py (original) +++ py/dist/py/test/rsession/slave.py Tue Dec 12 18:58:19 2006 @@ -3,11 +3,14 @@ """ import py -from py.__.test.rsession.executor import RunExecutor, BoxExecutor +from py.__.test.rsession.executor import RunExecutor, BoxExecutor, AsyncExecutor from py.__.test.rsession.outcome import Outcome +class Info: + pid = None + class SlaveNode(object): - def __init__(self, rootcollector, executor=BoxExecutor): + def __init__(self, rootcollector, executor=AsyncExecutor): self.rootcollector = rootcollector self.executor = executor @@ -17,7 +20,13 @@ # ex = Executor(item.obj, setup=item.setup) #else: ex = self.executor(item) - return ex.execute() + if self.executor is AsyncExecutor: + cont, pid = ex.execute() + else: + # for tests only + return ex.execute() + Info.pid = pid + return cont() def run(self, itemspec): #outcome = self.execute(itemspec) @@ -28,7 +37,7 @@ else: return outcome.make_repr() -def slave_main(receive, send, path): +def slave_main(receive, send, path, info = None): import os assert os.path.exists(path) path = os.path.abspath(path) @@ -61,9 +70,21 @@ while nextitem is not None: nextitem = receive() - + def setup(): + def callback_gen(queue): + from py.__.test.rsession.slave import Info + def callback(item): + if item == 42: # magic call-cleanup + # XXX should kill a pid here + if Info.pid: + os.kill(Info.pid, 15) + sys.exit(0) + queue.put(item) + return callback + import os, sys + from Queue import Queue pkgdir = channel.receive() # path is ready options = channel.receive() # options stuff, should be dictionary basedir = os.path.dirname(pkgdir) @@ -73,6 +94,8 @@ import py options['we_are_remote'] = True from py.__.test.rsession.rsession import RemoteOptions + from py.__.test.rsession.slave import Info + Info.pid = 0 py.test.remote = RemoteOptions(options) # XXX the following assumes that py lib is there, a bit # much of an assumtion @@ -81,6 +104,8 @@ mod = __import__(pkgname) assert py.path.local(mod.__file__).dirpath() == py.path.local(pkgdir) from py.__.test.rsession.slave import slave_main - slave_main(channel.receive, channel.send, basedir) + queue = Queue() + channel.setcallback(callback_gen(queue)) + slave_main(queue.get, channel.send, basedir) if not py.test.remote.nomagic: py.magic.revoke(assertion=1) Modified: py/dist/py/test/rsession/testing/test_boxing.py ============================================================================== --- py/dist/py/test/rsession/testing/test_boxing.py (original) +++ py/dist/py/test/rsession/testing/test_boxing.py Tue Dec 12 18:58:19 2006 @@ -2,7 +2,7 @@ """ test boxing functionality """ -import py, sys +import py, sys, os if sys.platform == 'win32': py.test.skip("rsession is unsupported on Windows.") @@ -74,3 +74,18 @@ assert b.exitstat == 0 assert b.signal == 0 assert b.retval == 2 + +def test_box_killer(): + class A: + pass + info = A() + import time + + def box_fun(): + time.sleep(300) # we don't want to last forever here + + b = RealBox(box_fun) + par, pid = b.run(continuation=True) + os.kill(pid, 15) + par(pid) + assert b.signal == 15 Modified: py/dist/py/test/rsession/testing/test_executor.py ============================================================================== --- py/dist/py/test/rsession/testing/test_executor.py (original) +++ py/dist/py/test/rsession/testing/test_executor.py Tue Dec 12 18:58:19 2006 @@ -2,13 +2,16 @@ import py import example1 -from py.__.test.rsession.executor import RunExecutor, BoxExecutor +from py.__.test.rsession.executor import RunExecutor, BoxExecutor,\ + AsyncExecutor from py.__.test.rsession.outcome import ReprOutcome from py.__.test.rsession.testing.test_slave import funcprint_spec, \ funcprintfail_spec def setup_module(mod): mod.rootdir = py.path.local(py.__file__).dirpath().dirpath() + from py.__.test.rsession.rsession import remote_options + remote_options['nice_level'] = 0 def XXXtest_executor_passing_function(): ex = Executor(example1.f1) @@ -107,3 +110,14 @@ outcome = ReprOutcome(outcome_repr) assert not outcome.passed assert outcome.stdout == "samfing elz\n" + +def test_cont_executor(): + rootcol = py.test.collect.Directory(rootdir) + item = rootcol.getitembynames(funcprintfail_spec) + ex = AsyncExecutor(item) + cont, pid = ex.execute() + assert pid + outcome_repr = cont() + outcome = ReprOutcome(outcome_repr) + assert not outcome.passed + assert outcome.stdout == "samfing elz\n" Modified: py/dist/py/test/rsession/testing/test_reporter.py ============================================================================== --- py/dist/py/test/rsession/testing/test_reporter.py (original) +++ py/dist/py/test/rsession/testing/test_reporter.py Tue Dec 12 18:58:19 2006 @@ -140,7 +140,7 @@ assert self.report_received_item_outcome() == 'FsF.' def test_module(self): - assert self._test_module().endswith("test_slave.py[8] FsF."),\ + assert self._test_module().endswith("test_slave.py[9] FsF."),\ self._test_module() def test_full_module(self): Modified: py/dist/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/dist/py/test/rsession/testing/test_rsession.py (original) +++ py/dist/py/test/rsession/testing/test_rsession.py Tue Dec 12 18:58:19 2006 @@ -302,7 +302,7 @@ if isinstance(x, report.ReceivedItemOutcome)] passevents = [x for x in testevents if x.outcome.passed] assert len(passevents) == 1 - + class TestDirectories(object): def test_simple_parse(self): sshhosts = ['h1', 'h2', 'h3'] Modified: py/dist/py/test/rsession/testing/test_slave.py ============================================================================== --- py/dist/py/test/rsession/testing/test_slave.py (original) +++ py/dist/py/test/rsession/testing/test_slave.py Tue Dec 12 18:58:19 2006 @@ -40,6 +40,10 @@ def funcoptioncustom(): assert py.test.remote.custom == "custom" +def funchang(): + import time + time.sleep(1000) + BASE = "py/test/rsession/testing/test_slave.py/" funcpass_spec = (BASE + "funcpass").split("/") funcfail_spec = (BASE + "funcfail").split("/") @@ -48,6 +52,7 @@ funcprintfail_spec = (BASE + "funcprintfail").split("/") funcoption_spec = (BASE + "funcoption").split("/") funcoptioncustom_spec = (BASE + "funcoptioncustom").split("/") +funchang_spec = (BASE + "funchang").split("/") mod_spec = BASE[:-1].split("/") # ---------------------------------------------------------------------- @@ -132,7 +137,7 @@ from py.__.test.rsession.rsession import remote_options retval = remote_options.d else: - raise NotImplementedError("mora data") + raise NotImplementedError("more data") self.count += 1 return retval try: @@ -143,6 +148,43 @@ else: py.test.fail("missing exception") +def test_slave_setup_exit(): + tmp = py.test.ensuretemp("slaveexit") + tmp.ensure("__init__.py") + from py.__.test.rsession.slave import setup + from Queue import Queue + q = Queue() + + class C: + res = [] + def __init__(self): + from py.__.test.rsession.rsession import remote_options + self.q = [str(tmp), + remote_options.d, + funchang_spec, + 42, + funcpass_spec] + self.q.reverse() + + def receive(self): + return self.q.pop() + + def setcallback(self, callback): + import thread + def f(): + while 1: + callback(self.q.pop()) + f() + #thread.start_new_thread(f, ()) + + send = res.append + try: + exec py.code.Source(setup, "setup()").compile() in {'channel':C()} + except SystemExit: + pass + else: + py.test.fail("Did not exit") + def test_slave_setup_fails_on_missing_pkg(): from py.__.test.rsession.slave import setup tmp = py.test.ensuretemp("slavesetup2") @@ -158,7 +200,7 @@ from py.__.test.rsession.rsession import remote_options retval = remote_options.d else: - raise NotImplementedError("mora data") + raise NotImplementedError("more data") self.count += 1 return retval try: From fijal at codespeak.net Tue Dec 12 19:59:03 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 19:59:03 +0100 (CET) Subject: [py-svn] r35640 - py/dist/py/test/testing Message-ID: <20061212185903.878E210083@code0.codespeak.net> Author: fijal Date: Tue Dec 12 19:59:02 2006 New Revision: 35640 Modified: py/dist/py/test/testing/test_collect.py Log: let's break some stuff Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 19:59:02 2006 @@ -409,3 +409,7 @@ errors = [] l = list(col.tryiter(reporterror=errors.append)) assert len(errors) == 0 + +def test_fail(): + XXX + From fijal at codespeak.net Tue Dec 12 20:00:37 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 20:00:37 +0100 (CET) Subject: [py-svn] r35641 - py/dist/py/test/testing Message-ID: <20061212190037.7FEBC1007B@code0.codespeak.net> Author: fijal Date: Tue Dec 12 20:00:36 2006 New Revision: 35641 Modified: py/dist/py/test/testing/test_collect.py Log: more breaks Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 20:00:36 2006 @@ -413,3 +413,4 @@ def test_fail(): XXX + xxx From fijal at codespeak.net Tue Dec 12 20:03:00 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 20:03:00 +0100 (CET) Subject: [py-svn] r35642 - py/dist/py/test/testing Message-ID: <20061212190300.55B7010084@code0.codespeak.net> Author: fijal Date: Tue Dec 12 20:02:59 2006 New Revision: 35642 Modified: py/dist/py/test/testing/test_collect.py Log: more breaks Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 20:02:59 2006 @@ -413,4 +413,3 @@ def test_fail(): XXX - xxx From fijal at codespeak.net Tue Dec 12 20:15:30 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 20:15:30 +0100 (CET) Subject: [py-svn] r35643 - py/dist/py/test/testing Message-ID: <20061212191530.C118D10084@code0.codespeak.net> Author: fijal Date: Tue Dec 12 20:15:28 2006 New Revision: 35643 Modified: py/dist/py/test/testing/test_collect.py Log: more breaks Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 20:15:28 2006 @@ -412,4 +412,4 @@ def test_fail(): XXX - + xxx From fijal at codespeak.net Tue Dec 12 20:26:36 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 20:26:36 +0100 (CET) Subject: [py-svn] r35645 - py/dist/py/test/testing Message-ID: <20061212192636.780B210050@code0.codespeak.net> Author: fijal Date: Tue Dec 12 20:26:35 2006 New Revision: 35645 Modified: py/dist/py/test/testing/test_collect.py Log: more breaks Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 20:26:35 2006 @@ -413,3 +413,4 @@ def test_fail(): XXX xxx + yyy From fijal at codespeak.net Tue Dec 12 20:32:02 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 20:32:02 +0100 (CET) Subject: [py-svn] r35646 - py/dist/py/test/testing Message-ID: <20061212193202.23CEB10050@code0.codespeak.net> Author: fijal Date: Tue Dec 12 20:32:01 2006 New Revision: 35646 Modified: py/dist/py/test/testing/test_collect.py Log: more breaks Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 20:32:01 2006 @@ -412,5 +412,4 @@ def test_fail(): XXX - xxx - yyy + From fijal at codespeak.net Tue Dec 12 20:35:47 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 20:35:47 +0100 (CET) Subject: [py-svn] r35647 - py/dist/py/test/testing Message-ID: <20061212193547.7AFE61007B@code0.codespeak.net> Author: fijal Date: Tue Dec 12 20:35:46 2006 New Revision: 35647 Modified: py/dist/py/test/testing/test_collect.py Log: break Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 20:35:46 2006 @@ -412,4 +412,3 @@ def test_fail(): XXX - From fijal at codespeak.net Tue Dec 12 20:42:02 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 20:42:02 +0100 (CET) Subject: [py-svn] r35648 - py/dist/py/test/testing Message-ID: <20061212194202.7105810084@code0.codespeak.net> Author: fijal Date: Tue Dec 12 20:42:01 2006 New Revision: 35648 Modified: py/dist/py/test/testing/test_collect.py Log: break Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 20:42:01 2006 @@ -412,3 +412,5 @@ def test_fail(): XXX + xxx + From fijal at codespeak.net Tue Dec 12 20:43:25 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 20:43:25 +0100 (CET) Subject: [py-svn] r35649 - py/dist/py/test/testing Message-ID: <20061212194325.387AD1008A@code0.codespeak.net> Author: fijal Date: Tue Dec 12 20:43:24 2006 New Revision: 35649 Modified: py/dist/py/test/testing/test_collect.py Log: break Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 20:43:24 2006 @@ -412,5 +412,3 @@ def test_fail(): XXX - xxx - From fijal at codespeak.net Tue Dec 12 20:49:57 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 20:49:57 +0100 (CET) Subject: [py-svn] r35650 - py/dist/py/test/testing Message-ID: <20061212194957.D48931008D@code0.codespeak.net> Author: fijal Date: Tue Dec 12 20:49:53 2006 New Revision: 35650 Modified: py/dist/py/test/testing/test_collect.py Log: Testing automatic mails about broken commits Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 20:49:53 2006 @@ -412,3 +412,5 @@ def test_fail(): XXX + xxx + From fijal at codespeak.net Tue Dec 12 20:51:56 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 20:51:56 +0100 (CET) Subject: [py-svn] r35651 - py/dist/py/test/testing Message-ID: <20061212195156.00D1F1008D@code0.codespeak.net> Author: fijal Date: Tue Dec 12 20:51:55 2006 New Revision: 35651 Modified: py/dist/py/test/testing/test_collect.py Log: Remove failing test. It seems that code is buggy and needs more tests. Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 20:51:55 2006 @@ -410,7 +410,4 @@ l = list(col.tryiter(reporterror=errors.append)) assert len(errors) == 0 -def test_fail(): - XXX - xxx From fijal at codespeak.net Tue Dec 12 21:10:54 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 21:10:54 +0100 (CET) Subject: [py-svn] r35652 - in py/dist/py: rest test/rsession test/rsession/testing Message-ID: <20061212201054.A8B9B1008A@code0.codespeak.net> Author: fijal Date: Tue Dec 12 21:10:52 2006 New Revision: 35652 Modified: py/dist/py/rest/convert.py py/dist/py/test/rsession/testing/test_web.py py/dist/py/test/rsession/web.py Log: Fixed (I hope) last few issues with failing tests (at least on my machine) Modified: py/dist/py/rest/convert.py ============================================================================== --- py/dist/py/rest/convert.py (original) +++ py/dist/py/rest/convert.py Tue Dec 12 21:10:52 2006 @@ -16,9 +16,9 @@ raise SystemExit("neither ps2eps nor ps2epsi found") try: eps = ps.new(ext=".eps") - py.process.cmdexec("ERROR: ps2epsi %s %s" % (ps, eps)) + py.process.cmdexec("ps2epsi %s %s" % (ps, eps)) except ExecutionFailed: - py.process.cmdexec("ERROR: ps2eps -l -f %s" % ps) + py.process.cmdexec("ps2eps -l -f %s" % ps) def ps2pdf(ps, compat_level="1.2"): if not is_on_path("gs"): Modified: py/dist/py/test/rsession/testing/test_web.py ============================================================================== --- py/dist/py/test/rsession/testing/test_web.py (original) +++ py/dist/py/test/rsession/testing/test_web.py Tue Dec 12 21:10:52 2006 @@ -24,7 +24,7 @@ def test_js_generate(): from py.__.test.rsession import webjs - from py.__.test.rsession.web import FUNCTION_LIST + from py.__.test.rsession.web import FUNCTION_LIST, IMPORTED_PYPY source = rpython2javascript(webjs, FUNCTION_LIST) assert source Modified: py/dist/py/test/rsession/web.py ============================================================================== --- py/dist/py/test/rsession/web.py (original) +++ py/dist/py/test/rsession/web.py Tue Dec 12 21:10:52 2006 @@ -30,8 +30,11 @@ # replace("'", "\\'").replace(" ", " ").replace("\n", "
") try: - if not session_options.import_pypy: - raise ImportError + try: + if not session_options.import_pypy: + raise ImportError + except NotImplementedError: + pass from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal,\ described from pypy.translator.js.main import rpython2javascript From fijal at codespeak.net Tue Dec 12 21:16:54 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 21:16:54 +0100 (CET) Subject: [py-svn] r35653 - py/dist/py/test/rsession Message-ID: <20061212201654.C5A1410084@code0.codespeak.net> Author: fijal Date: Tue Dec 12 21:16:53 2006 New Revision: 35653 Modified: py/dist/py/test/rsession/rsession.py py/dist/py/test/rsession/web.py Log: If config is not bind, let's raise AttributeError instead of NotImplementedError (thx pedronis) Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Tue Dec 12 21:16:53 2006 @@ -74,7 +74,7 @@ def __getattr__(self, attr): if self.config is None: - raise NotImplementedError("Need to set up config first") + raise AttributeError("Need to set up config first") return self.getvalue(attr) session_options = SessionOptions() Modified: py/dist/py/test/rsession/web.py ============================================================================== --- py/dist/py/test/rsession/web.py (original) +++ py/dist/py/test/rsession/web.py Tue Dec 12 21:16:53 2006 @@ -33,7 +33,7 @@ try: if not session_options.import_pypy: raise ImportError - except NotImplementedError: + except AttributeError: pass from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal,\ described From fijal at codespeak.net Tue Dec 12 21:21:53 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 21:21:53 +0100 (CET) Subject: [py-svn] r35654 - py/dist/py/test/testing Message-ID: <20061212202153.10CBB10083@code0.codespeak.net> Author: fijal Date: Tue Dec 12 21:21:52 2006 New Revision: 35654 Modified: py/dist/py/test/testing/test_collect.py Log: failing test once more, to see if hooks are working Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 21:21:52 2006 @@ -411,3 +411,6 @@ assert len(errors) == 0 +def test_fail(): + xxx + From fijal at codespeak.net Tue Dec 12 21:26:00 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 12 Dec 2006 21:26:00 +0100 (CET) Subject: [py-svn] r35656 - py/dist/py/test/testing Message-ID: <20061212202600.34EA710084@code0.codespeak.net> Author: fijal Date: Tue Dec 12 21:25:57 2006 New Revision: 35656 Modified: py/dist/py/test/testing/test_collect.py Log: breaking once more Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Tue Dec 12 21:25:57 2006 @@ -413,4 +413,4 @@ def test_fail(): xxx - + yy From arigo at codespeak.net Wed Dec 13 13:36:41 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 13 Dec 2006 13:36:41 +0100 (CET) Subject: [py-svn] r35671 - in py/dist/py: documentation misc Message-ID: <20061213123641.D897B10079@code0.codespeak.net> Author: arigo Date: Wed Dec 13 13:36:39 2006 New Revision: 35671 Modified: py/dist/py/documentation/confrest.py py/dist/py/misc/difftime.py Log: Tentative check-in. Print the date of modification instead of the "X days ago", which for PyPy's web site usually ends up as "47 seconds ago" and stays this way until the next check-in. Modified: py/dist/py/documentation/confrest.py ============================================================================== --- py/dist/py/documentation/confrest.py (original) +++ py/dist/py/documentation/confrest.py Wed Dec 13 13:36:39 2006 @@ -1,6 +1,6 @@ import py from py.__.misc.rest import convert_rest_html, strip_html_header -from py.__.misc.difftime import worded_diff_time +from py.__.misc.difftime import worded_time mydir = py.magic.autopath().dirpath() html = py.xml.html @@ -105,7 +105,7 @@ try: svninfo = txtpath.info() - modified = " modified %s by %s" % (worded_diff_time(svninfo.mtime), + modified = " modified %s by %s" % (worded_time(svninfo.mtime), getrealname(svninfo.last_author)) except (KeyboardInterrupt, SystemExit): raise Modified: py/dist/py/misc/difftime.py ============================================================================== --- py/dist/py/misc/difftime.py (original) +++ py/dist/py/misc/difftime.py Wed Dec 13 13:36:39 2006 @@ -23,3 +23,10 @@ plural = div > 1 and 's' or '' l.append('%d %s%s' %(div, _time_desc[key], plural)) return ", ".join(l) + " ago " + +_months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + +def worded_time(ctime): + tm = py.std.time.gmtime(ctime) + return "%s %d, %d" % (_months[tm.tm_mon-1], tm.tm_mday, tm.tm_year) From guido at codespeak.net Thu Dec 14 13:22:00 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Thu, 14 Dec 2006 13:22:00 +0100 (CET) Subject: [py-svn] r35732 - py/dist/py/path/svn Message-ID: <20061214122200.188DE1008A@code0.codespeak.net> Author: guido Date: Thu Dec 14 13:21:58 2006 New Revision: 35732 Modified: py/dist/py/path/svn/wccommand.py Log: Made that on non-existent revisions, svnwc.log() doesn't print stuff to stderr anymore. Also changed the exception that is raised when this occurs from xml.parsers.expat.ExpatError to ValueError... Not sure if it's the best choice, but pretty sure it's better than an ExpatError. ;) Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Thu Dec 14 13:21:58 2006 @@ -463,10 +463,18 @@ rev_opt = "-r %s:%s" % (rev_start, rev_end) verbose_opt = verbose and "-v" or "" s = svncommon.fixlocale() - xmlpipe = os.popen(s+'svn log --xml %s %s "%s"' % (rev_opt, \ - verbose_opt, self.strpath)) + # some blather on stderr + stdin, stdout, stderr = os.popen3(s + 'svn log --xml %s %s "%s"' % ( + rev_opt, verbose_opt, + self.strpath)) from xml.dom import minidom - tree = minidom.parse(xmlpipe) + from xml.parsers.expat import ExpatError + try: + tree = minidom.parse(stdout) + except ExpatError: + # XXX not entirely sure about this exception... shouldn't it be + # some py.error.* something? + raise ValueError('no such revision') result = [] for logentry in filter(None, tree.firstChild.childNodes): if logentry.nodeType == logentry.ELEMENT_NODE: From guido at codespeak.net Thu Dec 14 14:36:39 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Thu, 14 Dec 2006 14:36:39 +0100 (CET) Subject: [py-svn] r35737 - py/dist/py/rest Message-ID: <20061214133639.606211007A@code0.codespeak.net> Author: guido Date: Thu Dec 14 14:36:37 2006 New Revision: 35737 Modified: py/dist/py/rest/rst.py Log: Added small docstring to some exception (mostly to trigger .svntrigger on codespeak.net). Modified: py/dist/py/rest/rst.py ============================================================================== --- py/dist/py/rest/rst.py (original) +++ py/dist/py/rest/rst.py Thu Dec 14 14:36:37 2006 @@ -22,7 +22,7 @@ return txt class RestError(Exception): - pass + """ raised on containment errors (wrong parent) """ class AbstractMetaclass(type): def __new__(cls, *args): From guido at codespeak.net Thu Dec 14 14:56:22 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Thu, 14 Dec 2006 14:56:22 +0100 (CET) Subject: [py-svn] r35740 - py/dist/py/rest Message-ID: <20061214135622.92FA710083@code0.codespeak.net> Author: guido Date: Thu Dec 14 14:56:21 2006 New Revision: 35740 Modified: py/dist/py/rest/rst.py Log: Another docstring... Modified: py/dist/py/rest/rst.py ============================================================================== --- py/dist/py/rest/rst.py (original) +++ py/dist/py/rest/rst.py Thu Dec 14 14:56:21 2006 @@ -103,6 +103,8 @@ return [self.text()] class Rest(AbstractNode): + """ Root node of a document """ + sep = "\n\n" def __init__(self, *args, **kwargs): AbstractNode.__init__(self, *args, **kwargs) From guido at codespeak.net Thu Dec 14 15:37:13 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Thu, 14 Dec 2006 15:37:13 +0100 (CET) Subject: [py-svn] r35742 - py/dist/py/rest Message-ID: <20061214143713.5F8771007B@code0.codespeak.net> Author: guido Date: Thu Dec 14 15:37:09 2006 New Revision: 35742 Modified: py/dist/py/rest/rst.py Log: Yes! Another docstring! :| Modified: py/dist/py/rest/rst.py ============================================================================== --- py/dist/py/rest/rst.py (original) +++ py/dist/py/rest/rst.py Thu Dec 14 15:37:09 2006 @@ -134,6 +134,7 @@ return text + self.render_links() class Transition(AbstractNode): + """ a horizontal line """ parentclass = Rest def __init__(self, char='-', width=80, *args, **kwargs): From fijal at codespeak.net Thu Dec 14 16:29:12 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 14 Dec 2006 16:29:12 +0100 (CET) Subject: [py-svn] r35746 - in py/dist/py/test/rsession: . testing Message-ID: <20061214152912.75C421007C@code0.codespeak.net> Author: fijal Date: Thu Dec 14 16:29:10 2006 New Revision: 35746 Modified: py/dist/py/test/rsession/reporter.py py/dist/py/test/rsession/rest.py py/dist/py/test/rsession/rsession.py py/dist/py/test/rsession/testing/test_boxing.py Log: Fixed script return value. Modified: py/dist/py/test/rsession/reporter.py ============================================================================== --- py/dist/py/test/rsession/reporter.py (original) +++ py/dist/py/test/rsession/reporter.py Thu Dec 14 16:29:10 2006 @@ -41,7 +41,7 @@ repfun = getattr(self, "report_" + what.__class__.__name__, self.report_unknown) try: - repfun(what) + return repfun(what) except (KeyboardInterrupt, SystemExit): raise except: @@ -88,6 +88,7 @@ if hasattr(self, 'nodes'): # XXX: Testing self.hangs() self.summary() + return len(self.failed_tests_outcome) > 0 def hangs(self): h = [] Modified: py/dist/py/test/rsession/rest.py ============================================================================== --- py/dist/py/test/rsession/rest.py (original) +++ py/dist/py/test/rsession/rest.py Thu Dec 14 16:29:10 2006 @@ -47,6 +47,7 @@ def report_TestFinished(self, item): self.timeend = item.timeend self.summary() + return len(self.failed_tests_outcome) > 0 def report_ImmediateFailure(self, item): pass Modified: py/dist/py/test/rsession/rsession.py ============================================================================== --- py/dist/py/test/rsession/rsession.py (original) +++ py/dist/py/test/rsession/rsession.py Thu Dec 14 16:29:10 2006 @@ -207,10 +207,11 @@ teardown_hosts(reporter, [node.channel for node in nodes], nodes, exitfirst=self.config.option.exitfirst) reporter(report.Nodes(nodes)) - reporter(report.TestFinished()) + retval = reporter(report.TestFinished()) if startserverflag: from py.__.test.rsession.web import kill_server kill_server() + return retval class LSession(AbstractSession): """ Local version of session @@ -269,7 +270,7 @@ # XXX: We have to decide which runner to use at this point local_loop(self, reporter, itemgenerator, checkfun, self.config, runner=runner) - reporter(report.TestFinished()) + retval = reporter(report.TestFinished()) if startserverflag: from py.__.test.rsession.web import kill_server kill_server() @@ -286,3 +287,4 @@ "provided way of doing that in conftest") else: apigen.write_docs(self.docstorage) + return retval Modified: py/dist/py/test/rsession/testing/test_boxing.py ============================================================================== --- py/dist/py/test/rsession/testing/test_boxing.py (original) +++ py/dist/py/test/rsession/testing/test_boxing.py Thu Dec 14 16:29:10 2006 @@ -89,3 +89,4 @@ os.kill(pid, 15) par(pid) assert b.signal == 15 + From fijal at codespeak.net Thu Dec 14 16:43:05 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 14 Dec 2006 16:43:05 +0100 (CET) Subject: [py-svn] r35747 - py/dist/py/test/rsession/testing Message-ID: <20061214154305.7AD291007B@code0.codespeak.net> Author: fijal Date: Thu Dec 14 16:43:03 2006 New Revision: 35747 Modified: py/dist/py/test/rsession/testing/test_web.py Log: Dummy checking to see post-commit hook running. Modified: py/dist/py/test/rsession/testing/test_web.py ============================================================================== --- py/dist/py/test/rsession/testing/test_web.py (original) +++ py/dist/py/test/rsession/testing/test_web.py Thu Dec 14 16:43:03 2006 @@ -89,3 +89,4 @@ result = mq.get(4567) assert result == 2 assert mq.empty() + From fijal at codespeak.net Thu Dec 14 16:46:49 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 14 Dec 2006 16:46:49 +0100 (CET) Subject: [py-svn] r35748 - py/dist/py/test/testing Message-ID: <20061214154649.794341007B@code0.codespeak.net> Author: fijal Date: Thu Dec 14 16:46:47 2006 New Revision: 35748 Modified: py/dist/py/test/testing/test_collect.py Log: Remove dummy test Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Thu Dec 14 16:46:47 2006 @@ -410,7 +410,3 @@ l = list(col.tryiter(reporterror=errors.append)) assert len(errors) == 0 - -def test_fail(): - xxx - yy From fijal at codespeak.net Thu Dec 14 21:52:37 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 14 Dec 2006 21:52:37 +0100 (CET) Subject: [py-svn] r35762 - py/dist/py/apigen/source Message-ID: <20061214205237.3C0FF1007A@code0.codespeak.net> Author: fijal Date: Thu Dec 14 21:52:36 2006 New Revision: 35762 Modified: py/dist/py/apigen/source/server.py Log: skip test if pypy is not there Modified: py/dist/py/apigen/source/server.py ============================================================================== --- py/dist/py/apigen/source/server.py (original) +++ py/dist/py/apigen/source/server.py Thu Dec 14 21:52:36 2006 @@ -4,7 +4,10 @@ import py import time -from pypy.translator.js.examples import server +try: + from pypy.translator.js.examples import server +except ImportError: + py.test.skip("PyPy not present") from py.__.apigen.source.browser import parse_path from py.__.apigen.source.html import create_html from py.xml import html From fijal at codespeak.net Thu Dec 14 22:01:05 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 14 Dec 2006 22:01:05 +0100 (CET) Subject: [py-svn] r35763 - py/dist/py/code Message-ID: <20061214210105.C8E691007A@code0.codespeak.net> Author: fijal Date: Thu Dec 14 22:01:01 2006 New Revision: 35763 Modified: py/dist/py/code/source.py Log: workaround old python version Modified: py/dist/py/code/source.py ============================================================================== --- py/dist/py/code/source.py (original) +++ py/dist/py/code/source.py Thu Dec 14 22:01:01 2006 @@ -228,7 +228,10 @@ try: fullsource = obj.co_filename.__source__ except AttributeError: - strsrc = inspect.getsource(obj) + try: + strsrc = inspect.getsource(obj) + except IndentationError: + strsrc = "\"Buggy python version consider upgrading, cannot get source\"" assert isinstance(strsrc, str) return Source(strsrc, **kwargs) else: From fijal at codespeak.net Thu Dec 14 22:12:35 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 14 Dec 2006 22:12:35 +0100 (CET) Subject: [py-svn] r35764 - in py/dist/py: apigen/source test/rsession test/rsession/testing Message-ID: <20061214211235.D39011007A@code0.codespeak.net> Author: fijal Date: Thu Dec 14 22:12:30 2006 New Revision: 35764 Modified: py/dist/py/apigen/source/server.py py/dist/py/test/rsession/master.py py/dist/py/test/rsession/testing/test_web.py py/dist/py/test/rsession/testing/test_webjs.py Log: Unify pypy skips. Modified: py/dist/py/apigen/source/server.py ============================================================================== --- py/dist/py/apigen/source/server.py (original) +++ py/dist/py/apigen/source/server.py Thu Dec 14 22:12:30 2006 @@ -7,7 +7,7 @@ try: from pypy.translator.js.examples import server except ImportError: - py.test.skip("PyPy not present") + py.test.skip("PyPy not found") from py.__.apigen.source.browser import parse_path from py.__.apigen.source.html import create_html from py.xml import html Modified: py/dist/py/test/rsession/master.py ============================================================================== --- py/dist/py/test/rsession/master.py (original) +++ py/dist/py/test/rsession/master.py Thu Dec 14 22:12:30 2006 @@ -34,20 +34,25 @@ from py.__.test.rsession.rsession import session_options max_tasks_per_node = session_options.max_tasks_per_node - while 1: - try: - for node in masternodes: - if len(node.pending) < max_tasks_per_node: - item = itemgenerator.next() - if shouldstop(): - for _node in masternodes: - _node.send(StopIteration) # magic connector - return - node.send(item) - except StopIteration: - break - waiter() - + try: + while 1: + try: + for node in masternodes: + if len(node.pending) < max_tasks_per_node: + item = itemgenerator.next() + if shouldstop(): + for _node in masternodes: + _node.send(StopIteration) # magic connector + return + node.send(item) + except StopIteration: + break + waiter() + except (KeyboardInterrupt, SystemExit): + for _node in masternodes: + _node.send(StopIteration) + raise + def setup_slave(gateway, pkgpath, options): from py.__.test.rsession import slave import os Modified: py/dist/py/test/rsession/testing/test_web.py ============================================================================== --- py/dist/py/test/rsession/testing/test_web.py (original) +++ py/dist/py/test/rsession/testing/test_web.py Thu Dec 14 22:12:30 2006 @@ -10,7 +10,7 @@ commproxy.USE_MOCHIKIT = False except ImportError: - py.test.skip("No PyPy detected") + py.test.skip("PyPy not found") def setup_module(mod): config, args = py.test.Config.parse([]) Modified: py/dist/py/test/rsession/testing/test_webjs.py ============================================================================== --- py/dist/py/test/rsession/testing/test_webjs.py (original) +++ py/dist/py/test/rsession/testing/test_webjs.py Thu Dec 14 22:12:30 2006 @@ -2,7 +2,7 @@ try: import pypy except ImportError: - py.test.skip('missing PyPy') + py.test.skip('PyPy not found') from pypy.translator.js.tester import schedule_callbacks here = py.magic.autopath().dirpath() From fijal at codespeak.net Thu Dec 14 22:15:50 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 14 Dec 2006 22:15:50 +0100 (CET) Subject: [py-svn] r35765 - py/dist/py/test/rsession Message-ID: <20061214211550.3059C1007A@code0.codespeak.net> Author: fijal Date: Thu Dec 14 22:15:48 2006 New Revision: 35765 Modified: py/dist/py/test/rsession/master.py Log: didn't mean to check that in. Modified: py/dist/py/test/rsession/master.py ============================================================================== --- py/dist/py/test/rsession/master.py (original) +++ py/dist/py/test/rsession/master.py Thu Dec 14 22:15:48 2006 @@ -34,24 +34,20 @@ from py.__.test.rsession.rsession import session_options max_tasks_per_node = session_options.max_tasks_per_node - try: - while 1: - try: - for node in masternodes: - if len(node.pending) < max_tasks_per_node: - item = itemgenerator.next() - if shouldstop(): - for _node in masternodes: - _node.send(StopIteration) # magic connector - return - node.send(item) - except StopIteration: - break - waiter() - except (KeyboardInterrupt, SystemExit): - for _node in masternodes: - _node.send(StopIteration) - raise + while 1: + try: + for node in masternodes: + if len(node.pending) < max_tasks_per_node: + item = itemgenerator.next() + if shouldstop(): + for _node in masternodes: + _node.send(StopIteration) # magic connector + return + node.send(item) + except StopIteration: + break + waiter() + def setup_slave(gateway, pkgpath, options): from py.__.test.rsession import slave From fijal at codespeak.net Thu Dec 14 22:27:04 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 14 Dec 2006 22:27:04 +0100 (CET) Subject: [py-svn] r35766 - in py/dist/py/test/rsession: . testing Message-ID: <20061214212704.DAC7C1007A@code0.codespeak.net> Author: fijal Date: Thu Dec 14 22:27:02 2006 New Revision: 35766 Modified: py/dist/py/test/rsession/reporter.py py/dist/py/test/rsession/testing/test_reporter.py Log: Fixed real bug exposed by svntrigger Modified: py/dist/py/test/rsession/reporter.py ============================================================================== --- py/dist/py/test/rsession/reporter.py (original) +++ py/dist/py/test/rsession/reporter.py Thu Dec 14 22:27:02 2006 @@ -308,7 +308,7 @@ d = str(self.pkgdir.dirpath().dirpath()) if local.startswith(d): local = local[len(d) + 1:] - if name.startswith(local): + if local and name.startswith(local): name = name[len(local) + 1:] self.out.write("\n%s[%d] " % (name, lgt)) Modified: py/dist/py/test/rsession/testing/test_reporter.py ============================================================================== --- py/dist/py/test/rsession/testing/test_reporter.py (original) +++ py/dist/py/test/rsession/testing/test_reporter.py Thu Dec 14 22:27:02 2006 @@ -144,10 +144,12 @@ self._test_module() def test_full_module(self): - assert self._test_full_module() == """ + received = self._test_full_module() + expected = """ repmod/test_one.py[1] repmod/test_three.py[0] - FAILED TO LOAD MODULE repmod/test_two.py[0] - skipped (reason)""" + assert received == expected class TestRemoteReporter(AbstractTestReporter): reporter = RemoteReporter From fijal at codespeak.net Thu Dec 14 22:53:34 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 14 Dec 2006 22:53:34 +0100 (CET) Subject: [py-svn] r35769 - py/dist/py/test/rsession/testing Message-ID: <20061214215334.24D0F1007A@code0.codespeak.net> Author: fijal Date: Thu Dec 14 22:53:31 2006 New Revision: 35769 Modified: py/dist/py/test/rsession/testing/test_boxing.py Log: Increase the timeout to check if this still fails. Modified: py/dist/py/test/rsession/testing/test_boxing.py ============================================================================== --- py/dist/py/test/rsession/testing/test_boxing.py (original) +++ py/dist/py/test/rsession/testing/test_boxing.py Thu Dec 14 22:53:31 2006 @@ -82,7 +82,7 @@ import time def box_fun(): - time.sleep(300) # we don't want to last forever here + time.sleep(1500) # we don't want to last forever here b = RealBox(box_fun) par, pid = b.run(continuation=True) From guido at codespeak.net Fri Dec 15 12:52:47 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Fri, 15 Dec 2006 12:52:47 +0100 (CET) Subject: [py-svn] r35789 - py/dist/py/rest Message-ID: <20061215115247.600D01007C@code0.codespeak.net> Author: guido Date: Fri Dec 15 12:52:46 2006 New Revision: 35789 Modified: py/dist/py/rest/rst.py Log: More docstrings. Modified: py/dist/py/rest/rst.py ============================================================================== --- py/dist/py/rest/rst.py (original) +++ py/dist/py/rest/rst.py Fri Dec 15 12:52:46 2006 @@ -146,6 +146,8 @@ return (self.width - 1) * self.char class Paragraph(AbstractNode): + """ simple paragraph """ + parentclass = Rest sep = " " indent = "" @@ -189,9 +191,13 @@ return "\n".join(outcome) class SubParagraph(Paragraph): + """ indented sub paragraph """ + indent = " " class Title(Paragraph): + """ title element """ + parentclass = Rest belowchar = "=" abovechar = "" From guido at codespeak.net Fri Dec 15 14:14:39 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Fri, 15 Dec 2006 14:14:39 +0100 (CET) Subject: [py-svn] r35793 - py/dist/py/test/rsession/testing Message-ID: <20061215131439.672481007B@code0.codespeak.net> Author: guido Date: Fri Dec 15 14:14:38 2006 New Revision: 35793 Modified: py/dist/py/test/rsession/testing/test_boxing.py Log: Just a little test. Modified: py/dist/py/test/rsession/testing/test_boxing.py ============================================================================== --- py/dist/py/test/rsession/testing/test_boxing.py (original) +++ py/dist/py/test/rsession/testing/test_boxing.py Fri Dec 15 14:14:38 2006 @@ -86,6 +86,7 @@ b = RealBox(box_fun) par, pid = b.run(continuation=True) + py.std.time.sleep(1) os.kill(pid, 15) par(pid) assert b.signal == 15 From guido at codespeak.net Fri Dec 15 15:10:45 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Fri, 15 Dec 2006 15:10:45 +0100 (CET) Subject: [py-svn] r35802 - py/dist/py/test/rsession/testing Message-ID: <20061215141045.857511007C@code0.codespeak.net> Author: guido Date: Fri Dec 15 15:10:44 2006 New Revision: 35802 Modified: py/dist/py/test/rsession/testing/test_boxing.py Log: Trying to figure out why the tests fail in .svntrigger situation. Modified: py/dist/py/test/rsession/testing/test_boxing.py ============================================================================== --- py/dist/py/test/rsession/testing/test_boxing.py (original) +++ py/dist/py/test/rsession/testing/test_boxing.py Fri Dec 15 15:10:44 2006 @@ -83,11 +83,15 @@ def box_fun(): time.sleep(1500) # we don't want to last forever here + open('/tmp/boxingtest_thisshouldnotbehere', 'w').write('grmbl') b = RealBox(box_fun) par, pid = b.run(continuation=True) py.std.time.sleep(1) - os.kill(pid, 15) + try: + os.kill(pid, 15) + except OSError: + py.test.skip('strange situation in which os.kill fails...') par(pid) assert b.signal == 15 From stephan at codespeak.net Fri Dec 15 15:53:59 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Fri, 15 Dec 2006 15:53:59 +0100 (CET) Subject: [py-svn] r35804 - in py/dist/py/magic: . testing Message-ID: <20061215145359.62F191007B@code0.codespeak.net> Author: stephan Date: Fri Dec 15 15:53:58 2006 New Revision: 35804 Added: py/dist/py/magic/coroutine.py py/dist/py/magic/testing/test_coroutine.py Log: coroutine is a thin experimental wrapper around greenlets Added: py/dist/py/magic/coroutine.py ============================================================================== --- (empty file) +++ py/dist/py/magic/coroutine.py Fri Dec 15 15:53:58 2006 @@ -0,0 +1,76 @@ +""" +This is a thin wrapper around the greenlet module to provide the +coroutine interface as used in pypy. + +>>> from py.magic import coroutine +>>> def f(txt, coro=None): +... print txt, +... if coro is not None: +... coro.switch() +... +>>> coro1 = coroutine() +>>> coro2 = coroutine() +>>> coro1.bind(f,'hello',coro2) +>>> coro2.bind(f,'world') +>>> coro1.switch() +hello world +>>> +""" + +try: + from functools import partial +except ImportError: # we are not running python 2.5 + class partial(object): + # just enough of 'partial' to be usefull + def __init__(self, func, *argl, **argd): + self.func = func + self.argl = argl + self.argd = argd + + def __call__(self): + return self.func(*self.argl, **self.argd) + +from py.magic import greenlet + +reg = {} + +class coroutine(object): + + def __init__(self): + self._frame = greenlet() + reg[self._frame] = self + + def __getattr__(self, attr): + return getattr(self._frame, attr) + + def bind(self, func, *argl, **argd): + if self._frame.dead: + self._frame = greenlet() + if hasattr(self._frame, 'run') and self._frame.run: + raise ValueError("cannot bind a bound coroutine") + self._frame.run = partial(func, *argl, **argd) + + def switch(self): + return greenlet.switch(self._frame) + + def kill(self): + self._frame.throw() + + @property + def is_zombie(self): + return self._frame.dead + + @property + def is_alive(self): + return not self._frame.dead + + @staticmethod + def getcurrent(): + return reg[greenlet.getcurrent()] + +maincoro = coroutine() +maingreenlet = greenlet.getcurrent() +maincoro._frame = maingreenlet +reg[maingreenlet] = maincoro +del maincoro +del maingreenlet Added: py/dist/py/magic/testing/test_coroutine.py ============================================================================== --- (empty file) +++ py/dist/py/magic/testing/test_coroutine.py Fri Dec 15 15:53:58 2006 @@ -0,0 +1,92 @@ +from py.magic import coroutine + +from py.test import skip, raises + +class Test_Coroutine: + + def test_is_zombie(self): + co = coroutine() + def f(): + print 'in coro' + co.bind(f) + assert not co.is_zombie + + def test_raise_propagate(self): + co = coroutine() + def f(): + return 1/0 + co.bind(f) + try: + co.switch() + except ZeroDivisionError: + pass + else: + raise AssertionError("exception not propagated") + + def test_strange_test(self): + def f(): + return 42 + def create(): + b = coroutine() + b.bind(f) + b.switch() + return b + a = coroutine() + a.bind(create) + b = a.switch() + def nothing(): + pass + a.bind(nothing) + def kill(): + a.kill() + b.bind(kill) + b.switch() + + def test_kill(self): + co = coroutine() + def f(): + pass + co.bind(f) + assert co.is_alive + co.kill() + assert not co.is_alive + + def test_bogus_bind(self): + co = coroutine() + def f(): + pass + co.bind(f) + raises(ValueError, co.bind, f) + + def test_simple_task(self): + maintask = coroutine.getcurrent() + def f():pass + co = coroutine() + co.bind(f) + co.switch() + assert not co.is_alive + assert maintask is coroutine.getcurrent() + + def test_backto_main(self): + maintask = coroutine.getcurrent() + def f(task): + task.switch() + co = coroutine() + co.bind(f,maintask) + co.switch() + + def test_wrapped_main(self): + class mwrap(object): + def __init__(self, coro): + self._coro = coro + + def __getattr__(self, attr): + return getattr(self._coro, attr) + + maintask = mwrap(coroutine.getcurrent()) + def f(task): + task.switch() + co = coroutine() + co.bind(f,maintask) + co.switch() + From stephan at codespeak.net Fri Dec 15 16:19:48 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Fri, 15 Dec 2006 16:19:48 +0100 (CET) Subject: [py-svn] r35807 - py/dist/py Message-ID: <20061215151948.9F64D10086@code0.codespeak.net> Author: stephan Date: Fri Dec 15 16:19:47 2006 New Revision: 35807 Modified: py/dist/py/__init__.py Log: upps, forgot the changed py.__init__.py Modified: py/dist/py/__init__.py ============================================================================== --- py/dist/py/__init__.py (original) +++ py/dist/py/__init__.py Fri Dec 15 16:19:47 2006 @@ -81,6 +81,7 @@ 'magic.autopath' : ('./magic/autopath.py', 'autopath'), 'magic.View' : ('./magic/viewtype.py', 'View'), 'magic.AssertionError' : ('./magic/assertion.py', 'AssertionError'), + 'magic.coroutine' : ('./magic/coroutine.py', 'coroutine'), # python inspection/code-generation API 'code.compile' : ('./code/source.py', 'compile_'), From stephan at codespeak.net Fri Dec 15 17:42:44 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Fri, 15 Dec 2006 17:42:44 +0100 (CET) Subject: [py-svn] r35813 - in py/dist/py: . magic magic/testing Message-ID: <20061215164244.1F8B110083@code0.codespeak.net> Author: stephan Date: Fri Dec 15 17:42:42 2006 New Revision: 35813 Removed: py/dist/py/magic/coroutine.py py/dist/py/magic/testing/test_coroutine.py Modified: py/dist/py/__init__.py Log: removed the coroutine interface by public demand Modified: py/dist/py/__init__.py ============================================================================== --- py/dist/py/__init__.py (original) +++ py/dist/py/__init__.py Fri Dec 15 17:42:42 2006 @@ -81,7 +81,6 @@ 'magic.autopath' : ('./magic/autopath.py', 'autopath'), 'magic.View' : ('./magic/viewtype.py', 'View'), 'magic.AssertionError' : ('./magic/assertion.py', 'AssertionError'), - 'magic.coroutine' : ('./magic/coroutine.py', 'coroutine'), # python inspection/code-generation API 'code.compile' : ('./code/source.py', 'compile_'), Deleted: /py/dist/py/magic/coroutine.py ============================================================================== --- /py/dist/py/magic/coroutine.py Fri Dec 15 17:42:42 2006 +++ (empty file) @@ -1,76 +0,0 @@ -""" -This is a thin wrapper around the greenlet module to provide the -coroutine interface as used in pypy. - ->>> from py.magic import coroutine ->>> def f(txt, coro=None): -... print txt, -... if coro is not None: -... coro.switch() -... ->>> coro1 = coroutine() ->>> coro2 = coroutine() ->>> coro1.bind(f,'hello',coro2) ->>> coro2.bind(f,'world') ->>> coro1.switch() -hello world ->>> -""" - -try: - from functools import partial -except ImportError: # we are not running python 2.5 - class partial(object): - # just enough of 'partial' to be usefull - def __init__(self, func, *argl, **argd): - self.func = func - self.argl = argl - self.argd = argd - - def __call__(self): - return self.func(*self.argl, **self.argd) - -from py.magic import greenlet - -reg = {} - -class coroutine(object): - - def __init__(self): - self._frame = greenlet() - reg[self._frame] = self - - def __getattr__(self, attr): - return getattr(self._frame, attr) - - def bind(self, func, *argl, **argd): - if self._frame.dead: - self._frame = greenlet() - if hasattr(self._frame, 'run') and self._frame.run: - raise ValueError("cannot bind a bound coroutine") - self._frame.run = partial(func, *argl, **argd) - - def switch(self): - return greenlet.switch(self._frame) - - def kill(self): - self._frame.throw() - - @property - def is_zombie(self): - return self._frame.dead - - @property - def is_alive(self): - return not self._frame.dead - - @staticmethod - def getcurrent(): - return reg[greenlet.getcurrent()] - -maincoro = coroutine() -maingreenlet = greenlet.getcurrent() -maincoro._frame = maingreenlet -reg[maingreenlet] = maincoro -del maincoro -del maingreenlet Deleted: /py/dist/py/magic/testing/test_coroutine.py ============================================================================== --- /py/dist/py/magic/testing/test_coroutine.py Fri Dec 15 17:42:42 2006 +++ (empty file) @@ -1,92 +0,0 @@ -from py.magic import coroutine - -from py.test import skip, raises - -class Test_Coroutine: - - def test_is_zombie(self): - co = coroutine() - def f(): - print 'in coro' - co.bind(f) - assert not co.is_zombie - - def test_raise_propagate(self): - co = coroutine() - def f(): - return 1/0 - co.bind(f) - try: - co.switch() - except ZeroDivisionError: - pass - else: - raise AssertionError("exception not propagated") - - def test_strange_test(self): - def f(): - return 42 - def create(): - b = coroutine() - b.bind(f) - b.switch() - return b - a = coroutine() - a.bind(create) - b = a.switch() - def nothing(): - pass - a.bind(nothing) - def kill(): - a.kill() - b.bind(kill) - b.switch() - - def test_kill(self): - co = coroutine() - def f(): - pass - co.bind(f) - assert co.is_alive - co.kill() - assert not co.is_alive - - def test_bogus_bind(self): - co = coroutine() - def f(): - pass - co.bind(f) - raises(ValueError, co.bind, f) - - def test_simple_task(self): - maintask = coroutine.getcurrent() - def f():pass - co = coroutine() - co.bind(f) - co.switch() - assert not co.is_alive - assert maintask is coroutine.getcurrent() - - def test_backto_main(self): - maintask = coroutine.getcurrent() - def f(task): - task.switch() - co = coroutine() - co.bind(f,maintask) - co.switch() - - def test_wrapped_main(self): - class mwrap(object): - def __init__(self, coro): - self._coro = coro - - def __getattr__(self, attr): - return getattr(self._coro, attr) - - maintask = mwrap(coroutine.getcurrent()) - def f(task): - task.switch() - co = coroutine() - co.bind(f,maintask) - co.switch() - From arigo at codespeak.net Sat Dec 16 15:50:27 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 16 Dec 2006 15:50:27 +0100 (CET) Subject: [py-svn] r35834 - in py/dist/py/execnet: . testing Message-ID: <20061216145027.C7BFA1007B@code0.codespeak.net> Author: arigo Date: Sat Dec 16 15:50:24 2006 New Revision: 35834 Modified: py/dist/py/execnet/register.py py/dist/py/execnet/testing/test_gateway.py Log: Avoid confusing execnet with os.write() statements. When execnet uses fd 0 and 1 for its own communications, we redirect them in such a way that if the application also does I/O on fd 0 and 1, it just goes to /dev/null. Modified: py/dist/py/execnet/register.py ============================================================================== --- py/dist/py/execnet/register.py (original) +++ py/dist/py/execnet/register.py Sat Dec 16 15:50:24 2006 @@ -97,6 +97,26 @@ s = "\n".join([extra, "import sys ; sys.path[:0] = %r" % (plist,), "import os ; os.environ['PYTHONPATH'] = %r" % ppath, + # redirect file descriptors 0 and 1 to /dev/null, to avoid + # complete confusion (this is independent from the sys.stdout + # and sys.stderr redirection that gateway.remote_exec() can do) + str(py.code.Source(""" + try: + devnull = os.devnull + except AttributeError: + if os.name == 'nt': + devnull = 'NUL' + else: + devnull = '/dev/null' + sys.stdin = os.fdopen(os.dup(0), 'rb', 0) + sys.stdout = os.fdopen(os.dup(1), 'wb', 0) + fd = os.open(devnull, os.O_RDONLY) + os.dup2(fd, 0) + os.close(fd) + fd = os.open(devnull, os.O_WRONLY) + os.dup2(fd, 1) + os.close(fd) + """)), "" ]) super(PopenGateway, self).remote_bootstrap_gateway(io, s) Modified: py/dist/py/execnet/testing/test_gateway.py ============================================================================== --- py/dist/py/execnet/testing/test_gateway.py (original) +++ py/dist/py/execnet/testing/test_gateway.py Sat Dec 16 15:50:24 2006 @@ -308,6 +308,21 @@ assert first.strip() == 'hello world' py.test.raises(EOFError, channel.receive) + def test_confusion_from_os_write(self): + channel = self.gw.remote_exec(""" + import os + os.write(1, 'confusion!') + os.write(2, 'test') + channel.send(channel.receive() * 6) + channel.send(channel.receive() * 6) + """) + channel.send(3) + res = channel.receive() + assert res == 18 + channel.send(7) + res = channel.receive() + assert res == 42 + #class TestBlockingIssues: # def test_join_blocked_execution_gateway(self): # gateway = py.execnet.PopenGateway() From cfbolz at codespeak.net Sat Dec 16 21:30:14 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 16 Dec 2006 21:30:14 +0100 (CET) Subject: [py-svn] r35836 - in py/dist/py: bin misc rest rest/testing Message-ID: <20061216203014.1C49C10081@code0.codespeak.net> Author: cfbolz Date: Sat Dec 16 21:30:10 2006 New Revision: 35836 Modified: py/dist/py/bin/py.rest py/dist/py/misc/rest.py py/dist/py/rest/directive.py py/dist/py/rest/testing/test_directive.py Log: refactor the graphviz directive to make it useable with docutils versions > 4.0. Slightly messy code :-( Modified: py/dist/py/bin/py.rest ============================================================================== --- py/dist/py/bin/py.rest (original) +++ py/dist/py/bin/py.rest Sat Dec 16 21:30:10 2006 @@ -47,7 +47,7 @@ filenames = [py.path.svnwc(x) for x in args] if options.topdf: - directive.BackendStore("latex") + directive.set_backend_and_register_directives("latex") for p in filenames: if not p.check(): @@ -62,7 +62,7 @@ rest.process(x) elif p.check(file=1): if p.ext == ".rst2pdfconfig": - directive.BackendStore("latex") + directive.set_backend_and_register_directives("latex") process_configfile(p, options.debug) else: if options.topdf: Modified: py/dist/py/misc/rest.py ============================================================================== --- py/dist/py/misc/rest.py (original) +++ py/dist/py/misc/rest.py Sat Dec 16 21:30:10 2006 @@ -17,7 +17,7 @@ stylesheet path (to be used if any) """ from docutils.core import publish_string - directive.BackendStore("html") + directive.set_backend_and_register_directives("html") kwargs = { 'stylesheet' : stylesheet, 'stylesheet_path': None, Modified: py/dist/py/rest/directive.py ============================================================================== --- py/dist/py/rest/directive.py (original) +++ py/dist/py/rest/directive.py Sat Dec 16 21:30:10 2006 @@ -1,8 +1,10 @@ +# XXX this file is messy since it tries to deal with several docutils versions import py from py.__.rest.convert import convert_dot, latexformula2png import sys +import docutils from docutils import nodes from docutils.parsers.rst import directives, states, roles from docutils.parsers.rst.directives import images @@ -12,63 +14,87 @@ except ImportError: from docutils.parsers.rst.states import unescape # docutils 0.3.5 -backend_to_image_format = {"html": "png", "latex": "pdf"} +if docutils.__version__ >= '0.5': + ImageClass = images.Image + +else: + class ImageClass(object): + option_spec = images.image.options + def run(self): + return images.image(u'image', + self.arguments, + self.options, + self.content, + self.lineno, + self.content_offset, + self.block_text, + self.state, + self.state_machine) -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 - # format - def __init__(self, backend): - 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) +backend_to_image_format = {"html": "png", "latex": "pdf"} + +class GraphvizDirective(ImageClass): def convert(self, fn, path): path = py.path.local(path).dirpath() dot = path.join(fn) - result = convert_dot(dot, self.convert_to_format) + result = convert_dot(dot, backend_to_image_format[_backend]) return result.relto(path) - 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) - 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} - - 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(unescape(text, True), image) - imagenode = nodes.image(image.relto(sourcedir), uri=image.relto(sourcedir)) - return [imagenode], [] - latexformula_role.content = True - latexformula_role.options = {} - + def run(self): + newname = self.convert(self.arguments[0], + self.state.document.settings._source) + text = self.block_text.replace("graphviz", "image", 1) + self.block_text = text.replace(self.arguments[0], newname, 1) + self.name = u'image' + self.arguments = [newname] + return ImageClass.run(self) + + def old_interface(self): + def f(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + for arg in "name arguments options content lineno " \ + "content_offset block_text state state_machine".split(): + setattr(self, arg, locals()[arg]) + return self.run() + f.arguments = (1, 0, 1) + f.options = self.option_spec + return f + + +_backend = None +def set_backend_and_register_directives(backend): + #XXX this is only used to work around the inflexibility of docutils: + # a directive does not know the target format + global _backend + _backend = backend + if docutils.__version__ >= "0.5": + directives.register_directive("graphviz", GraphvizDirective) + else: + directives.register_directive("graphviz", + GraphvizDirective().old_interface()) + roles.register_canonical_role("latexformula", latexformula_role) + +def latexformula_role(name, rawtext, text, lineno, inliner, + options={}, content=[]): + if _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(unescape(text, True), image) + imagenode = nodes.image(image.relto(sourcedir), uri=image.relto(sourcedir)) + return [imagenode], [] +latexformula_role.content = True +latexformula_role.options = {} Modified: py/dist/py/rest/testing/test_directive.py ============================================================================== --- py/dist/py/rest/testing/test_directive.py (original) +++ py/dist/py/rest/testing/test_directive.py Sat Dec 16 21:30:10 2006 @@ -12,7 +12,7 @@ def test_graphviz_html(): if not is_on_path("dot"): py.test.skip("graphviz needed") - directive.BackendStore("html") + directive.set_backend_and_register_directives("html") #for reasons that elude me rest.process expects svnwcs??? if not is_on_path("svn"): py.test.skip("svn needed") @@ -28,10 +28,10 @@ png.remove() def test_graphviz_pdf(): - if is_on_path("dot") or not is_on_path("latex"): + if not is_on_path("dot") or not is_on_path("latex"): py.test.skip("graphviz and latex needed") - directive.BackendStore("latex") + directive.set_backend_and_register_directives("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 16 23:01:44 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 16 Dec 2006 23:01:44 +0100 (CET) Subject: [py-svn] r35837 - py/dist/py/rest Message-ID: <20061216220144.0D8161007F@code0.codespeak.net> Author: cfbolz Date: Sat Dec 16 23:01:42 2006 New Revision: 35837 Modified: py/dist/py/rest/directive.py Log: just checking docutils.__version__ is not enough :-( Modified: py/dist/py/rest/directive.py ============================================================================== --- py/dist/py/rest/directive.py (original) +++ py/dist/py/rest/directive.py Sat Dec 16 23:01:42 2006 @@ -9,12 +9,17 @@ from docutils.parsers.rst import directives, states, roles from docutils.parsers.rst.directives import images +if hasattr(images, "image"): + directives_are_functions = True +else: + directives_are_functions = False + try: from docutils.utils import unescape # docutils version > 0.3.5 except ImportError: from docutils.parsers.rst.states import unescape # docutils 0.3.5 -if docutils.__version__ >= '0.5': +if not directives_are_functions: ImageClass = images.Image else: @@ -68,7 +73,7 @@ # a directive does not know the target format global _backend _backend = backend - if docutils.__version__ >= "0.5": + if not directives_are_functions: directives.register_directive("graphviz", GraphvizDirective) else: directives.register_directive("graphviz", From arigo at codespeak.net Sun Dec 17 14:00:55 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 17 Dec 2006 14:00:55 +0100 (CET) Subject: [py-svn] r35839 - py/dist/py/test/rsession Message-ID: <20061217130055.3C93010072@code0.codespeak.net> Author: arigo Date: Sun Dec 17 14:00:53 2006 New Revision: 35839 Modified: py/dist/py/test/rsession/box.py py/dist/py/test/rsession/rsync.py Log: Minor clean-ups. Move the (commented-out) prints in rsync to their proper place. Modified: py/dist/py/test/rsession/box.py ============================================================================== --- py/dist/py/test/rsession/box.py (original) +++ py/dist/py/test/rsession/box.py Sun Dec 17 14:00:53 2006 @@ -8,8 +8,6 @@ import sys import marshal -#NICE_LEVEL = 0 # XXX make it a conftest option - PYTESTSTDOUT = "pyteststdout" PYTESTSTDERR = "pyteststderr" PYTESTRETVAL = "pytestretval" @@ -94,7 +92,6 @@ os.dup2(fdstderr, 2) retvalf = self.PYTESTRETVAL.open("w") try: - from py.__.test.rsession.rsession import remote_options if nice_level: os.nice(nice_level) retval = self.fun(*self.args, **self.kwargs) Modified: py/dist/py/test/rsession/rsync.py ============================================================================== --- py/dist/py/test/rsession/rsync.py (original) +++ py/dist/py/test/rsession/rsync.py Sun Dec 17 14:00:53 2006 @@ -52,8 +52,6 @@ else: modified_rel_path, checksum = req modifiedpath = os.path.join(self.sourcedir, *modified_rel_path) - #print channel.gateway.getremoteaddress(), - #print '/'.join(modified_rel_path) f = open(modifiedpath, 'rb') data = f.read() f.close() @@ -63,6 +61,8 @@ # ! there is a reason for the interning: # sharing multiple copies of the file's data data = intern(data) + #print channel.gateway.getremoteaddress(), + #print '/'.join(modified_rel_path) channel.send(data) del data From guido at codespeak.net Mon Dec 18 14:34:54 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 18 Dec 2006 14:34:54 +0100 (CET) Subject: [py-svn] r35847 - in py/dist/py/test/rsession: . testing Message-ID: <20061218133454.72E931005A@code0.codespeak.net> Author: guido Date: Mon Dec 18 14:34:52 2006 New Revision: 35847 Modified: py/dist/py/test/rsession/conftest.py py/dist/py/test/rsession/testing/test_boxing.py Log: Added cmdline option to skip the test that keeps failing on codespeak.net (some problem with multiple levels of nested scripts, some of which do strange setuid tricks) so that we can make all tests run on that host, and install the svn 'send email on broken tests' thingie. Modified: py/dist/py/test/rsession/conftest.py ============================================================================== --- py/dist/py/test/rsession/conftest.py (original) +++ py/dist/py/test/rsession/conftest.py Mon Dec 18 14:34:52 2006 @@ -1,8 +1,15 @@ -#import py -#Option = py.test.Config.Option +import py +Option = py.test.Config.Option #defaultwait = 100.0 +option = py.test.Config.addoptions("boxing test options", + Option('', '--skip-kill-test', action='store_true', dest='skip_kill_test', + help='skip a certain test that checks for os.kill results, this ' + 'should be used when kill() is not allowed for the current ' + 'user'), +) + #option = py.test.Config.addoptions("distributed testing options", # Option('-D', '--disthosts', # action="store", dest="disthosts", default=None, Modified: py/dist/py/test/rsession/testing/test_boxing.py ============================================================================== --- py/dist/py/test/rsession/testing/test_boxing.py (original) +++ py/dist/py/test/rsession/testing/test_boxing.py Mon Dec 18 14:34:52 2006 @@ -9,6 +9,7 @@ from py.__.test.rsession.box import Box, RealBox, ScreenBox from py.__.test.rsession.testing import example2 +from py.__.test.rsession.conftest import option def setup_module(mod): from py.__.test.rsession.rsession import remote_options @@ -76,22 +77,19 @@ assert b.retval == 2 def test_box_killer(): + if option.skip_kill_test: + py.test.skip('skipping kill test') class A: pass info = A() import time def box_fun(): - time.sleep(1500) # we don't want to last forever here - open('/tmp/boxingtest_thisshouldnotbehere', 'w').write('grmbl') + time.sleep(10) # we don't want to last forever here b = RealBox(box_fun) par, pid = b.run(continuation=True) - py.std.time.sleep(1) - try: - os.kill(pid, 15) - except OSError: - py.test.skip('strange situation in which os.kill fails...') + os.kill(pid, 15) par(pid) assert b.signal == 15 From guido at codespeak.net Mon Dec 18 15:26:04 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 18 Dec 2006 15:26:04 +0100 (CET) Subject: [py-svn] r35850 - py/dist/py/bin Message-ID: <20061218142604.5D56F10074@code0.codespeak.net> Author: guido Date: Mon Dec 18 15:25:55 2006 New Revision: 35850 Modified: py/dist/py/bin/pytest.cmd Log: Fixed quoting for paths that contain spaces. Modified: py/dist/py/bin/pytest.cmd ============================================================================== --- py/dist/py/bin/pytest.cmd (original) +++ py/dist/py/bin/pytest.cmd Mon Dec 18 15:25:55 2006 @@ -1,3 +1,3 @@ @echo off -python %~dp0\py.test %* +python "%~dp0\py.test" %* From guido at codespeak.net Mon Dec 18 15:40:12 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 18 Dec 2006 15:40:12 +0100 (CET) Subject: [py-svn] r35851 - py/dist/py/execnet Message-ID: <20061218144012.AEFD510069@code0.codespeak.net> Author: guido Date: Mon Dec 18 15:39:21 2006 New Revision: 35851 Modified: py/dist/py/execnet/register.py Log: Added the same hack for fd 2 on win32 as there is for fd 0 and 1, because in some cases os.write(2, ...) still seems to block there. Modified: py/dist/py/execnet/register.py ============================================================================== --- py/dist/py/execnet/register.py (original) +++ py/dist/py/execnet/register.py Mon Dec 18 15:39:21 2006 @@ -100,6 +100,9 @@ # redirect file descriptors 0 and 1 to /dev/null, to avoid # complete confusion (this is independent from the sys.stdout # and sys.stderr redirection that gateway.remote_exec() can do) + # note that we redirect fd 2 on win too, since for some reason that + # blocks there, while it works (sending to stderr if possible else + # ignoring) on *nix str(py.code.Source(""" try: devnull = os.devnull @@ -110,11 +113,15 @@ devnull = '/dev/null' sys.stdin = os.fdopen(os.dup(0), 'rb', 0) sys.stdout = os.fdopen(os.dup(1), 'wb', 0) + if os.name == 'nt': + sys.stderr = os.fdopen(os.dup(2), 'wb', 0) fd = os.open(devnull, os.O_RDONLY) os.dup2(fd, 0) os.close(fd) fd = os.open(devnull, os.O_WRONLY) os.dup2(fd, 1) + if os.name == 'nt': + os.dup2(fd, 2) os.close(fd) """)), "" From guido at codespeak.net Mon Dec 18 15:42:47 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 18 Dec 2006 15:42:47 +0100 (CET) Subject: [py-svn] r35852 - py/dist/py/execnet/testing Message-ID: <20061218144247.EAD8910069@code0.codespeak.net> Author: guido Date: Mon Dec 18 15:42:46 2006 New Revision: 35852 Modified: py/dist/py/execnet/testing/test_gateway.py Log: Added some tests (all already succeeding btw) for error reporting in execnet, spread the 'confusion_from_os_write' test over two tests, seperately testing fd 1 and 2. Modified: py/dist/py/execnet/testing/test_gateway.py ============================================================================== --- py/dist/py/execnet/testing/test_gateway.py (original) +++ py/dist/py/execnet/testing/test_gateway.py Mon Dec 18 15:42:46 2006 @@ -137,6 +137,26 @@ channel.RemoteError("error")) py.test.raises(channel.RemoteError, channel.waitclose, 0.01) + def test_channel_error_reporting(self): + channel = self.gw.remote_exec('def foo():\n return foobar()\nfoo()\n') + try: + channel.receive() + except channel.RemoteError, e: + assert str(e).startswith('Traceback (most recent call last):') + assert str(e).find('NameError: global name \'foobar\' ' + 'is not defined') > -1 + else: + py.test.fail('No exception raised') + + def test_channel_syntax_error(self): + # missing colon + channel = self.gw.remote_exec('def foo()\n return 1\nfoo()\n') + try: + channel.receive() + except channel.RemoteError, e: + assert str(e).startswith('Traceback (most recent call last):') + assert str(e).find('SyntaxError') > -1 + def test_channel_iter(self): channel = self.gw.remote_exec(""" for x in range(3): @@ -308,10 +328,23 @@ assert first.strip() == 'hello world' py.test.raises(EOFError, channel.receive) - def test_confusion_from_os_write(self): + def test_confusion_from_os_write_stdout(self): channel = self.gw.remote_exec(""" import os os.write(1, 'confusion!') + channel.send(channel.receive() * 6) + channel.send(channel.receive() * 6) + """) + channel.send(3) + res = channel.receive() + assert res == 18 + channel.send(7) + res = channel.receive() + assert res == 42 + + def test_confusion_from_os_write_stdout(self): + channel = self.gw.remote_exec(""" + import os os.write(2, 'test') channel.send(channel.receive() * 6) channel.send(channel.receive() * 6) @@ -433,3 +466,4 @@ py.test.raises(EOFError, channel.receive) # now it did py.test.raises(IOError, gw.remote_exec, "...") + From arigo at codespeak.net Tue Dec 19 15:09:29 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 19 Dec 2006 15:09:29 +0100 (CET) Subject: [py-svn] r35888 - py/dist/py/execnet/testing Message-ID: <20061219140929.2DEE710078@code0.codespeak.net> Author: arigo Date: Tue Dec 19 15:09:18 2006 New Revision: 35888 Modified: py/dist/py/execnet/testing/test_gateway.py Log: Two tests with the same name. Bad idea. Modified: py/dist/py/execnet/testing/test_gateway.py ============================================================================== --- py/dist/py/execnet/testing/test_gateway.py (original) +++ py/dist/py/execnet/testing/test_gateway.py Tue Dec 19 15:09:18 2006 @@ -342,7 +342,7 @@ res = channel.receive() assert res == 42 - def test_confusion_from_os_write_stdout(self): + def test_confusion_from_os_write_stderr(self): channel = self.gw.remote_exec(""" import os os.write(2, 'test') From guido at codespeak.net Fri Dec 29 16:57:59 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Fri, 29 Dec 2006 16:57:59 +0100 (CET) Subject: [py-svn] r36038 - in py/dist/py: misc/testing path/svn Message-ID: <20061229155759.D2DB11009F@code0.codespeak.net> Author: guido Date: Fri Dec 29 16:57:52 2006 New Revision: 36038 Modified: py/dist/py/misc/testing/test_svnlook.py py/dist/py/path/svn/wccommand.py Log: fixed tests on win32, some escaping problems in svn code Modified: py/dist/py/misc/testing/test_svnlook.py ============================================================================== --- py/dist/py/misc/testing/test_svnlook.py (original) +++ py/dist/py/misc/testing/test_svnlook.py Fri Dec 29 16:57:52 2006 @@ -13,7 +13,7 @@ tempdir = py.test.ensuretemp("svnlook") repo = tempdir.join("repo") py.process.cmdexec("svnadmin create --fs-type fsfs %s" % repo) - py.process.cmdexec("svnadmin load %s <%s" %(repo, + py.process.cmdexec("svnadmin load %s < \"%s\"" %(repo, data.join("svnlookrepo.dump"))) author = svnlook.author(repo, 1) Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Fri Dec 29 16:57:52 2006 @@ -69,10 +69,10 @@ l = ['svn %s' % cmd] args = [self._escape(item) for item in args] l.extend(args) - l.append("%s" % self._escape(self.strpath)) + l.append('"%s"' % self._escape(self.strpath)) # try fixing the locale because we can't otherwise parse string = svncommon.fixlocale() + " ".join(l) - if DEBUG: + if 1 or DEBUG: print "execing", string try: try: From guido at codespeak.net Sat Dec 30 14:07:43 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Sat, 30 Dec 2006 14:07:43 +0100 (CET) Subject: [py-svn] r36058 - py/dist/py/path/svn Message-ID: <20061230130743.7D09A10077@code0.codespeak.net> Author: guido Date: Sat Dec 30 14:07:39 2006 New Revision: 36058 Modified: py/dist/py/path/svn/wccommand.py Log: Oops, removing debug print. Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Sat Dec 30 14:07:39 2006 @@ -72,7 +72,7 @@ l.append('"%s"' % self._escape(self.strpath)) # try fixing the locale because we can't otherwise parse string = svncommon.fixlocale() + " ".join(l) - if 1 or DEBUG: + if DEBUG: print "execing", string try: try: