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(T