From hpk at codespeak.net Sun Sep 4 11:17:53 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 4 Sep 2005 11:17:53 +0200 (CEST) Subject: [py-svn] r17196 - in py/dist/py/path/local: . testing Message-ID: <20050904091753.06AE427B52@code1.codespeak.net> Author: hpk Date: Sun Sep 4 11:17:51 2005 New Revision: 17196 Added: py/dist/py/path/local/common.py Modified: py/dist/py/path/local/local.py py/dist/py/path/local/posix.py py/dist/py/path/local/testing/test_local.py py/dist/py/path/local/testing/test_posix.py py/dist/py/path/local/win.py Log: refactoring local path stat result access: path.stat() and path.lstat() now return a stat object that has attributes like 'uid', 'gid', 'owner', 'size', 'mtime' ... you can still use the underlying 'st_uid', 'st_gid' etc.pp. names but they are deprecated and might go soon. Added: py/dist/py/path/local/common.py ============================================================================== --- (empty file) +++ py/dist/py/path/local/common.py Sun Sep 4 11:17:51 2005 @@ -0,0 +1,22 @@ +import py + +class Stat(object): + def __init__(self, path, osstatresult): + self.path = path + self._osstatresult = osstatresult + + for name in ('atime blksize blocks ctime dev gid ' + 'ino mode mtime nlink rdev size uid'.split()): + exec """if 1: + def fget(self): + return getattr(self._osstatresult, "st_%(name)s", None) + %(name)s = property(fget) + def fget_deprecated(self): + py.std.warnings.warn("statresult.st_%(name)s is deprecated, use " + "statresult.%(name)s instead.", + DeprecationWarning, stacklevel=2) + return getattr(self._osstatresult, "st_%(name)s", None) + st_%(name)s = property(fget_deprecated)""" % locals() + del fget + del fget_deprecated + Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Sun Sep 4 11:17:51 2005 @@ -15,6 +15,8 @@ else: from py.__.path.local.posix import PosixMixin as PlatformMixin +from py.__.path.local.common import Stat + class LocalPath(common.FSPathBase, PlatformMixin): """ Local path implementation offering access/modification methods similar to os.path. @@ -32,17 +34,17 @@ return self._statcache def dir(self): - return stat.S_ISDIR(self._stat().st_mode) + return stat.S_ISDIR(self._stat().mode) def file(self): - return stat.S_ISREG(self._stat().st_mode) + return stat.S_ISREG(self._stat().mode) def exists(self): return self._stat() def link(self): st = self.path.lstat() - return stat.S_ISLNK(st.st_mode) + return stat.S_ISLNK(st.mode) def __new__(cls, path=None): """ Initialize and return a local Path instance. @@ -199,11 +201,11 @@ def size(self): """ return size of the underlying file object """ - return self.stat().st_size + return self.stat().size def mtime(self): """ return last modification time of the path. """ - return self.stat().st_mtime + return self.stat().mtime def remove(self, rec=1): """ remove a file or directory (or a directory tree if rec=1). """ @@ -288,11 +290,12 @@ def stat(self): """ Return an os.stat() tuple. """ - return self._callex(os.stat, self.strpath) + stat = self._callex(os.stat, self.strpath) + return self._makestat(stat) def lstat(self): """ Return an os.lstat() tuple. """ - return self._callex(os.lstat, self.strpath) + return self._makestat(self._callex(os.lstat, self.strpath)) # xlocal implementation def setmtime(self, mtime=None): @@ -320,7 +323,7 @@ def atime(self): """ return last access time of the path. """ - return self.stat().st_atime + return self.stat().atime def __repr__(self): return 'local(%r)' % self.strpath Modified: py/dist/py/path/local/posix.py ============================================================================== --- py/dist/py/path/local/posix.py (original) +++ py/dist/py/path/local/posix.py Sun Sep 4 11:17:51 2005 @@ -10,23 +10,44 @@ # Local Path Posix Mixin #__________________________________________________________ -class PosixMixin: - # an instance needs to be a local path instance +from common import Stat + +class PosixStat(Stat): def owner(self): - """ return owner name of file. """ - uid = self.stat().st_uid - entry = self._callex(py.std.pwd.getpwuid, uid) + entry = self.path._callex(py.std.pwd.getpwuid, self.uid) return entry[0] + owner = property(owner, None, None, "owner of path") def group(self): """ return group name of file. """ - gid = self.stat().st_gid - entry = self._callex(py.std.grp.getgrgid, gid) + entry = self.path._callex(py.std.grp.getgrgid, self.gid) return entry[0] + group = property(group) + +class PosixMixin(object): + def _makestat(self, statresult): + return PosixStat(self, statresult) + + def _deprecated(self, name): + py.std.warnings.warn("'path.%s()' is deprecated, use " + "'path.stat().%s' instead." % (name,name), + DeprecationWarning, stacklevel=3) + + # an instance needs to be a local path instance + def owner(self): + """ return owner name of file. """ + self._deprecated('owner') + return self.stat().owner + + def group(self): + """ return group name of file. """ + self._deprecated('group') + return self.stat().group def mode(self): """ return permission mode of the path object """ - return self.stat().st_mode + self._deprecated('mode') + return self.stat().mode def chmod(self, mode, rec=0): """ change permissions to the given mode. If mode is an Modified: py/dist/py/path/local/testing/test_local.py ============================================================================== --- py/dist/py/path/local/testing/test_local.py (original) +++ py/dist/py/path/local/testing/test_local.py Sun Sep 4 11:17:51 2005 @@ -177,9 +177,9 @@ #dir.remove() def test_sysexec(self): - x = py.path.local.sysfind('ls') - out = x.sysexec() - for x in py.path.local().listdir(lambda x: x.check(dir=0)): + x = py.path.local.sysfind('ls') + out = x.sysexec('-a') + for x in py.path.local().listdir(): assert out.find(x.basename) != -1 def test_sysexec_failing(self): Modified: py/dist/py/path/local/testing/test_posix.py ============================================================================== --- py/dist/py/path/local/testing/test_posix.py (original) +++ py/dist/py/path/local/testing/test_posix.py Sun Sep 4 11:17:51 2005 @@ -83,11 +83,19 @@ def test_owner(self): from pwd import getpwuid - assert getpwuid(self.root.stat().st_uid)[0] == self.root.owner() - - def test_group(self): from grp import getgrgid - assert getgrgid(self.root.stat().st_gid)[0] == self.root.group() + stat = self.root.stat() + assert stat.path == self.root + + uid = stat.st_uid + gid = stat.st_gid + owner = getpwuid(uid)[0] + group = getgrgid(gid)[0] + + assert uid == stat.uid + assert owner == stat.owner + assert gid == stat.gid + assert group == stat.group def XXXtest_atime(self): # XXX disabled. this test is just not platform independent enough Modified: py/dist/py/path/local/win.py ============================================================================== --- py/dist/py/path/local/win.py (original) +++ py/dist/py/path/local/win.py Sun Sep 4 11:17:51 2005 @@ -4,5 +4,8 @@ (implementor needed :-) """ +from py.__.path.local.common import Stat + class WinMixin: - pass + def _makestat(self, statresult): + return Stat(self, statresult) From hpk at codespeak.net Sun Sep 4 11:19:48 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 4 Sep 2005 11:19:48 +0200 (CEST) Subject: [py-svn] r17197 - py/dist/py/path/local Message-ID: <20050904091948.8CDD927B52@code1.codespeak.net> Author: hpk Date: Sun Sep 4 11:19:47 2005 New Revision: 17197 Modified: py/dist/py/path/local/local.py Log: the platforms mixins care for Stat classes Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Sun Sep 4 11:19:47 2005 @@ -15,8 +15,6 @@ else: from py.__.path.local.posix import PosixMixin as PlatformMixin -from py.__.path.local.common import Stat - class LocalPath(common.FSPathBase, PlatformMixin): """ Local path implementation offering access/modification methods similar to os.path. From hpk at codespeak.net Sun Sep 4 13:19:37 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 4 Sep 2005 13:19:37 +0200 (CEST) Subject: [py-svn] r17200 - in py/dist/py/log: . testing Message-ID: <20050904111937.C821D27B4E@code1.codespeak.net> Author: hpk Date: Sun Sep 4 13:19:36 2005 New Revision: 17200 Modified: py/dist/py/log/consumer.py py/dist/py/log/producer.py py/dist/py/log/testing/test_log.py Log: add a set_consumer() helper method on Producers Modified: py/dist/py/log/consumer.py ============================================================================== --- py/dist/py/log/consumer.py (original) +++ py/dist/py/log/consumer.py Sun Sep 4 13:19:36 2005 @@ -34,5 +34,5 @@ if not hasattr(consumer, 'write'): raise TypeError("%r should be None, callable or file-like" % (consumer,)) consumer = File(consumer) - py.log.Producer.keywords2consumer[keywords] = consumer + py.log.Producer(keywords).set_consumer(consumer) Modified: py/dist/py/log/producer.py ============================================================================== --- py/dist/py/log/producer.py (original) +++ py/dist/py/log/producer.py Sun Sep 4 13:19:36 2005 @@ -49,11 +49,11 @@ return producer def __call__(self, *args): - func = self._getconsumer(self.keywords) + func = self.get_consumer(self.keywords) if func is not None: func(self.Message(self.keywords, args)) - def _getconsumer(self, keywords): + def get_consumer(self, keywords): for i in range(len(self.keywords), 0, -1): try: return self.keywords2consumer[self.keywords[:i]] @@ -61,6 +61,9 @@ continue return self.keywords2consumer.get('default', default_consumer) + def set_consumer(self, consumer): + self.keywords2consumer[self.keywords] = consumer + default = Producer('default') def _getstate(): Modified: py/dist/py/log/testing/test_log.py ============================================================================== --- py/dist/py/log/testing/test_log.py (original) +++ py/dist/py/log/testing/test_log.py Sun Sep 4 13:19:36 2005 @@ -73,6 +73,14 @@ assert l assert l[0].content() == "hello" + def test_simple_consumer_match_2(self): + l = [] + p = py.log.Producer("x1 x2") + p.set_consumer(l.append) + p("42") + assert l + assert l[0].content() == "42" + def test_setconsumer_with_producer(self): l = [] p = py.log.Producer("hello") From hpk at codespeak.net Sun Sep 4 13:21:53 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 4 Sep 2005 13:21:53 +0200 (CEST) Subject: [py-svn] r17201 - in py/dist/py/log: . testing Message-ID: <20050904112153.DCBEE27B4D@code1.codespeak.net> Author: hpk Date: Sun Sep 4 13:21:53 2005 New Revision: 17201 Modified: py/dist/py/log/producer.py py/dist/py/log/testing/test_log.py Log: names with any '_' in them don't give new producers. Modified: py/dist/py/log/producer.py ============================================================================== --- py/dist/py/log/producer.py (original) +++ py/dist/py/log/producer.py Sun Sep 4 13:21:53 2005 @@ -42,7 +42,7 @@ return "" % ":".join(self.keywords) def __getattr__(self, name): - if name[0] == '_': + if '_' in name: raise AttributeError, name producer = self.__class__(self.keywords + (name,)) setattr(self, name, producer) Modified: py/dist/py/log/testing/test_log.py ============================================================================== --- py/dist/py/log/testing/test_log.py (original) +++ py/dist/py/log/testing/test_log.py Sun Sep 4 13:21:53 2005 @@ -81,6 +81,11 @@ assert l assert l[0].content() == "42" + def test_no_auto_producer(self): + p = py.log.Producer('x') + py.test.raises(AttributeError, "p._x") + py.test.raises(AttributeError, "p.x_y") + def test_setconsumer_with_producer(self): l = [] p = py.log.Producer("hello") From hpk at codespeak.net Sun Sep 4 13:23:17 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 4 Sep 2005 13:23:17 +0200 (CEST) Subject: [py-svn] r17202 - py/dist/py Message-ID: <20050904112317.D538D27B4E@code1.codespeak.net> Author: hpk Date: Sun Sep 4 13:23:17 2005 New Revision: 17202 Modified: py/dist/py/LICENSE Log: added two more names of contributors Modified: py/dist/py/LICENSE ============================================================================== --- py/dist/py/LICENSE (original) +++ py/dist/py/LICENSE Sun Sep 4 13:23:17 2005 @@ -15,4 +15,5 @@ Ian Bicking Grig Gheorghiu Bob Ippolito - + Christian Tismer + Samuele Pedroni From hpk at codespeak.net Sun Sep 4 19:18:24 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 4 Sep 2005 19:18:24 +0200 (CEST) Subject: [py-svn] r17207 - in py/dist/py: . log log/testing Message-ID: <20050904171824.0584827B48@code1.codespeak.net> Author: hpk Date: Sun Sep 4 19:18:23 2005 New Revision: 17207 Added: py/dist/py/log/logger.py py/dist/py/log/testing/test_logger.py Modified: py/dist/py/__init__.py Log: experimenting with a different flatter log interface Modified: py/dist/py/__init__.py ============================================================================== --- py/dist/py/__init__.py (original) +++ py/dist/py/__init__.py Sun Sep 4 19:18:23 2005 @@ -115,6 +115,7 @@ 'log.Path' : ('./log/consumer.py', 'Path'), 'log.STDOUT' : ('./log/consumer.py', 'STDOUT'), 'log.STDERR' : ('./log/consumer.py', 'STDERR'), + 'log.get' : ('./log/logger.py', 'get'), # compatibility modules (taken from 2.4.1) 'compat.doctest' : ('./compat/doctest.py', '*'), Added: py/dist/py/log/logger.py ============================================================================== --- (empty file) +++ py/dist/py/log/logger.py Sun Sep 4 19:18:23 2005 @@ -0,0 +1,65 @@ + +class Message(object): + def __init__(self, prefix, *args): + self.content = args + self.prefix = prefix + + def strcontent(self): + return " ".join(map(str, self.content)) + + def strprefix(self): + return '[%s] ' % (self.prefix,) + + def __str__(self): + return self.strprefix() + self.strcontent() + +class Processor(object): + def __init__(self, logger, name, consume): + self.logger = logger + self.name = name + self.consume = consume + parts = filter(None, [str(logger._ident), str(name)]) + self.prefix = ":".join(parts) + + def __call__(self, *args): + try: + consume = self.logger._override + except AttributeError: + consume = self.consume + if consume is not None: + msg = Message(self.prefix, *args) + consume(msg) + +class Logger(object): + _key2logger = {} + + def __init__(self, ident): + self._ident = ident + self._key2logger[ident] = self + + def set_sub(self, **kwargs): + for name, value in kwargs.items(): + self._setsub(name, value) + + def ensure_sub(self, **kwargs): + for name, value in kwargs.items(): + if not hasattr(self, name): + self._setsub(name, value) + + def set_override(self, consumer): + self._override = lambda msg: consumer(msg) + + def del_override(self): + del self._override + + def _setsub(self, name, dest): + assert "_" not in name + setattr(self, name, Processor(self, name, dest)) + +def get(ident="global", **kwargs): + try: + log = Logger._key2logger[ident] + except KeyError: + log = Logger(ident) + log.ensure_sub(**kwargs) + return log Added: py/dist/py/log/testing/test_logger.py ============================================================================== --- (empty file) +++ py/dist/py/log/testing/test_logger.py Sun Sep 4 19:18:23 2005 @@ -0,0 +1,99 @@ + +import py + +def test_logger_identity(): + assert py.log.get() is py.log.get() + otherkey = object() + for key in "name1", object(): + log = py.log.get(key) + assert py.log.get(key) is log + assert py.log.get(otherkey) is not log + +def test_log_preset(): + log = py.log.get(test_log_preset) + l2 = [] + log.set_sub(x1=None, x2=l2.append) + l3 = [] + log2 = py.log.get(test_log_preset, + x2=None, + x3=l3.append) + + log2.x2("hello") + log2.x3("world") + assert l2[0].strcontent() == "hello" + assert l3[0].strcontent() == "world" + +def test_log_override(): + l2 = [] + log = py.log.get(object(), x1=None, x2=l2.append) + l = [] + log.set_override(l.append) + log.x1("hello") + log.x2("world") + log.ensure_sub(x3=None) + log.x3(42) + assert len(l) == 3 + assert not l2 + r = [x.strcontent() for x in l] + assert r == ["hello", "world", "42"] + l[:] = [] + log.del_override() + log.x2("hello") + assert l2[0].strcontent() == "hello" + +def test_log_basic(): + l1 = [] + class SomeKey: + def __str__(self): + return "somekey" + + for key in "name1", SomeKey(): + log = py.log.get(key) + log.set_sub(x1=l1.append) + log.x1(42) + assert l1[-1].content == (42,) + assert l1[-1].strcontent() == "42" + assert l1[-1].strprefix() == "[%s:x1] " %(key,) + + #log.set_prefix("hello") + #assert l1[0].strprefix() == "hello" + #log("world") + #assert str(l1[-1]) == "hello world" + +class TestLogger: + def setup_method(self, method): + self._x1 = [] + self._x2 = [] + self.log = py.log.get() + self.log.set_sub(x1=self._x1.append, + x2=self._x2.append) + + #def teardown_method(self, method): + # self.log.close() + + def test_simple(self): + self.log.x1("hello") + self.log.x2("world") + assert self._x1[0].strcontent() == 'hello' + assert self._x1[0].strprefix() == '[global:x1] ' + assert self._x2[0].strcontent() == 'world' + assert self._x2[0].strprefix() == '[global:x2] ' + py.test.raises(AttributeError, "self.log.x3") + + def test_reconfig(self): + self.log.set_sub(x1=None) + self.log.x1("asdasd") + assert not self._x1 + + def test_reconfig_add(self): + l = [] + self.log.set_sub(x2=None, x3=l.append) + self.log.x2("asdhello") + assert not self._x2 + self.log.x3(123) + assert l[0].content == (123,) + + def test_logger_del(self): + del self.log.x2 + py.test.raises(AttributeError, "self.log.x2") + From hpk at codespeak.net Sun Sep 4 19:37:23 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 4 Sep 2005 19:37:23 +0200 (CEST) Subject: [py-svn] r17208 - in py/dist/py/log: . testing Message-ID: <20050904173723.3360027B48@code1.codespeak.net> Author: hpk Date: Sun Sep 4 19:37:22 2005 New Revision: 17208 Modified: py/dist/py/log/logger.py py/dist/py/log/testing/test_logger.py Log: using keywords instead of prefix-string mangling Modified: py/dist/py/log/logger.py ============================================================================== --- py/dist/py/log/logger.py (original) +++ py/dist/py/log/logger.py Sun Sep 4 19:37:22 2005 @@ -1,14 +1,16 @@ class Message(object): - def __init__(self, prefix, *args): + def __init__(self, processor, *args): self.content = args - self.prefix = prefix + self.processor = processor + self.keywords = (processor.logger._ident, + processor.name) def strcontent(self): return " ".join(map(str, self.content)) def strprefix(self): - return '[%s] ' % (self.prefix,) + return '[%s] ' % ":".join(map(str, self.keywords)) def __str__(self): return self.strprefix() + self.strcontent() @@ -18,8 +20,6 @@ self.logger = logger self.name = name self.consume = consume - parts = filter(None, [str(logger._ident), str(name)]) - self.prefix = ":".join(parts) def __call__(self, *args): try: @@ -27,7 +27,7 @@ except AttributeError: consume = self.consume if consume is not None: - msg = Message(self.prefix, *args) + msg = Message(self, *args) consume(msg) class Logger(object): @@ -36,6 +36,7 @@ def __init__(self, ident): self._ident = ident self._key2logger[ident] = self + self._keywords = () def set_sub(self, **kwargs): for name, value in kwargs.items(): Modified: py/dist/py/log/testing/test_logger.py ============================================================================== --- py/dist/py/log/testing/test_logger.py (original) +++ py/dist/py/log/testing/test_logger.py Sun Sep 4 19:37:22 2005 @@ -53,6 +53,7 @@ log.x1(42) assert l1[-1].content == (42,) assert l1[-1].strcontent() == "42" + assert l1[-1].keywords == (key, 'x1') assert l1[-1].strprefix() == "[%s:x1] " %(key,) #log.set_prefix("hello") From hpk at codespeak.net Tue Sep 6 22:01:03 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 6 Sep 2005 22:01:03 +0200 (CEST) Subject: [py-svn] r17300 - py/dist/py/c-extension/greenlet Message-ID: <20050906200103.8586427B5E@code1.codespeak.net> Author: hpk Date: Tue Sep 6 22:01:02 2005 New Revision: 17300 Modified: py/dist/py/c-extension/greenlet/switch_x86_unix.h Log: remove ebx from clobbered list as discussed on py-dev this makes things work again for me on an intel linux machine. Modified: py/dist/py/c-extension/greenlet/switch_x86_unix.h ============================================================================== --- py/dist/py/c-extension/greenlet/switch_x86_unix.h (original) +++ py/dist/py/c-extension/greenlet/switch_x86_unix.h Tue Sep 6 22:01:02 2005 @@ -31,7 +31,7 @@ slp_switch(void) { register int *stackref, stsizediff; - __asm__ volatile ("" : : : "ebx", "esi", "edi"); + __asm__ volatile ("" : : : "esi", "edi"); __asm__ ("movl %%esp, %0" : "=g" (stackref)); { SLP_SAVE_STATE(stackref, stsizediff); @@ -44,7 +44,7 @@ SLP_RESTORE_STATE(); return 0; } - __asm__ volatile ("" : : : "ebx", "esi", "edi"); + __asm__ volatile ("" : : : "esi", "edi"); } #endif From hpk at codespeak.net Tue Sep 6 22:17:23 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 6 Sep 2005 22:17:23 +0200 (CEST) Subject: [py-svn] r17302 - py/dist/py/compat Message-ID: <20050906201723.6B24B27B5E@code1.codespeak.net> Author: hpk Date: Tue Sep 6 22:17:22 2005 New Revision: 17302 Added: py/dist/py/compat/LICENSE Log: added a license file to the compat modules taken from python 2.4.1 Added: py/dist/py/compat/LICENSE ============================================================================== --- (empty file) +++ py/dist/py/compat/LICENSE Tue Sep 6 22:17:22 2005 @@ -0,0 +1,8 @@ +License for modules in py/compat directory +============================================================== + +The "*.py" files in py/compat/ and subdirectories are are all +- except when otherwise stated at the beginning of the file - +copyrighted by the Python Software Foundation and licensed +under the Python Software License of which you can find a copy +here: http://www.python.org/doc/Copyright.html From arigo at codespeak.net Wed Sep 7 14:42:23 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 7 Sep 2005 14:42:23 +0200 (CEST) Subject: [py-svn] r17324 - py/dist/py/c-extension/greenlet Message-ID: <20050907124223.D80AB27B5E@code1.codespeak.net> Author: arigo Date: Wed Sep 7 14:42:22 2005 New Revision: 17324 Modified: py/dist/py/c-extension/greenlet/switch_ppc_macosx.h py/dist/py/c-extension/greenlet/switch_ppc_unix.h py/dist/py/c-extension/greenlet/switch_x86_unix.h Log: Removed r31 in the ppc files as well, and added big fat warnings. (The problem here is that if you try to compile these statically, e.g. use them back in Stackless, then it's likely to almost work if you are lucky but possibly crash mysteriously sometimes... Hence the big fat warnings.) Still looking for a solution that would detect by itself if these extra registers must be mentioned or not... Modified: py/dist/py/c-extension/greenlet/switch_ppc_macosx.h ============================================================================== --- py/dist/py/c-extension/greenlet/switch_ppc_macosx.h (original) +++ py/dist/py/c-extension/greenlet/switch_ppc_macosx.h Wed Sep 7 14:42:22 2005 @@ -2,6 +2,10 @@ * this is the internal transfer function. * * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! * 14-Jan-04 Bob Ippolito * added cr2-cr4 to the registers to be saved. * Open questions: Should we save FP registers? @@ -32,8 +36,11 @@ #define STACK_MAGIC 3 +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ #define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ - "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r31", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ "cr2", "cr3", "cr4" static int Modified: py/dist/py/c-extension/greenlet/switch_ppc_unix.h ============================================================================== --- py/dist/py/c-extension/greenlet/switch_ppc_unix.h (original) +++ py/dist/py/c-extension/greenlet/switch_ppc_unix.h Wed Sep 7 14:42:22 2005 @@ -2,6 +2,10 @@ * this is the internal transfer function. * * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! * 14-Jan-04 Bob Ippolito * added cr2-cr4 to the registers to be saved. * Open questions: Should we save FP registers? @@ -34,8 +38,11 @@ #define STACK_MAGIC 3 +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ #define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ - "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r31", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ "cr2", "cr3", "cr4" static int slp_switch(void) Modified: py/dist/py/c-extension/greenlet/switch_x86_unix.h ============================================================================== --- py/dist/py/c-extension/greenlet/switch_x86_unix.h (original) +++ py/dist/py/c-extension/greenlet/switch_x86_unix.h Wed Sep 7 14:42:22 2005 @@ -2,6 +2,10 @@ * this is the internal transfer function. * * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'ebx' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! * 24-Nov-02 Christian Tismer * needed to add another magic constant to insure * that f in slp_eval_frame(PyFrameObject *f) @@ -31,6 +35,10 @@ slp_switch(void) { register int *stackref, stsizediff; + /* !!!!WARNING!!!! need to add "ebx" in the next line, as well as in the + * last line of this function, if this header file is meant to be compiled + * non-dynamically! + */ __asm__ volatile ("" : : : "esi", "edi"); __asm__ ("movl %%esp, %0" : "=g" (stackref)); { From arigo at codespeak.net Thu Sep 8 12:03:55 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 8 Sep 2005 12:03:55 +0200 (CEST) Subject: [py-svn] r17354 - py/dist/py/misc Message-ID: <20050908100355.9EE0527B5E@code1.codespeak.net> Author: arigo Date: Thu Sep 8 12:03:54 2005 New Revision: 17354 Modified: py/dist/py/misc/rest.py Log: Grumble, distutils depends on the current directory in some quite implicit places (e.g. there is an os.getcwd() in the logic that looks for the stylesheet). Bug found while running py.test in svn/pypy/dist/pypy: the test "doc/news.txt" fails, although it works if run from within the doc directory. Modified: py/dist/py/misc/rest.py ============================================================================== --- py/dist/py/misc/rest.py (original) +++ py/dist/py/misc/rest.py Thu Sep 8 12:03:54 2005 @@ -23,8 +23,15 @@ #'halt' : 0, # 'info', 'halt_level' : 2, } - return publish_string(source, str(source_path), writer_name='html', - settings_overrides=kwargs) + # docutils uses os.getcwd() :-( + source_path = os.path.abspath(str(source_path)) + prevdir = os.getcwd() + try: + os.chdir(os.path.dirname(source_path)) + return publish_string(source, source_path, writer_name='html', + settings_overrides=kwargs) + finally: + os.chdir(prevdir) def process(txtpath, encoding='latin1'): """ process a textfile """ From arigo at codespeak.net Thu Sep 8 19:28:41 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 8 Sep 2005 19:28:41 +0200 (CEST) Subject: [py-svn] r17387 - in py/dist/py: . bin compat/testing Message-ID: <20050908172841.0EE1527B6C@code1.codespeak.net> Author: arigo Date: Thu Sep 8 19:28:39 2005 New Revision: 17387 Modified: py/dist/py/bin/_findpy.py py/dist/py/bin/_makepyrelease.py py/dist/py/bin/py.lookup py/dist/py/bin/py.rest py/dist/py/compat/testing/_findpy.py py/dist/py/compat/testing/test_optparse.py py/dist/py/env.py Log: Consistently use #!/usr/bin/env python instead of #!/usr/bin/python Modified: py/dist/py/bin/_findpy.py ============================================================================== --- py/dist/py/bin/_findpy.py (original) +++ py/dist/py/bin/_findpy.py Thu Sep 8 19:28:39 2005 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # find and import a version of 'py' Modified: py/dist/py/bin/_makepyrelease.py ============================================================================== --- py/dist/py/bin/_makepyrelease.py (original) +++ py/dist/py/bin/_makepyrelease.py Thu Sep 8 19:28:39 2005 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from _findpy import py import sys Modified: py/dist/py/bin/py.lookup ============================================================================== --- py/dist/py/bin/py.lookup (original) +++ py/dist/py/bin/py.lookup Thu Sep 8 19:28:39 2005 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from _findpy import py import re Modified: py/dist/py/bin/py.rest ============================================================================== --- py/dist/py/bin/py.rest (original) +++ py/dist/py/bin/py.rest Thu Sep 8 19:28:39 2005 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ invoke Modified: py/dist/py/compat/testing/_findpy.py ============================================================================== --- py/dist/py/compat/testing/_findpy.py (original) +++ py/dist/py/compat/testing/_findpy.py Thu Sep 8 19:28:39 2005 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # find and import a version of 'py' Modified: py/dist/py/compat/testing/test_optparse.py ============================================================================== --- py/dist/py/compat/testing/test_optparse.py (original) +++ py/dist/py/compat/testing/test_optparse.py Thu Sep 8 19:28:39 2005 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # Test suite for Optik. Supplied by Johannes Gijsbers Modified: py/dist/py/env.py ============================================================================== --- py/dist/py/env.py (original) +++ py/dist/py/env.py Thu Sep 8 19:28:39 2005 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import sys, os From hpk at codespeak.net Mon Sep 12 17:38:49 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 12 Sep 2005 17:38:49 +0200 (CEST) Subject: [py-svn] r17504 - py/dist/py/misc Message-ID: <20050912153849.DFAD927BB9@code1.codespeak.net> Author: hpk Date: Mon Sep 12 17:38:48 2005 New Revision: 17504 Added: py/dist/py/misc/dynpkg.py Log: experimental code (not expoerted to the outside world) to support building setup.py-style packages on the fly from an __init__.py file representing the resulting package on a project. Added: py/dist/py/misc/dynpkg.py ============================================================================== --- (empty file) +++ py/dist/py/misc/dynpkg.py Mon Sep 12 17:38:48 2005 @@ -0,0 +1,79 @@ +""" + +""" + +import py +import sys + +log = py.log.get("dynpkg", + info=py.log.STDOUT, + debug=py.log.STDOUT, + command=None) # py.log.STDOUT) + +class DistPython: + def __init__(self, location=None, python=None): + if python is None: + python = py.std.sys.executable + self.python = python + if location is None: + location = py.path.local() + self.location = location + + def clean(self): + out = self._exec("clean -a") + #print out + + def build(self): + out = self._exec("build") + #print out + + def _exec(self, cmd): + python = self.python + old = self.location.chdir() + try: + cmd = "%(python)s setup.py %(cmd)s" % locals() + log.command(cmd) + out = py.process.cmdexec(cmd) + finally: + old.chdir() + return out + + def get_package_path(self, pkgname): + pkg = self._get_package_path(pkgname) + if pkg is None: + #self.clean() + self.build() + pkg = self._get_package_path(pkgname) + assert pkg is not None + return pkg + + def _get_package_path(self, pkgname): + major, minor = py.std.sys.version_info[:2] + #assert major >=2 and minor in (3,4,5) + suffix = "%s.%s" %(major, minor) + location = self.location + base = location.join('build') + if base.check(dir=1): + # XXX check if we need to rebuild + for pkg in base.visit(lambda x: x.check(dir=1)): + if pkg.basename == pkgname: + if pkg.dirpath().basename.endswith(suffix): + return pkg + +def setpkg(distdir, finalpkgname): + assert distdir.check(dir=1) + dist = DistPython(distdir) + pkg = dist.get_package_path(finalpkgname) + assert pkg.check(dir=1) + sys.path.insert(0, str(pkg.dirpath())) + try: + modname = pkg.purebasename + if modname in sys.modules: + log.debug("removing from sys.modules:", modname) + del sys.modules[modname] + sys.modules[modname] = mod = __import__(modname) + finally: + sys.path[0] # XXX + log.info("module is at", mod.__file__) + return mod + From hpk at codespeak.net Mon Sep 12 18:23:54 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 12 Sep 2005 18:23:54 +0200 (CEST) Subject: [py-svn] r17509 - py/dist/py/misc Message-ID: <20050912162354.A71C927B6D@code1.codespeak.net> Author: hpk Date: Mon Sep 12 18:23:53 2005 New Revision: 17509 Modified: py/dist/py/misc/dynpkg.py Log: resort to "lib" dirs if there are no version-specific lib-...-2.4/3 dirs from setup.py build. Modified: py/dist/py/misc/dynpkg.py ============================================================================== --- py/dist/py/misc/dynpkg.py (original) +++ py/dist/py/misc/dynpkg.py Mon Sep 12 18:23:53 2005 @@ -57,10 +57,11 @@ # XXX check if we need to rebuild for pkg in base.visit(lambda x: x.check(dir=1)): if pkg.basename == pkgname: - if pkg.dirpath().basename.endswith(suffix): + if pkg.dirpath().basename.endswith(suffix) or \ + pkg.dirpath().basename == 'lib': return pkg -def setpkg(distdir, finalpkgname): +def setpkg(finalpkgname, distdir): assert distdir.check(dir=1) dist = DistPython(distdir) pkg = dist.get_package_path(finalpkgname) From hpk at codespeak.net Mon Sep 12 20:08:05 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 12 Sep 2005 20:08:05 +0200 (CEST) Subject: [py-svn] r17511 - py/dist/py/test Message-ID: <20050912180805.931CA27BA6@code1.codespeak.net> Author: hpk Date: Mon Sep 12 20:08:04 2005 New Revision: 17511 Modified: py/dist/py/test/config.py Log: keep a bit the order of configpaths Modified: py/dist/py/test/config.py ============================================================================== --- py/dist/py/test/config.py (original) +++ py/dist/py/test/config.py Mon Sep 12 20:08:04 2005 @@ -176,15 +176,16 @@ def guessconfigpaths(*paths): """ return test configuration paths from skimming the args. """ d = {} + l = [] for anchor in paths: if anchor: for p in anchor.parts(): x = p.join(configbasename) - if x.check(file=1): + if x not in d and x.check(file=1): d[x] = True - configpaths = d.keys() - configpaths.sort(lambda x,y: cmp(len(str(x)), len(str(y)))) - return configpaths + l.append(x) + l.reverse() + return l def getanchorpaths(args): """ yield "anchors" from skimming the args for existing files/dirs. """ From hpk at codespeak.net Mon Sep 19 11:59:28 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 19 Sep 2005 11:59:28 +0200 (CEST) Subject: [py-svn] r17653 - py/dist/py/tool Message-ID: <20050919095928.5780627B69@code1.codespeak.net> Author: hpk Date: Mon Sep 19 11:59:27 2005 New Revision: 17653 Modified: py/dist/py/tool/utestconvert.py Log: allow trial's unittest special assertNotIn and assertIn to be converted to assert style as well. Modified: py/dist/py/tool/utestconvert.py ============================================================================== --- py/dist/py/tool/utestconvert.py (original) +++ py/dist/py/tool/utestconvert.py Mon Sep 19 11:59:27 2005 @@ -17,6 +17,8 @@ d['failIf'] = ('assert not', '', [1,2]) d['assertEqual'] = ('assert', ' ==', [2,3]) d['failIfEqual'] = ('assert not', ' ==', [2,3]) +d['assertIn'] = ('assert', ' in', [2,3]) +d['assertNotIn'] = ('assert', ' not in', [2,3]) d['assertNotEqual'] = ('assert', ' !=', [2,3]) d['failUnlessEqual'] = ('assert', ' ==', [2,3]) d['assertAlmostEqual'] = ('assert round', ' ==', [2,3,4]) From hpk at codespeak.net Mon Sep 19 12:01:04 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 19 Sep 2005 12:01:04 +0200 (CEST) Subject: [py-svn] r17654 - in py/branch/monday: . py/tool Message-ID: <20050919100104.BB03827B69@code1.codespeak.net> Author: hpk Date: Mon Sep 19 12:01:03 2005 New Revision: 17654 Added: py/branch/monday/ - copied from r17652, py/dist/ py/branch/monday/py/tool/utestconvert.py - copied unchanged from r17653, py/dist/py/tool/utestconvert.py Log: a branch for Jan, Armin and Holger to work on monday(s) From jan at codespeak.net Mon Sep 19 15:33:31 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Mon, 19 Sep 2005 15:33:31 +0200 (CEST) Subject: [py-svn] r17655 - py/branch/monday/py/test/tkinter Message-ID: <20050919133331.1052227B68@code1.codespeak.net> Author: jan Date: Mon Sep 19 15:33:30 2005 New Revision: 17655 Modified: py/branch/monday/py/test/tkinter/backend.py Log: use new channel api Modified: py/branch/monday/py/test/tkinter/backend.py ============================================================================== --- py/branch/monday/py/test/tkinter/backend.py (original) +++ py/branch/monday/py/test/tkinter/backend.py Mon Sep 19 15:33:30 2005 @@ -191,8 +191,8 @@ self.testrepository = TestRepository() self.reportstore = ReportStore() self.gateway = py.execnet.PopenGateway(config.option.executable) - self.channel = self.gateway.newchannel(receiver = self.queue.put) - self.gateway.remote_exec(channel = self.channel, source = ''' + #self.channel = self.gateway.newchannel(receiver = self.queue.put) + self.channel = self.gateway.remote_exec(source = ''' import py from py.__.test.tkinter.backend import remote @@ -201,6 +201,7 @@ # why? channel.close() ''') + self.channel.setcallback(self.queue.put) self.channel.send((args, tests)) self.waitfinish_thread = threading.Thread(target = waitfinish, args = (self.channel,)) self.waitfinish_thread.start() From hpk at codespeak.net Mon Sep 19 15:50:58 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 19 Sep 2005 15:50:58 +0200 (CEST) Subject: [py-svn] r17658 - in py/branch/monday/py/execnet: . testing Message-ID: <20050919135058.F07FE27B6C@code1.codespeak.net> Author: hpk Date: Mon Sep 19 15:50:57 2005 New Revision: 17658 Modified: py/branch/monday/py/execnet/channel.py py/branch/monday/py/execnet/gateway.py py/branch/monday/py/execnet/testing/test_gateway.py Log: (arigo,hpk,jan) - removed channel argument from gateway.remote_exec - removed receiver arg from newchannel() - introduced new channel.setcallback(callback) that sends all received items to the callback Modified: py/branch/monday/py/execnet/channel.py ============================================================================== --- py/branch/monday/py/execnet/channel.py (original) +++ py/branch/monday/py/execnet/channel.py Mon Sep 19 15:50:57 2005 @@ -24,18 +24,44 @@ """Communication channel between two possibly remote threads of code. """ RemoteError = RemoteError - def __init__(self, gateway, id, has_callback=False): + def __init__(self, gateway, id): assert isinstance(id, int) self.gateway = gateway self.id = id - if has_callback: - self._items = None - else: - self._items = Queue.Queue() + self._items = Queue.Queue() self._closed = False self._receiveclosed = threading.Event() self._remoteerrors = [] + def setcallback(self, callback): + queue = self._items + lock = self.gateway.channelfactory._receivelock + lock.acquire() + try: + _callbacks = self.gateway.channelfactory._callbacks + if _callbacks.setdefault(self.id, callback) is not callback: + raise IOError("%r has callback already registered" %(self,)) + self._items = None + while 1: + try: + olditem = queue.get(block=False) + except Queue.Empty: + break + else: + if olditem is ENDMARKER: + queue.put(olditem) + break + else: + callback(olditem) + if self._closed or self._receiveclosed.isSet(): + # no need to keep a callback + try: + del _callbacks[self.id] + except KeyError: + pass + finally: + lock.release() + def __repr__(self): flag = self.isclosed() and "closed" or "open" return "" % (self.id, flag) @@ -100,8 +126,9 @@ self._remoteerrors.append(error) self._closed = True # --> "closed" self._receiveclosed.set() - if self._items is not None: - self._items.put(ENDMARKER) + queue = self._items + if queue is not None: + queue.put(ENDMARKER) self.gateway.channelfactory._no_longer_opened(self.id) def waitclose(self, timeout=None): @@ -139,11 +166,12 @@ reraised as channel.RemoteError exceptions containing a textual representation of the remote traceback. """ - if self._items is None: + queue = self._items + if queue is None: raise IOError("calling receive() on channel with receiver callback") - x = self._items.get() + x = queue.get() if x is ENDMARKER: - self._items.put(x) # for other receivers + queue.put(x) # for other receivers raise self._getremoteerror() or EOFError() else: return x @@ -170,20 +198,18 @@ self._channels = weakref.WeakValueDictionary() self._callbacks = {} self._writelock = threading.Lock() + self._receivelock = threading.RLock() self.gateway = gateway self.count = startcount - def new(self, id=None, receiver=None): + def new(self, id=None): """ create a new Channel with 'id' (or create new id if None). """ self._writelock.acquire() try: if id is None: id = self.count self.count += 2 - has_callback = receiver is not None - if has_callback: - self._callbacks[id] = receiver - channel = Channel(self.gateway, id, has_callback) + channel = Channel(self.gateway, id) self._channels[id] = channel return channel finally: @@ -217,8 +243,9 @@ channel._remoteerrors.append(remoteerror) channel._closed = True # --> "closed" channel._receiveclosed.set() - if channel._items is not None: - channel._items.put(ENDMARKER) + queue = channel._items + if queue is not None: + queue.put(ENDMARKER) self._no_longer_opened(id) def _local_last_message(self, id): @@ -229,21 +256,27 @@ else: # state transition: if "opened", change to "sendonly" channel._receiveclosed.set() - if channel._items is not None: - channel._items.put(ENDMARKER) + queue = channel._items + if queue is not None: + queue.put(ENDMARKER) self._no_longer_opened(id) def _local_receive(self, id, data): # executes in receiver thread - callback = self._callbacks.get(id) - if callback is not None: - callback(data) # even if channel may be already closed - else: - channel = self._channels.get(id) - if channel is None or channel._items is None: - pass # drop data + self._receivelock.acquire() + try: + callback = self._callbacks.get(id) + if callback is not None: + callback(data) # even if channel may be already closed else: - channel._items.put(data) + channel = self._channels.get(id) + queue = channel and channel._items + if queue is None: + pass # drop data + else: + queue.put(data) + finally: + self._receivelock.release() def _finished_receiving(self): for id in self._channels.keys(): Modified: py/branch/monday/py/execnet/gateway.py ============================================================================== --- py/branch/monday/py/execnet/gateway.py (original) +++ py/branch/monday/py/execnet/gateway.py Mon Sep 19 15:50:57 2005 @@ -137,7 +137,7 @@ channel.close() return close - def thread_executor(self, channel, (source, outid, errid, autoclose)): + def thread_executor(self, channel, (source, outid, errid)): """ worker thread to execute source objects from the execution queue. """ from sys import exc_info try: @@ -159,15 +159,7 @@ channel.close(errortext) self.trace(errortext) else: - if autoclose: - channel.close() - else: - # the channel should usually be closed by Channel.__del__. - # Give it a better chance now. - try: - del loc['channel'] - except KeyError: - pass + channel.close() def _local_schedulexec(self, channel, sourcetask): self.trace("dispatching exec") @@ -179,7 +171,8 @@ if hasattr(callback, 'write'): callback = callback.write assert callable(callback) - chan = self.newchannel(receiver=callback) + chan = self.newchannel() + chan.setcallback(callback) return chan.id # _____________________________________________________________________ @@ -187,18 +180,14 @@ # High Level Interface # _____________________________________________________________________ # - def newchannel(self, receiver=None): - """ return new channel object. If a 'receiver' callback is provided - it will be invoked on each received item. You cannot call - receive() anymore on such a channel. - """ - return self.channelfactory.new(receiver=receiver) + def newchannel(self): + """ return new channel object. """ + return self.channelfactory.new() - def remote_exec(self, source, stdout=None, stderr=None, channel=None): + def remote_exec(self, source, stdout=None, stderr=None): """ return channel object for communicating with the asynchronously executing 'source' code which will have a corresponding 'channel' - object in its executing namespace. If a channel object is not - provided a new channel will be created. + object in its executing namespace. """ try: source = str(Source(source)) @@ -208,26 +197,23 @@ source = str(py.code.Source(source)) except ImportError: pass - if channel is None: - channel = self.newchannel() - autoclose = True - else: - autoclose = False + channel = self.newchannel() outid = self._newredirectchannelid(stdout) errid = self._newredirectchannelid(stderr) self._outgoing.put(Message.CHANNEL_OPEN(channel.id, - (source, outid, errid, autoclose))) + (source, outid, errid))) return channel def remote_redirect(self, stdout=None, stderr=None): - """ return a handle representing a redirection of of remote + """ return a handle representing a redirection of a remote end's stdout to a local file object. with handle.close() the redirection will be reverted. """ clist = [] for name, out in ('stdout', stdout), ('stderr', stderr): if out: - outchannel = self.newchannel(receiver=getattr(out, 'write', out)) + outchannel = self.newchannel() + outchannel.setcallback(getattr(out, 'write', out)) channel = self.remote_exec(""" import sys outchannel = channel.receive() Modified: py/branch/monday/py/execnet/testing/test_gateway.py ============================================================================== --- py/branch/monday/py/execnet/testing/test_gateway.py (original) +++ py/branch/monday/py/execnet/testing/test_gateway.py Mon Sep 19 15:50:57 2005 @@ -162,41 +162,76 @@ def test_channel_receiver_callback(self): l = [] - channel = self.gw.newchannel(receiver=l.append) - self.gw.remote_exec(channel=channel, source=''' + #channel = self.gw.newchannel(receiver=l.append) + channel = self.gw.remote_exec(source=''' channel.send(42) channel.send(13) channel.send(channel.gateway.newchannel()) ''') + channel.setcallback(callback=l.append) + py.test.raises(IOError, channel.receive) channel.waitclose(1.0) assert len(l) == 3 assert l[:2] == [42,13] assert isinstance(l[2], channel.__class__) + def test_channel_callback_after_receive(self): + l = [] + channel = self.gw.remote_exec(source=''' + channel.send(42) + channel.send(13) + channel.send(channel.gateway.newchannel()) + ''') + x = channel.receive() + assert x == 42 + channel.setcallback(callback=l.append) + py.test.raises(IOError, channel.receive) + channel.waitclose(1.0) + assert len(l) == 2 + assert l[0] == 13 + assert isinstance(l[1], channel.__class__) + + def test_waiting_for_callbacks(self): + l = [] + def callback(msg): + import time; time.sleep(0.2) + l.append(msg) + channel = self.gw.remote_exec(source=''' + channel.send(42) + ''') + channel.setcallback(callback) + channel.waitclose(1.0) + assert l == [42] + def test_channel_callback_stays_active(self, earlyfree=True): # with 'earlyfree==True', this tests the "sendonly" channel state. l = [] - channel = self.gw.newchannel(receiver=l.append) - self.gw.remote_exec(channel=channel, source=''' + channel = self.gw.remote_exec(source=''' import thread, time - def producer(channel): + def producer(subchannel): for i in range(5): time.sleep(0.15) - channel.send(i*100) - thread.start_new_thread(producer, (channel,)) + subchannel.send(i*100) + channel2 = channel.receive() + thread.start_new_thread(producer, (channel2,)) + del channel2 ''') + subchannel = self.gw.newchannel() + subchannel.setcallback(l.append) + channel.send(subchannel) if earlyfree: - channel = None + subchannel = None counter = 100 while len(l) < 5: - if channel and channel.isclosed(): + if subchannel and subchannel.isclosed(): break counter -= 1 + print counter if not counter: - py.test.fail("timed out waiting for the answer[%d]" % i) + py.test.fail("timed out waiting for the answer[%d]" % len(l)) time.sleep(0.04) # busy-wait assert l == [0, 100, 200, 300, 400] - return channel + return subchannel def test_channel_callback_remote_freed(self): channel = self.test_channel_callback_stays_active(False) From hpk at codespeak.net Mon Sep 19 18:59:36 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 19 Sep 2005 18:59:36 +0200 (CEST) Subject: [py-svn] r17666 - py/branch/monday/py/test/terminal Message-ID: <20050919165936.6CAD827B5E@code1.codespeak.net> Author: hpk Date: Mon Sep 19 18:59:35 2005 New Revision: 17666 Modified: py/branch/monday/py/test/terminal/remote.py Log: don't use deprecated stat api Modified: py/branch/monday/py/test/terminal/remote.py ============================================================================== --- py/branch/monday/py/test/terminal/remote.py (original) +++ py/branch/monday/py/test/terminal/remote.py Mon Sep 19 18:59:35 2005 @@ -21,8 +21,8 @@ print "# WARN: race condition on", path else: if oldstat: - if oldstat.st_mtime != curstat.st_mtime or \ - oldstat.st_size != curstat.st_size: + if oldstat.mtime != curstat.mtime or \ + oldstat.size != curstat.size: changed = True print "# MODIFIED", path else: From hpk at codespeak.net Mon Sep 19 19:17:30 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 19 Sep 2005 19:17:30 +0200 (CEST) Subject: [py-svn] r17667 - in py/branch/monday/py: code code/testing test/terminal Message-ID: <20050919171730.F0CAC27B5E@code1.codespeak.net> Author: hpk Date: Mon Sep 19 19:17:29 2005 New Revision: 17667 Modified: py/branch/monday/py/code/testing/test_excinfo.py py/branch/monday/py/code/traceback2.py py/branch/monday/py/test/terminal/terminal.py Log: (arigo,jan,hpk) refactor cut_traceback logic and move most of it in a cleaner way to py.code.Traceback Modified: py/branch/monday/py/code/testing/test_excinfo.py ============================================================================== --- py/branch/monday/py/code/testing/test_excinfo.py (original) +++ py/branch/monday/py/code/testing/test_excinfo.py Mon Sep 19 19:17:29 2005 @@ -30,11 +30,18 @@ # testchain for getentries test below def f(): + # raise ValueError + # def g(): + # + __tracebackhide__ = True f() + # def h(): + # g() + # class TestTraceback_f_g_h: def setup_method(self, method): @@ -80,6 +87,20 @@ assert s.startswith("def xyz():\n try:") assert s.endswith("except somenoname:") + def test_traceback_cut(self): + co = py.code.Code(f) + path, firstlineno = co.path, co.firstlineno + traceback = self.excinfo.traceback + newtraceback = traceback.cut(path=path, firstlineno=firstlineno) + assert len(newtraceback) == 1 + newtraceback = traceback.cut(path=path, lineno=firstlineno+2) + assert len(newtraceback) == 1 + + def test_traceback_filter(self): + traceback = self.excinfo.traceback + ntraceback = traceback.filter() + assert len(ntraceback) == len(traceback) - 1 + #def test_traceback_display_func(self): # tb = self.excinfo.traceback # for x in tb: Modified: py/branch/monday/py/code/traceback2.py ============================================================================== --- py/branch/monday/py/code/traceback2.py (original) +++ py/branch/monday/py/code/traceback2.py Mon Sep 19 19:17:29 2005 @@ -52,6 +52,14 @@ break return source[start:end] + def ishidden(self): + try: + return self.frame.eval("__tracebackhide__") + except (SystemExit, KeyboardInterrupt): + raise + except: + return False + def __str__(self): try: fn = str(self.path) @@ -65,11 +73,31 @@ Entry = TracebackEntry def __init__(self, tb): - def f(cur): - while cur is not None: - yield self.Entry(cur) - cur = cur.tb_next - list.__init__(self, f(tb)) + if hasattr(tb, 'tb_next'): + def f(cur): + while cur is not None: + yield self.Entry(cur) + cur = cur.tb_next + list.__init__(self, f(tb)) + else: + list.__init__(self, tb) + + def cut(self, path=None, lineno=None, firstlineno=None): + for x in self: + if ((path is None or x.frame.code.path == path) and + (lineno is None or x.lineno == lineno) and + (firstlineno is None or x.frame.code.firstlineno == firstlineno)): + return Traceback(x._rawentry) + return self + + def __getitem__(self, key): + val = super(Traceback, self).__getitem__(key) + if isinstance(key, slice): + val = self.__class__(val) + return val + + def filter(self, fn=lambda x: not x.ishidden()): + return Traceback(filter(fn, self)) # def __str__(self): # for x in self Modified: py/branch/monday/py/test/terminal/terminal.py ============================================================================== --- py/branch/monday/py/test/terminal/terminal.py (original) +++ py/branch/monday/py/test/terminal/terminal.py Mon Sep 19 19:17:29 2005 @@ -255,8 +255,12 @@ #print "repr_failures sees item", item #print "repr_failures sees traceback" #py.std.pprint.pprint(traceback) - if item: - self.cut_traceback(traceback, item) + if item and not self.config.option.fulltrace: + path, firstlineno = item.getpathlineno() + ntraceback = traceback.cut(path=path, firstlineno=firstlineno) + if ntraceback == traceback: + ntraceback = ntraceback.cut(path=path) + traceback = ntraceback if not traceback: self.out.line("empty traceback from item %r" % (item,)) return @@ -348,14 +352,14 @@ return 4 + (len(s) - len(s.lstrip())) return 0 - def cut_traceback(self, traceback, item=None): + def cut_traceback(self, traceback, item): if self.config.option.fulltrace or item is None: return + newtraceback = traceback[:] path, lineno = item.getpathlineno() for i, entry in py.builtin.enumerate(newtraceback): if entry.frame.code.path == path: - last = i while i < len(newtraceback)-1: entry = newtraceback[i] next = newtraceback[i+1] From hpk at codespeak.net Mon Sep 19 19:59:08 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 19 Sep 2005 19:59:08 +0200 (CEST) Subject: [py-svn] r17668 - py/branch/monday/py/test/terminal Message-ID: <20050919175908.ED30927B6C@code1.codespeak.net> Author: hpk Date: Mon Sep 19 19:59:08 2005 New Revision: 17668 Modified: py/branch/monday/py/test/terminal/terminal.py Log: finally remove the cut_traceback function and use traceback.filter() to filter out the "hidden" frames. Modified: py/branch/monday/py/test/terminal/terminal.py ============================================================================== --- py/branch/monday/py/test/terminal/terminal.py (original) +++ py/branch/monday/py/test/terminal/terminal.py Mon Sep 19 19:59:08 2005 @@ -260,7 +260,7 @@ ntraceback = traceback.cut(path=path, firstlineno=firstlineno) if ntraceback == traceback: ntraceback = ntraceback.cut(path=path) - traceback = ntraceback + traceback = ntraceback.filter() if not traceback: self.out.line("empty traceback from item %r" % (item,)) return @@ -352,39 +352,7 @@ return 4 + (len(s) - len(s.lstrip())) return 0 - def cut_traceback(self, traceback, item): - if self.config.option.fulltrace or item is None: - return - - newtraceback = traceback[:] - path, lineno = item.getpathlineno() - for i, entry in py.builtin.enumerate(newtraceback): - if entry.frame.code.path == path: - while i < len(newtraceback)-1: - entry = newtraceback[i] - next = newtraceback[i+1] - if next.frame.code.path != path: - break - if entry.frame.code.firstlineno == lineno: - break - del newtraceback[:i] - break - if not newtraceback: - newtraceback = traceback[:] - - # get rid of all frames marked with __tracebackhide__ - l = [] - for entry in newtraceback: - try: - x = entry.frame.eval("__tracebackhide__") - except: - x = None - if not x: - l.append(entry) - traceback[:] = l - def repr_failure_explanation(self, excinfo, indent): - indent = " " * indent # get the real exception information out lines = excinfo.exconly(tryshort=True).split('\n') From hpk at codespeak.net Mon Sep 19 20:20:58 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 19 Sep 2005 20:20:58 +0200 (CEST) Subject: [py-svn] r17669 - in py/branch/monday/py: code code/testing test/terminal Message-ID: <20050919182058.15B2D27B6D@code1.codespeak.net> Author: hpk Date: Mon Sep 19 20:20:57 2005 New Revision: 17669 Modified: py/branch/monday/py/code/testing/test_excinfo.py py/branch/monday/py/code/traceback2.py py/branch/monday/py/test/terminal/terminal.py Log: (hpk, arigo) Moved the recursion detection to the Traceback class. Modified: py/branch/monday/py/code/testing/test_excinfo.py ============================================================================== --- py/branch/monday/py/code/testing/test_excinfo.py (original) +++ py/branch/monday/py/code/testing/test_excinfo.py Mon Sep 19 20:20:57 2005 @@ -100,6 +100,16 @@ traceback = self.excinfo.traceback ntraceback = traceback.filter() assert len(ntraceback) == len(traceback) - 1 + + def test_traceback_recursion_index(self): + def f(n): + if n < 10: + n += 1 + f(n) + excinfo = py.test.raises(RuntimeError, f, 8) + traceback = excinfo.traceback + recindex = traceback.recursionindex() + assert recindex == 3 #def test_traceback_display_func(self): # tb = self.excinfo.traceback Modified: py/branch/monday/py/code/traceback2.py ============================================================================== --- py/branch/monday/py/code/traceback2.py (original) +++ py/branch/monday/py/code/traceback2.py Mon Sep 19 20:20:57 2005 @@ -99,6 +99,23 @@ def filter(self, fn=lambda x: not x.ishidden()): return Traceback(filter(fn, self)) + def recursionindex(self): + cache = {} + for i, entry in py.builtin.enumerate(self): + key = entry.frame.code.path, entry.frame.lineno + #print "checking for recursion at", key + l = cache.setdefault(key, []) + if l: + f = entry.frame + loc = f.f_locals + for otherloc in l: + if f.is_true(f.eval(co_equal, + __recursioncache_locals_1=loc, + __recursioncache_locals_2=otherloc)): + return i + l.append(entry.frame.f_locals) + return None + # def __str__(self): # for x in self # l = [] @@ -106,3 +123,6 @@ # l.append(entry.display()) # return "".join(l) + +co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2', + '?', 'eval') Modified: py/branch/monday/py/test/terminal/terminal.py ============================================================================== --- py/branch/monday/py/test/terminal/terminal.py (original) +++ py/branch/monday/py/test/terminal/terminal.py Mon Sep 19 20:20:57 2005 @@ -266,8 +266,11 @@ return last = traceback[-1] first = traceback[0] - recursioncache = {} - for entry in traceback: + if not self.config.option.nomagic and excinfo.errisinstance(RuntimeError): + recursionindex = traceback.recursionindex() + else: + recursionindex = None + for index, entry in py.builtin.enumerate(traceback): if entry == first: if item: self.repr_failure_info(item, entry) @@ -291,27 +294,11 @@ self.out.sep("_") else: self.out.sep("_ ") - if not self.config.option.nomagic and excinfo.errisinstance(RuntimeError) \ - and self.isrecursive(entry, recursioncache): + if index == recursionindex: self.out.line("Recursion detected (same locals & position)") self.out.sep("!") break - def isrecursive(self, entry, recursioncache): - # recursion detection - key = entry.frame.code.path, entry.frame.lineno - #print "checking for recursion at", key - l = recursioncache.setdefault(key, []) - if l: - f = entry.frame - loc = f.f_locals - for otherloc in l: - if f.is_true(f.eval(co_equal, - __recursioncache_locals_1=loc, - __recursioncache_locals_2=otherloc)): - return True - l.append(entry.frame.f_locals) - def repr_failure_info(self, item, entry): root = item.fspath modpath = item.getmodpath() @@ -407,9 +394,6 @@ self.out.line("%-10s =\\" % (name,)) py.std.pprint.pprint(value, stream=self.out) -co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2', - '?', 'eval') - def repr_pythonversion(): v = py.std.sys.version_info try: From hpk at codespeak.net Mon Sep 19 21:06:44 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 19 Sep 2005 21:06:44 +0200 (CEST) Subject: [py-svn] r17671 - py/branch/monday/py/test/terminal Message-ID: <20050919190644.0BDC227B6C@code1.codespeak.net> Author: hpk Date: Mon Sep 19 21:06:43 2005 New Revision: 17671 Modified: py/branch/monday/py/test/terminal/terminal.py Log: (jan, arigo) Shuffled stuff around: preparation for methods that can more easily move to a Reporter class. Modified: py/branch/monday/py/test/terminal/terminal.py ============================================================================== --- py/branch/monday/py/test/terminal/terminal.py (original) +++ py/branch/monday/py/test/terminal/terminal.py Mon Sep 19 21:06:43 2005 @@ -277,11 +277,12 @@ self.out.line() else: self.out.line("") + source = self.getentrysource(entry) if entry == last: - indent = self.repr_source(entry, 'E') - self.repr_failure_explanation(excinfo, indent) + self.repr_source(source, 'E') + self.repr_failure_explanation(excinfo, source) else: - self.repr_source(entry, '>') + self.repr_source(source, '>') self.out.line("") self.out.line("[%s:%d]" %(entry.frame.code.path, entry.lineno+1)) self.repr_locals(entry) @@ -317,30 +318,27 @@ else: self.out.sep("_", "entrypoint: %s %s" %(root.basename, modpath)) - def repr_source(self, entry, marker=">"): + def getentrysource(self, entry): try: source = entry.getsource() except py.error.ENOENT: - self.out.line("[failure to get at sourcelines from %r]\n" % entry) - else: - source = source.deindent() - for line in source[:-1]: - self.out.line(" " + line) - lastline = source[-1] - self.out.line(marker + " " + lastline) - try: - s = str(source.getstatement(len(source)-1)) - except KeyboardInterrupt: - raise - except: - #self.out.line("[failed to get last statement]\n%s" %(source,)) - s = str(source[-1]) - #print "XXX %r" % s - return 4 + (len(s) - len(s.lstrip())) - return 0 + source = py.code.Source("[failure to get at sourcelines from %r]\n" % entry) + return source.deindent() - def repr_failure_explanation(self, excinfo, indent): - indent = " " * indent + def repr_source(self, source, marker=">"): + for line in source[:-1]: + self.out.line(" " + line) + lastline = source[-1] + self.out.line(marker + " " + lastline) + + def repr_failure_explanation(self, excinfo, source): + try: + s = str(source.getstatement(len(source)-1)) + except KeyboardInterrupt: + raise + except: + s = str(source[-1]) + indent = " " * (4 + (len(s) - len(s.lstrip()))) # get the real exception information out lines = excinfo.exconly(tryshort=True).split('\n') self.out.line('>' + indent[:-1] + lines.pop(0)) From hpk at codespeak.net Tue Sep 20 12:16:42 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 20 Sep 2005 12:16:42 +0200 (CEST) Subject: [py-svn] r17683 - in py/branch/monday/py/code: . testing Message-ID: <20050920101642.C62E027B83@code1.codespeak.net> Author: hpk Date: Tue Sep 20 12:16:41 2005 New Revision: 17683 Modified: py/branch/monday/py/code/testing/test_excinfo.py py/branch/monday/py/code/traceback2.py Log: add a traceback.getcrashentry() function and tests Modified: py/branch/monday/py/code/testing/test_excinfo.py ============================================================================== --- py/branch/monday/py/code/testing/test_excinfo.py (original) +++ py/branch/monday/py/code/testing/test_excinfo.py Tue Sep 20 12:16:41 2005 @@ -110,6 +110,42 @@ traceback = excinfo.traceback recindex = traceback.recursionindex() assert recindex == 3 + + def test_traceback_getcrashentry(self): + def i(): + __tracebackhide__ = True + raise ValueError + def h(): + i() + def g(): + __tracebackhide__ = True + h() + def f(): + g() + + excinfo = py.test.raises(ValueError, f) + tb = excinfo.traceback + entry = tb.getcrashentry() + co = py.code.Code(h) + assert entry.frame.code.path == co.path + assert entry.lineno == co.firstlineno + 1 + assert entry.frame.code.name == 'h' + + def test_traceback_getcrashentry_empty(self): + def g(): + __tracebackhide__ = True + raise ValueError + def f(): + __tracebackhide__ = True + g() + + excinfo = py.test.raises(ValueError, f) + tb = excinfo.traceback + entry = tb.getcrashentry() + co = py.code.Code(g) + assert entry.frame.code.path == co.path + assert entry.lineno == co.firstlineno + 2 + assert entry.frame.code.name == 'g' #def test_traceback_display_func(self): # tb = self.excinfo.traceback Modified: py/branch/monday/py/code/traceback2.py ============================================================================== --- py/branch/monday/py/code/traceback2.py (original) +++ py/branch/monday/py/code/traceback2.py Tue Sep 20 12:16:41 2005 @@ -99,6 +99,15 @@ def filter(self, fn=lambda x: not x.ishidden()): return Traceback(filter(fn, self)) + def getcrashentry(self): + """ return last non-hidden traceback entry that lead + to the exception of a traceback. + """ + tb = self.filter() + if not tb: + tb = self + return tb[-1] + def recursionindex(self): cache = {} for i, entry in py.builtin.enumerate(self): From hpk at codespeak.net Tue Sep 20 12:46:28 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 20 Sep 2005 12:46:28 +0200 (CEST) Subject: [py-svn] r17685 - py/branch/monday/py/execnet Message-ID: <20050920104628.8121127B46@code1.codespeak.net> Author: hpk Date: Tue Sep 20 12:46:24 2005 New Revision: 17685 Modified: py/branch/monday/py/execnet/gateway.py Log: modify the repr of gateways a bit Modified: py/branch/monday/py/execnet/gateway.py ============================================================================== --- py/branch/monday/py/execnet/gateway.py (original) +++ py/branch/monday/py/execnet/gateway.py Tue Sep 20 12:46:24 2005 @@ -15,7 +15,7 @@ # to the other side. Yes, it is fragile but we have a # few tests that try to catch when we mess up. -# XXX the following line should not be here +# XXX the following lines should not be here if 'ThreadOut' not in globals(): import py from py.code import Source @@ -50,11 +50,13 @@ sender = self.thread_sender) def __repr__(self): - R = len(self.pool.getstarted('receiver')) and "receiving" or "not receiving" - S = len(self.pool.getstarted('sender')) and "sending" or "not sending" + r = (len(self.pool.getstarted('receiver')) + and "receiving" or "not receiving") + s = (len(self.pool.getstarted('sender')) + and "sending" or "not sending") i = len(self.channelfactory.channels()) - return "<%s %s/%s (%d active channels)>" %(self.__class__.__name__, - R, S, i) + return "<%s %s/%s (%d active channels)>" %( + self.__class__.__name__, r, s, i) ## def _local_trystopexec(self): ## self._execpool.shutdown() @@ -71,6 +73,7 @@ raise except: traceback.print_exc() + def traceex(self, excinfo): try: l = traceback.format_exception(*excinfo) From hpk at codespeak.net Tue Sep 20 12:51:51 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 20 Sep 2005 12:51:51 +0200 (CEST) Subject: [py-svn] r17686 - py/branch/monday/py/execnet/testing Message-ID: <20050920105151.B312C27B48@code1.codespeak.net> Author: hpk Date: Tue Sep 20 12:51:49 2005 New Revision: 17686 Modified: py/branch/monday/py/execnet/testing/test_gateway.py Log: add a repr check for gateways Modified: py/branch/monday/py/execnet/testing/test_gateway.py ============================================================================== --- py/branch/monday/py/execnet/testing/test_gateway.py (original) +++ py/branch/monday/py/execnet/testing/test_gateway.py Tue Sep 20 12:51:49 2005 @@ -69,6 +69,9 @@ for x in 'sender', 'receiver': assert self.gw.pool.getstarted(x) + def test_repr_doesnt_crash(self): + assert isinstance(repr(self), str) + def test_correct_setup_no_py(self): channel = self.gw.remote_exec(""" import sys From hpk at codespeak.net Tue Sep 20 13:21:51 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 20 Sep 2005 13:21:51 +0200 (CEST) Subject: [py-svn] r17687 - in py/branch/monday/py/thread: . testing Message-ID: <20050920112151.48B6227B58@code1.codespeak.net> Author: hpk Date: Tue Sep 20 13:21:48 2005 New Revision: 17687 Modified: py/branch/monday/py/thread/pool.py py/branch/monday/py/thread/testing/test_pool.py Log: make some pool methods private and provide EOFError if result has already been delivered Modified: py/branch/monday/py/thread/pool.py ============================================================================== --- py/branch/monday/py/thread/pool.py (original) +++ py/branch/monday/py/thread/pool.py Tue Sep 20 13:21:48 2005 @@ -3,18 +3,20 @@ import time import sys +ERRORMARKER = object() + class Reply(object): _excinfo = None def __init__(self, task): self.task = task self._queue = Queue.Queue() - def set(self, result): + def _set(self, result): self._queue.put(result) - def setexcinfo(self, excinfo): + def _setexcinfo(self, excinfo): self._excinfo = excinfo - self._queue.put(None) + self._queue.put(ERRORMARKER) def _get_with_timeout(self, timeout): # taken from python2.3's Queue.get() @@ -32,13 +34,15 @@ time.sleep(delay) #reduce CPU usage by using a sleep def get(self, timeout=None): + if self._queue is None: + raise EOFError("reply has already been delivered") if timeout is not None: result = self._get_with_timeout(timeout) else: result = self._queue.get() - excinfo = self._excinfo - if excinfo: - self._excinfo = None + if result is ERRORMARKER: + self._queue = None + excinfo = self._excinfo raise excinfo[0], excinfo[1], excinfo[2] return result @@ -61,9 +65,9 @@ except (SystemExit, KeyboardInterrupt): return False except: - reply.setexcinfo(sys.exc_info()) + reply._setexcinfo(sys.exc_info()) else: - reply.set(result) + reply._set(result) # at this point, reply, task and all other local variables go away return True Modified: py/branch/monday/py/thread/testing/test_pool.py ============================================================================== --- py/branch/monday/py/thread/testing/test_pool.py (original) +++ py/branch/monday/py/thread/testing/test_pool.py Tue Sep 20 13:21:48 2005 @@ -46,6 +46,7 @@ raise ValueError("42") reply = pool.dispatch(f) excinfo = py.test.raises(ValueError, "reply.get(1.0)") + py.test.raises(EOFError, "reply.get(1.0)") def test_maxthreads(): pool = WorkerPool(maxthreads=1) From arigo at codespeak.net Tue Sep 20 18:08:28 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 20 Sep 2005 18:08:28 +0200 (CEST) Subject: [py-svn] r17700 - py/dist/py/c-extension/greenlet Message-ID: <20050920160828.9376427B58@code1.codespeak.net> Author: arigo Date: Tue Sep 20 18:08:23 2005 New Revision: 17700 Modified: py/dist/py/c-extension/greenlet/switch_amd64_unix.h py/dist/py/c-extension/greenlet/switch_ppc_macosx.h py/dist/py/c-extension/greenlet/switch_ppc_unix.h py/dist/py/c-extension/greenlet/switch_s390_unix.h py/dist/py/c-extension/greenlet/switch_x86_unix.h Log: The last __asm__ volatile statement was after the 'return'. Strange strange. Modified: py/dist/py/c-extension/greenlet/switch_amd64_unix.h ============================================================================== --- py/dist/py/c-extension/greenlet/switch_amd64_unix.h (original) +++ py/dist/py/c-extension/greenlet/switch_amd64_unix.h Tue Sep 20 18:08:23 2005 @@ -47,9 +47,9 @@ : "r" (stsizediff) ); SLP_RESTORE_STATE(); - return 0; } __asm__ volatile ("" : : : REGS_TO_SAVE); + return 0; } #endif Modified: py/dist/py/c-extension/greenlet/switch_ppc_macosx.h ============================================================================== --- py/dist/py/c-extension/greenlet/switch_ppc_macosx.h (original) +++ py/dist/py/c-extension/greenlet/switch_ppc_macosx.h Tue Sep 20 18:08:23 2005 @@ -46,14 +46,8 @@ static int slp_switch(void) { - static int x = 0; register int *stackref, stsizediff; - __asm__ volatile ( - "; asm block 1\n" - : /* no outputs */ - : "r" (x) - : REGS_TO_SAVE - ); + __asm__ volatile ("" : : : REGS_TO_SAVE); __asm__ ("; asm block 2\n\tmr %0, r1" : "=g" (stackref) : ); { SLP_SAVE_STATE(stackref, stsizediff); @@ -67,8 +61,9 @@ : "r11" ); SLP_RESTORE_STATE(); - return 0; } + __asm__ volatile ("" : : : REGS_TO_SAVE); + return 0; } #endif Modified: py/dist/py/c-extension/greenlet/switch_ppc_unix.h ============================================================================== --- py/dist/py/c-extension/greenlet/switch_ppc_unix.h (original) +++ py/dist/py/c-extension/greenlet/switch_ppc_unix.h Tue Sep 20 18:08:23 2005 @@ -61,9 +61,9 @@ : "11" ); SLP_RESTORE_STATE(); - return 0; } __asm__ volatile ("" : : : REGS_TO_SAVE); + return 0; } #endif Modified: py/dist/py/c-extension/greenlet/switch_s390_unix.h ============================================================================== --- py/dist/py/c-extension/greenlet/switch_s390_unix.h (original) +++ py/dist/py/c-extension/greenlet/switch_s390_unix.h Tue Sep 20 18:08:23 2005 @@ -35,9 +35,9 @@ : "g" (stsizediff) ); SLP_RESTORE_STATE(); - return 0; } __asm__ volatile ("" : : : REGS_TO_SAVE); + return 0; } #endif Modified: py/dist/py/c-extension/greenlet/switch_x86_unix.h ============================================================================== --- py/dist/py/c-extension/greenlet/switch_x86_unix.h (original) +++ py/dist/py/c-extension/greenlet/switch_x86_unix.h Tue Sep 20 18:08:23 2005 @@ -50,9 +50,9 @@ : "r" (stsizediff) ); SLP_RESTORE_STATE(); - return 0; } __asm__ volatile ("" : : : "esi", "edi"); + return 0; } #endif From jan at codespeak.net Tue Sep 20 18:17:33 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Tue, 20 Sep 2005 18:17:33 +0200 (CEST) Subject: [py-svn] r17701 - py/dist/py/c-extension/greenlet Message-ID: <20050920161733.A057627B58@code1.codespeak.net> Author: jan Date: Tue Sep 20 18:17:32 2005 New Revision: 17701 Modified: py/dist/py/c-extension/greenlet/greenlet.c Log: Working around compiler optimizations, by forcing calls that it cannot inline. Necessary for MacOSX, gcc 3.3. Modified: py/dist/py/c-extension/greenlet/greenlet.c ============================================================================== --- py/dist/py/c-extension/greenlet/greenlet.c (original) +++ py/dist/py/c-extension/greenlet/greenlet.c Tue Sep 20 18:17:32 2005 @@ -255,6 +255,12 @@ #endif +/* This is a trick to prevent the compiler from inlining or + removing the frames */ +int (*_PyGreen_slp_switch) (void); +int (*_PyGreen_switchstack) (void); +void (*_PyGreen_initialstub) (void*); + static int g_switchstack(void) { /* perform a stack switch according to some global variables @@ -271,7 +277,7 @@ ts_current->top_frame = tstate->frame; } ts_origin = ts_current; - err = slp_switch(); + err = _PyGreen_slp_switch(); if (err < 0) { /* error */ Py_XDECREF(ts_passaround); ts_passaround = NULL; @@ -288,11 +294,6 @@ return err; } -/* This is a trick to prevent the compiler from inlining or - removing the frames */ -int (*_PyGreen_switchstack) (void); -void (*_PyGreen_initialstub) (void*); - static PyObject* g_switch(PyGreenlet* target, PyObject* args) { /* _consumes_ a reference to the args tuple, @@ -781,6 +782,7 @@ PyObject* m; char** p; _PyGreen_switchstack = g_switchstack; + _PyGreen_slp_switch = slp_switch; _PyGreen_initialstub = g_initialstub; m = Py_InitModule("greenlet", GreenMethods); From jan at codespeak.net Tue Sep 20 18:36:26 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Tue, 20 Sep 2005 18:36:26 +0200 (CEST) Subject: [py-svn] r17703 - in py/branch/monday/py/test: . terminal Message-ID: <20050920163626.6578E27B58@code1.codespeak.net> Author: jan Date: Tue Sep 20 18:36:25 2005 New Revision: 17703 Modified: py/branch/monday/py/test/session.py py/branch/monday/py/test/terminal/terminal.py Log: (arigo, hpk, jan) Shuffled even more stuff around Modified: py/branch/monday/py/test/session.py ============================================================================== --- py/branch/monday/py/test/session.py (original) +++ py/branch/monday/py/test/session.py Tue Sep 20 18:36:25 2005 @@ -1,10 +1,12 @@ import py +from time import time as now class Session(object): """ A Session gets test Items from Collectors, # executes the Items and sends the Outcome to the Reporter. """ + starttime = endtime = None def __init__(self, config): self._memo = [] self.config = config @@ -14,11 +16,13 @@ def header(self, colitems): """ setup any neccessary resources. """ + self.starttime = now() if not self.config.option.nomagic: py.magic.invoke(assertion=1) def footer(self, colitems): """ teardown any resources we know about. """ + self.endtime = now() py.test.Function.state.teardown_all() if not self.config.option.nomagic: py.magic.revoke(assertion=1) Modified: py/branch/monday/py/test/terminal/terminal.py ============================================================================== --- py/branch/monday/py/test/terminal/terminal.py (original) +++ py/branch/monday/py/test/terminal/terminal.py Tue Sep 20 18:36:25 2005 @@ -15,13 +15,53 @@ target = dest.sep.join(('..', )*n + (reldest, )) return target + +class TerminalReporter: + + def __init__(self, out): + self.out = out + + def summaryline(self, summaryinfo): + outlist = [] + for label, itemoutcomepairs in (('passed', summaryinfo.passed), + ('failed', summaryinfo.failed), + ('skipped', summaryinfo.skipped)): + if itemoutcomepairs: + outlist.append('%d %s' % (len(itemoutcomepairs), label)) + status = "%s" % ", ".join(outlist) + self.out.sep('=', 'tests finished: %s in %4.2f seconds' % + (status, summaryinfo.elapsedtime)) + + + class TerminalSession(py.test.Session): + + class SummaryInfo: + def __init__(self, session): + self.passed = session.getitemoutcomepairs(Item.Passed) + self.failed = session.getitemoutcomepairs(Item.Failed) + self.skipped = session.getitemoutcomepairs(Item.Skipped) + endtime = session.endtime or now() + self.elapsedtime = endtime - session.starttime + + def get_unique_skipped_locations(self): + texts = {} + for colitem, outcome in self.skipped: + raisingtb = outcome.excinfo.traceback.getcrashentry() + fn = raisingtb.frame.code.path + lineno = raisingtb.lineno + d = texts.setdefault(outcome.excinfo.exconly(), {}) + d[(fn,lineno)] = outcome + return texts + + def __init__(self, config, file=None): super(TerminalSession, self).__init__(config) if file is None: file = py.std.sys.stdout self._file = file - self.out = getout(file) + self.out = getout(file) + self.reporter = TerminalReporter(self.out) self._started = {} self._opencollectors = [] @@ -55,34 +95,45 @@ def start_Module(self, colitem): if self.config.option.verbose == 0: - abbrev_fn = getrelpath(py.path.local('.xxx.'), colitem.fspath) - self.out.write('%s' % (abbrev_fn, )) + self.report_abbrev_path_for_testmodule(colitem) else: - self.out.line() - self.out.line("+ testmodule: %s" % colitem.fspath) + self.report_path_for_testmodule(colitem) + + def report_path_for_testmodule(self, colitem): + self.out.line() + self.out.line("+ testmodule: %s" % colitem.fspath) + + def report_abbrev_path_for_testmodule(self, colitem): + abbrev_fn = getrelpath(py.path.local('dummy'), colitem.fspath) + self.out.write('%s' % (abbrev_fn, )) def startiteration(self, colitem, subitems): if (isinstance(colitem, py.test.collect.Module) and self.config.option.verbose == 0 and not self.config.option.collectonly): - try: - sum = 0 - for sub in subitems: - sum += len(list(colitem.join(sub).tryiter())) - except (SystemExit, KeyboardInterrupt): - raise - except: - self.out.write('[?]') - else: - self.out.write('[%d] ' % sum) - return self.out.line + return self.report_startiteration(colitem, subitems) + + def report_startiteration(self, colitem, subitems): + try: + sum = 0 + for sub in subitems: + sum += len(list(colitem.join(sub).tryiter())) + except (SystemExit, KeyboardInterrupt): + raise + except: + self.out.write('[?]') + else: + self.out.write('[%d] ' % sum) + return self.out.line def start_Item(self, colitem): if self.config.option.verbose >= 1: - if isinstance(colitem, py.test.Item): - realpath, lineno = colitem.getpathlineno() - location = "%s:%d" % (realpath.basename, lineno+1) - self.out.rewrite("%-20s %s " % (location, colitem.getmodpath())) + self.report_started_item(colitem) + + def report_started_item(self, colitem): + realpath, lineno = colitem.getpathlineno() + location = "%s:%d" % (realpath.basename, lineno+1) + self.out.rewrite("%-20s %s " % (location, colitem.getmodpath())) def finish(self, colitem, outcome): end = now() @@ -95,22 +146,34 @@ colitem.elapsedtime = end - colitem.start if self.config.option.usepdb: if isinstance(outcome, Item.Failed): - print "dispatching to ppdb", colitem - self.repr_failure(colitem, outcome) - import pdb - self.out.rewrite('\n%s\n' % (outcome.excinfo.exconly(),)) - pdb.post_mortem(outcome.excinfo._excinfo[2]) + self.start_pdb(colitem, outcome) if (isinstance(outcome, py.test.Item.Failed) and isinstance(colitem, py.test.collect.Module)): - self.out.line(" FAILED TO LOAD MODULE") + self.report_failed_to_load_module() if isinstance(colitem, py.test.Item): if self.config.option.verbose >= 1: - resultstring = self.repr_progress_long_result(colitem, outcome) - resultstring += " (%.2f)" % (colitem.elapsedtime,) - self.out.line(resultstring) + self.report_test_item_result_verbose(colitem, outcome) else: - c = self.repr_progress_short_result(colitem, outcome) - self.out.write(c) + self.report_test_item_result(colitem, outcome) + + def report_test_item_result(self, colitem, outcome): + c = self.report_string_result(colitem, outcome) + self.out.write(c) + + def report_test_item_result_verbose(self, colitem, outcome): + resultstring = self.report_string_result(colitem, outcome, verbose= True) + resultstring += " (%.2f)" % (colitem.elapsedtime,) + self.out.line(resultstring) + + def report_failed_to_load_module(self): + self.out.line(" FAILED TO LOAD MODULE") + + def start_pdb(self, colitem, outcome): + print "dispatching to ppdb", colitem + self.repr_failure(colitem, outcome) + import pdb + self.out.rewrite('\n%s\n' % (outcome.excinfo.exconly(),)) + pdb.post_mortem(outcome.excinfo._excinfo[2]) # ------------------- @@ -118,8 +181,30 @@ # ------------------- def header(self, colitems): super(TerminalSession, self).header(colitems) + self.report_header(self.config) + if self.config.option.traceconfig or self.config.option.verbose: + self.report_test_targets(colitems) + self.report_config_options(self.config) + self.out.line() + + def report_config_options(self, config): + for i,x in py.builtin.enumerate(config._initialconfigmodules): + self.out.line("initial conf %d: %s" %(i, x.__file__)) + + #for i, x in py.builtin.enumerate(py.test.config.configpaths): + # self.out.line("initial testconfig %d: %s" %(i, x)) + #additional = py.test.config.getfirst('additionalinfo') + #if additional: + # for key, descr in additional(): + # self.out.line("%s: %s" %(key, descr)) + + def report_test_targets(self, colitems): + for x in colitems: + self.out.line("test target: %s" %(x.fspath,)) + + def report_header(self, config): self.out.sep("=", "test process starts") - option = self.config.option + option = config.option modes = [] for name in 'looponfailing', 'exitfirst', 'nomagic': if getattr(option, name): @@ -134,24 +219,8 @@ (py.std.sys.executable, repr_pythonversion())) rev = py.__package__.getrev() self.out.line("using py lib: %s " % ( - py.path.local(py.__file__).dirpath(), rev)) - - if self.config.option.traceconfig or self.config.option.verbose: - - for x in colitems: - self.out.line("test target: %s" %(x.fspath,)) - - for i,x in py.builtin.enumerate(self.config._initialconfigmodules): - self.out.line("initial conf %d: %s" %(i, x.__file__)) - - #for i, x in py.builtin.enumerate(py.test.config.configpaths): - # self.out.line("initial testconfig %d: %s" %(i, x)) - #additional = py.test.config.getfirst('additionalinfo') - #if additional: - # for key, descr in additional(): - # self.out.line("%s: %s" %(key, descr)) - self.out.line() - self.starttime = now() + py.path.local(py.__file__).dirpath(), rev)) + # ------------------- # FOOTER information @@ -159,80 +228,64 @@ def footer(self, colitems): super(TerminalSession, self).footer(colitems) - self.endtime = now() self.out.line() - self.skippedreasons() - self.failures() - self.summaryline() + summaryinfo = self.SummaryInfo(self) + self.skippedreasons(summaryinfo) + self.failures(summaryinfo) + self.summaryline(summaryinfo) # -------------------- # progress information # -------------------- - typemap = { - Item.Passed: '.', - Item.Skipped: 's', - Item.Failed: 'F', - } - namemap = { - Item.Passed: 'ok', - Item.Skipped: 'SKIP', - Item.Failed: 'FAIL', - } - def repr_progress_short_result(self, item, outcome): - for outcometype, char in self.typemap.items(): + def report_string_result(self, item, outcome, verbose=False): + typemap = { + Item.Passed: '.', + Item.Skipped: 's', + Item.Failed: 'F', + type(None): '?', + } + namemap = { + Item.Passed: 'ok', + Item.Skipped: 'SKIP', + Item.Failed: 'FAIL', + type(None): 'UNKNOWN', + } + + if verbose: + item2message = namemap + else: + item2message = typemap + for outcometype, message in item2message.items(): if isinstance(outcome, outcometype): - return char + return message else: #raise TypeError, "not an Outomce instance: %r" % (outcome,) - return '?' + return item2message[type(None)] - def repr_progress_long_result(self, item, outcome): - for outcometype, char in self.namemap.items(): - if isinstance(outcome, outcometype): - return char - else: - #raise TypeError, "not an Outcome instance: %r" % (outcome,) - return 'UNKNOWN' # -------------------- # summary information # -------------------- - def summaryline(self): + def summaryline(self, summaryinfo): + self.reporter.summaryline(summaryinfo) + + def report_summary(self, summaryinfo): outlist = [] - sum = 0 - for typ in Item.Passed, Item.Failed, Item.Skipped: - l = self.getitemoutcomepairs(typ) - if l: - outlist.append('%d %s' % (len(l), typ.__name__.lower())) - sum += len(l) - elapsed = self.endtime-self.starttime + for label, itemoutcomepairs in (('passed', summaryinfo.passed), + ('failed', summaryinfo.failed), + ('skipped', summaryinfo.skipped)): + if itemoutcomepairs: + outlist.append('%d %s' % (len(itemoutcomepairs), label)) status = "%s" % ", ".join(outlist) self.out.sep('=', 'tests finished: %s in %4.2f seconds' % - (status, elapsed)) + (status, summaryinfo.elapsedtime)) - def getlastvisible(self, sourcetraceback): - traceback = sourcetraceback[:] - while traceback: - entry = traceback.pop() - try: - x = entry.frame.eval("__tracebackhide__") - except: - x = False - if not x: - return entry - else: - return sourcetraceback[-1] + def skippedreasons(self, summaryinfo): + self.report_skippedreasons(summaryinfo) - def skippedreasons(self): - texts = {} - for colitem, outcome in self.getitemoutcomepairs(Item.Skipped): - raisingtb = self.getlastvisible(outcome.excinfo.traceback) - fn = raisingtb.frame.code.path - lineno = raisingtb.lineno - d = texts.setdefault(outcome.excinfo.exconly(), {}) - d[(fn,lineno)] = outcome - + def report_skippedreasons(self, summaryinfo): + texts = summaryinfo.get_unique_skipped_locations() if texts: self.out.line() self.out.sep('_', 'reasons for skipped tests') @@ -242,8 +295,12 @@ self.out.line("reason: %s" % text) self.out.line() - def failures(self): - l = self.getitemoutcomepairs(Item.Failed) + + def failures(self, summaryinfo): + self.report_failures(summaryinfo) + + def report_failures(self, summaryinfo): + l = summaryinfo.failed if l: self.out.sep('_') for colitem, outcome in l: From jan at codespeak.net Thu Sep 22 21:00:03 2005 From: jan at codespeak.net (jan at codespeak.net) Date: Thu, 22 Sep 2005 21:00:03 +0200 (CEST) Subject: [py-svn] r17773 - in py/branch/monday/py/test: terminal tkinter Message-ID: <20050922190003.1349A27B95@code1.codespeak.net> Author: jan Date: Thu Sep 22 21:00:01 2005 New Revision: 17773 Modified: py/branch/monday/py/test/terminal/terminal.py py/branch/monday/py/test/tkinter/util.py Log: moved a lot of code to the new TerminalReporter Modified: py/branch/monday/py/test/terminal/terminal.py ============================================================================== --- py/branch/monday/py/test/terminal/terminal.py (original) +++ py/branch/monday/py/test/terminal/terminal.py Thu Sep 22 21:00:01 2005 @@ -32,8 +32,162 @@ self.out.sep('=', 'tests finished: %s in %4.2f seconds' % (status, summaryinfo.elapsedtime)) + def skippedreasons(self, summaryinfo): + texts = summaryinfo.get_unique_skipped_locations() + if texts: + self.out.line() + self.out.sep('_', 'reasons for skipped tests') + for text, dict in texts.items(): + for (fn, lineno), outcome in dict.items(): + self.out.line('Skipped in %s:%d' %(fn, lineno+1)) + self.out.line("reason: %s" % text) + self.out.line() + + def repr_out_err(self, colitem): + for parent in colitem.listchain(): + for name, obj in zip(['out', 'err'], parent.getouterr()): + if obj: + self.out.sep("- ", "%s: recorded std%s" % (parent.name, name)) + self.out.line(obj) + + def repr_locals(self, entry): + self.out.sep('- ', 'locals') + for name, value in entry.frame.f_locals.items(): + if name == '__builtins__': + self.out.line("__builtins__ = ") + elif len(repr(value)) < 70 or not isinstance(value, + (list, tuple, dict)): + self.out.line("%-10s = %r" %(name, value)) + else: + self.out.line("%-10s =\\" % (name,)) + py.std.pprint.pprint(value, stream=self.out) + def repr_failure_explanation(self, excinfo, source): + try: + s = str(source.getstatement(len(source)-1)) + except KeyboardInterrupt: + raise + except: + s = str(source[-1]) + indent = " " * (4 + (len(s) - len(s.lstrip()))) + # get the real exception information out + lines = excinfo.exconly(tryshort=True).split('\n') + self.out.line('>' + indent[:-1] + lines.pop(0)) + for x in lines: + self.out.line(indent + x) + return + + # XXX reinstate the following with a --magic option? + # the following line gets user-supplied messages (e.g. + # for "assert 0, 'custom message'") + msg = getattr(getattr(excinfo, 'value', ''), 'msg', '') + info = None + if not msg: + special = excinfo.errisinstance((SyntaxError, SystemExit, KeyboardInterrupt)) + if not self.config.option.nomagic and not special: + try: + info = excinfo.traceback[-1].reinterpret() # very detailed info + except KeyboardInterrupt: + raise + except: + if self.config.option.verbose >= 1: + self.out.line("[reinterpretation traceback]") + py.std.traceback.print_exc(file=py.std.sys.stdout) + else: + self.out.line("[reinterpretation failed, increase " + "verbosity to see details]") + # print reinterpreted info if any + if info: + lines = info.split('\n') + self.out.line('>' + indent[:-1] + lines.pop(0)) + for x in lines: + self.out.line(indent + x) + + def repr_source(self, source, marker=">"): + for line in source[:-1]: + self.out.line(" " + line) + lastline = source[-1] + self.out.line(marker + " " + lastline) + + def getentrysource(self, entry): + try: + source = entry.getsource() + except py.error.ENOENT: + source = py.code.Source("[failure to get at sourcelines from %r]\n" % entry) + return source.deindent() + + def repr_failure_info(self, item, entry): + root = item.fspath + modpath = item.getmodpath() + try: + fn, lineno = item.getpathlineno() + except TypeError: + assert isinstance(item.parent, py.test.collect.Generator) + # a generative test yielded a non-callable + fn, lineno = item.parent.getpathlineno() + # hum, the following overloads traceback output + #if fn != entry.frame.code.path or \ + # entry.frame.code.firstlineno != lineno: + # self.out.line("testcode: %s:%d" % (fn, lineno+1)) + if root == fn: + self.out.sep("_", "entrypoint: %s" %(modpath)) + else: + self.out.sep("_", "entrypoint: %s %s" %(root.basename, modpath)) + + + def repr_failure(self, item, outcome, config): + self.config = config + excinfo = outcome.excinfo + traceback = excinfo.traceback + #print "repr_failures sees item", item + #print "repr_failures sees traceback" + #py.std.pprint.pprint(traceback) + if item and not self.config.option.fulltrace: + path, firstlineno = item.getpathlineno() + ntraceback = traceback.cut(path=path, firstlineno=firstlineno) + if ntraceback == traceback: + ntraceback = ntraceback.cut(path=path) + traceback = ntraceback.filter() + if not traceback: + self.out.line("empty traceback from item %r" % (item,)) + return + last = traceback[-1] + first = traceback[0] + if not self.config.option.nomagic and excinfo.errisinstance(RuntimeError): + recursionindex = traceback.recursionindex() + else: + recursionindex = None + for index, entry in py.builtin.enumerate(traceback): + if entry == first: + if item: + self.repr_failure_info(item, entry) + self.out.line() + else: + self.out.line("") + source = self.getentrysource(entry) + if entry == last: + self.repr_source(source, 'E') + self.repr_failure_explanation(excinfo, source) + else: + self.repr_source(source, '>') + self.out.line("") + self.out.line("[%s:%d]" %(entry.frame.code.path, entry.lineno+1)) + self.repr_locals(entry) + + # trailing info + if entry == last: + #if item: + # self.repr_failure_info(item, entry) + self.repr_out_err(item) + self.out.sep("_") + else: + self.out.sep("_ ") + if index == recursionindex: + self.out.line("Recursion detected (same locals & position)") + self.out.sep("!") + break + class TerminalSession(py.test.Session): class SummaryInfo: @@ -41,6 +195,7 @@ self.passed = session.getitemoutcomepairs(Item.Passed) self.failed = session.getitemoutcomepairs(Item.Failed) self.skipped = session.getitemoutcomepairs(Item.Skipped) + self.config = session.config endtime = session.endtime or now() self.elapsedtime = endtime - session.starttime @@ -55,12 +210,15 @@ return texts - def __init__(self, config, file=None): + def __init__(self, config, file=None, out=None): super(TerminalSession, self).__init__(config) if file is None: file = py.std.sys.stdout self._file = file - self.out = getout(file) + if out is None: + self.out = getout(file) + else: + self.out = out self.reporter = TerminalReporter(self.out) self._started = {} self._opencollectors = [] @@ -230,9 +388,9 @@ super(TerminalSession, self).footer(colitems) self.out.line() summaryinfo = self.SummaryInfo(self) - self.skippedreasons(summaryinfo) + self.reporter.skippedreasons(summaryinfo) self.failures(summaryinfo) - self.summaryline(summaryinfo) + self.reporter.summaryline(summaryinfo) # -------------------- # progress information @@ -267,187 +425,15 @@ # -------------------- # summary information # -------------------- - def summaryline(self, summaryinfo): - self.reporter.summaryline(summaryinfo) - def report_summary(self, summaryinfo): - outlist = [] - for label, itemoutcomepairs in (('passed', summaryinfo.passed), - ('failed', summaryinfo.failed), - ('skipped', summaryinfo.skipped)): - if itemoutcomepairs: - outlist.append('%d %s' % (len(itemoutcomepairs), label)) - status = "%s" % ", ".join(outlist) - self.out.sep('=', 'tests finished: %s in %4.2f seconds' % - (status, summaryinfo.elapsedtime)) - - def skippedreasons(self, summaryinfo): - self.report_skippedreasons(summaryinfo) - - def report_skippedreasons(self, summaryinfo): - texts = summaryinfo.get_unique_skipped_locations() - if texts: - self.out.line() - self.out.sep('_', 'reasons for skipped tests') - for text, dict in texts.items(): - for (fn, lineno), outcome in dict.items(): - self.out.line('Skipped in %s:%d' %(fn, lineno+1)) - self.out.line("reason: %s" % text) - self.out.line() - - def failures(self, summaryinfo): - self.report_failures(summaryinfo) - - def report_failures(self, summaryinfo): l = summaryinfo.failed if l: self.out.sep('_') for colitem, outcome in l: - self.repr_failure(colitem, outcome) + self.reporter.repr_failure(colitem, outcome, self.config) - def repr_failure(self, item, outcome): - excinfo = outcome.excinfo - traceback = excinfo.traceback - #print "repr_failures sees item", item - #print "repr_failures sees traceback" - #py.std.pprint.pprint(traceback) - if item and not self.config.option.fulltrace: - path, firstlineno = item.getpathlineno() - ntraceback = traceback.cut(path=path, firstlineno=firstlineno) - if ntraceback == traceback: - ntraceback = ntraceback.cut(path=path) - traceback = ntraceback.filter() - if not traceback: - self.out.line("empty traceback from item %r" % (item,)) - return - last = traceback[-1] - first = traceback[0] - if not self.config.option.nomagic and excinfo.errisinstance(RuntimeError): - recursionindex = traceback.recursionindex() - else: - recursionindex = None - for index, entry in py.builtin.enumerate(traceback): - if entry == first: - if item: - self.repr_failure_info(item, entry) - self.out.line() - else: - self.out.line("") - source = self.getentrysource(entry) - if entry == last: - self.repr_source(source, 'E') - self.repr_failure_explanation(excinfo, source) - else: - self.repr_source(source, '>') - self.out.line("") - self.out.line("[%s:%d]" %(entry.frame.code.path, entry.lineno+1)) - self.repr_locals(entry) - - # trailing info - if entry == last: - #if item: - # self.repr_failure_info(item, entry) - self.repr_out_err(item) - self.out.sep("_") - else: - self.out.sep("_ ") - if index == recursionindex: - self.out.line("Recursion detected (same locals & position)") - self.out.sep("!") - break - def repr_failure_info(self, item, entry): - root = item.fspath - modpath = item.getmodpath() - try: - fn, lineno = item.getpathlineno() - except TypeError: - assert isinstance(item.parent, py.test.collect.Generator) - # a generative test yielded a non-callable - fn, lineno = item.parent.getpathlineno() - # hum, the following overloads traceback output - #if fn != entry.frame.code.path or \ - # entry.frame.code.firstlineno != lineno: - # self.out.line("testcode: %s:%d" % (fn, lineno+1)) - if root == fn: - self.out.sep("_", "entrypoint: %s" %(modpath)) - else: - self.out.sep("_", "entrypoint: %s %s" %(root.basename, modpath)) - - def getentrysource(self, entry): - try: - source = entry.getsource() - except py.error.ENOENT: - source = py.code.Source("[failure to get at sourcelines from %r]\n" % entry) - return source.deindent() - - def repr_source(self, source, marker=">"): - for line in source[:-1]: - self.out.line(" " + line) - lastline = source[-1] - self.out.line(marker + " " + lastline) - - def repr_failure_explanation(self, excinfo, source): - try: - s = str(source.getstatement(len(source)-1)) - except KeyboardInterrupt: - raise - except: - s = str(source[-1]) - indent = " " * (4 + (len(s) - len(s.lstrip()))) - # get the real exception information out - lines = excinfo.exconly(tryshort=True).split('\n') - self.out.line('>' + indent[:-1] + lines.pop(0)) - for x in lines: - self.out.line(indent + x) - return - - # XXX reinstate the following with a --magic option? - # the following line gets user-supplied messages (e.g. - # for "assert 0, 'custom message'") - msg = getattr(getattr(excinfo, 'value', ''), 'msg', '') - info = None - if not msg: - special = excinfo.errisinstance((SyntaxError, SystemExit, KeyboardInterrupt)) - if not self.config.option.nomagic and not special: - try: - info = excinfo.traceback[-1].reinterpret() # very detailed info - except KeyboardInterrupt: - raise - except: - if self.config.option.verbose >= 1: - self.out.line("[reinterpretation traceback]") - py.std.traceback.print_exc(file=py.std.sys.stdout) - else: - self.out.line("[reinterpretation failed, increase " - "verbosity to see details]") - # print reinterpreted info if any - if info: - lines = info.split('\n') - self.out.line('>' + indent[:-1] + lines.pop(0)) - for x in lines: - self.out.line(indent + x) - - def repr_out_err(self, colitem): - for parent in colitem.listchain(): - for name, obj in zip(['out', 'err'], parent.getouterr()): - if obj: - self.out.sep("- ", "%s: recorded std%s" % (parent.name, name)) - self.out.line(obj) - - def repr_locals(self, entry): - if self.config.option.showlocals: - self.out.sep('- ', 'locals') - for name, value in entry.frame.f_locals.items(): - if name == '__builtins__': - self.out.line("__builtins__ = ") - elif len(repr(value)) < 70 or not isinstance(value, - (list, tuple, dict)): - self.out.line("%-10s = %r" %(name, value)) - else: - self.out.line("%-10s =\\" % (name,)) - py.std.pprint.pprint(value, stream=self.out) def repr_pythonversion(): v = py.std.sys.version_info Modified: py/branch/monday/py/test/tkinter/util.py ============================================================================== --- py/branch/monday/py/test/tkinter/util.py (original) +++ py/branch/monday/py/test/tkinter/util.py Thu Sep 22 21:00:01 2005 @@ -201,9 +201,8 @@ def report_failed(self, config, item, res): #XXX hack abuse of TerminalSession - terminal = py.test.TerminalSession(config) out = OutBuffer() - terminal.out = out + terminal = py.test.TerminalSession(config, out = out) terminal.repr_failure(item, res) #terminal.repr_out_err(item) return out.getoutput() From hpk at codespeak.net Thu Sep 29 10:20:27 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 29 Sep 2005 10:20:27 +0200 (CEST) Subject: [py-svn] r17965 - in py/dist/py: log log/testing misc path/local Message-ID: <20050929082027.153FE27B9C@code1.codespeak.net> Author: hpk Date: Thu Sep 29 10:20:25 2005 New Revision: 17965 Modified: py/dist/py/log/logger.py (props changed) py/dist/py/log/testing/test_logger.py (props changed) py/dist/py/misc/dynpkg.py (props changed) py/dist/py/path/local/common.py (props changed) Log: FIXEOL From tismer at codespeak.net Fri Sep 30 00:38:24 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 30 Sep 2005 00:38:24 +0200 (CEST) Subject: [py-svn] r17988 - py/dist/py/documentation Message-ID: <20050929223824.5A06827BA7@code1.codespeak.net> Author: tismer Date: Fri Sep 30 00:38:23 2005 New Revision: 17988 Modified: py/dist/py/documentation/why_py.txt Log: tyop Modified: py/dist/py/documentation/why_py.txt ============================================================================== --- py/dist/py/documentation/why_py.txt (original) +++ py/dist/py/documentation/why_py.txt Fri Sep 30 00:38:23 2005 @@ -278,5 +278,5 @@ -- -.. [#] FOSS i an evolving acronym for Free and Open Source Software +.. [#] FOSS is an evolving acronym for Free and Open Source Software From hpk at codespeak.net Fri Sep 30 11:04:11 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 30 Sep 2005 11:04:11 +0200 (CEST) Subject: [py-svn] r17999 - py/dist/py/misc Message-ID: <20050930090411.4D30D27BB1@code1.codespeak.net> Author: hpk Date: Fri Sep 30 11:04:10 2005 New Revision: 17999 Modified: py/dist/py/misc/rest.py Log: account for a docutils-snapshot configuration change (they set stylesheet_path themselves) Modified: py/dist/py/misc/rest.py ============================================================================== --- py/dist/py/misc/rest.py (original) +++ py/dist/py/misc/rest.py Fri Sep 30 11:04:10 2005 @@ -18,6 +18,7 @@ from docutils.core import publish_string kwargs = { 'stylesheet' : stylesheet, + 'stylesheet_path': None, 'traceback' : 1, 'output_encoding' : encoding, #'halt' : 0, # 'info',