From hpk at codespeak.net Sat Jan 1 20:05:52 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 1 Jan 2005 20:05:52 +0100 (MET) Subject: [py-svn] r8024 - py/dist/py/misc Message-ID: <20050101190552.2FF035A1B3@thoth.codespeak.net> Author: hpk Date: Sat Jan 1 20:05:51 2005 New Revision: 8024 Added: py/dist/py/misc/cache.py - copied, changed from r8023, user/hpk/mycache.py py/dist/py/misc/test_cache.py Log: some experimental cache code (to be used for svn-related tests and stuff) Copied: py/dist/py/misc/cache.py (from r8023, user/hpk/mycache.py) ============================================================================== --- user/hpk/mycache.py (original) +++ py/dist/py/misc/cache.py Sat Jan 1 20:05:51 2005 @@ -1,6 +1,16 @@ -import py +""" +This module contains cache implementations. +Caches mainly have a __getitem__ and a +getorbuild() method, which either just +return a cached value or first builds the value. + +These are the current cache implementations: -dummy = object() + BACache tracks build-time and accesses and evicts + by product of num-access * build-time. + +""" +import py class WValue(object): def __init__(self, value, oneweight): @@ -19,8 +29,8 @@ self.num += 1 return self.value -class BACache(object): - """ A Buildtime/Access cache implementation. +class BTACache(object): + """ A BuildTime/Access-counting cache implementation. the weight of a value is computed as the product of num-accesses-of-a-value * time-to-build-the-value @@ -74,28 +84,3 @@ items.sort() for weight, key in items[:-(self.size-self.prunenum)]: del self._dict[key] - -def test_cache_works_somewhat_simple(): - cache = BACache() - for x in range(cache.size): - y = cache.getorbuild(x, lambda: x) - assert x == y - for x in range(cache.size): - assert cache.getorbuild(x, None) == x - for x in range(cache.size/2): - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(x, None) == x - val = cache.getorbuild(cache.size * 2, lambda: 42) - assert val == 42 - # check that recently used ones are still there - # and are not build again - for x in range(cache.size/2): - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(cache.size*2, None) == 42 - -def test_cache_get_key_error(): - cache = BACache() - cache.getorbuild(0, lambda: 0) - py.test.raises(KeyError, "cache[1]") - Added: py/dist/py/misc/test_cache.py ============================================================================== --- (empty file) +++ py/dist/py/misc/test_cache.py Sat Jan 1 20:05:51 2005 @@ -0,0 +1,27 @@ +import py +from cache import BTACache + +def test_cache_works_somewhat_simple(): + cache = BTACache() + for x in range(cache.size): + y = cache.getorbuild(x, lambda: x) + assert x == y + for x in range(cache.size): + assert cache.getorbuild(x, None) == x + for x in range(cache.size/2): + assert cache.getorbuild(x, None) == x + assert cache.getorbuild(x, None) == x + assert cache.getorbuild(x, None) == x + val = cache.getorbuild(cache.size * 2, lambda: 42) + assert val == 42 + # check that recently used ones are still there + # and are not build again + for x in range(cache.size/2): + assert cache.getorbuild(x, None) == x + assert cache.getorbuild(cache.size*2, None) == 42 + +def test_cache_get_key_error(): + cache = BTACache() + cache.getorbuild(0, lambda: 0) + py.test.raises(KeyError, "cache[1]") + From hpk at codespeak.net Sat Jan 1 20:07:45 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 1 Jan 2005 20:07:45 +0100 (MET) Subject: [py-svn] r8025 - py/dist/py/misc Message-ID: <20050101190745.52DDA5A1B3@thoth.codespeak.net> Author: hpk Date: Sat Jan 1 20:07:44 2005 New Revision: 8025 Modified: py/dist/py/misc/cache.py Log: fixes to docstrings. Modified: py/dist/py/misc/cache.py ============================================================================== --- py/dist/py/misc/cache.py (original) +++ py/dist/py/misc/cache.py Sat Jan 1 20:07:44 2005 @@ -1,13 +1,17 @@ """ -This module contains cache implementations. -Caches mainly have a __getitem__ and a -getorbuild() method, which either just -return a cached value or first builds the value. +This module contains multithread-safe cache implementations. + +Caches mainly have a + + __getitem__ and getorbuild() method + +where the latter either just return a cached value or +first builds the value. These are the current cache implementations: - BACache tracks build-time and accesses and evicts - by product of num-access * build-time. + BTACache tracks building-time and accesses. Evicts + by product of num-accesses * build-time. """ import py From hpk at codespeak.net Sun Jan 2 11:59:38 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 2 Jan 2005 11:59:38 +0100 (MET) Subject: [py-svn] r8029 - py/dist/py/misc Message-ID: <20050102105938.632E25AA66@thoth.codespeak.net> Author: hpk Date: Sun Jan 2 11:59:37 2005 New Revision: 8029 Modified: py/dist/py/misc/cache.py py/dist/py/misc/test_cache.py Log: refactored the internal experimental cache implementation, now there are two somewhat working caches: BuildcostAccessCache will prune entries that have the lowest build-cost * num-accesses weight. build-cost is measured in seconds. AgingCache will prune entries if they exceed their lifetime. Modified: py/dist/py/misc/cache.py ============================================================================== --- py/dist/py/misc/cache.py (original) +++ py/dist/py/misc/cache.py Sun Jan 2 11:59:37 2005 @@ -10,16 +10,17 @@ These are the current cache implementations: - BTACache tracks building-time and accesses. Evicts + BuildcostAccessCache tracks building-time and accesses. Evicts by product of num-accesses * build-time. """ import py +gettime = py.std.time.time -class WValue(object): +class WeightedCountingEntry(object): def __init__(self, value, oneweight): self.num = 1 - self.value = value + self._value = value self.oneweight = oneweight def weight(): @@ -28,63 +29,126 @@ return property(fget, None, None, "cumulative weight") weight = weight() - def get(self): - # you need to protect against mt-access at caller side! - self.num += 1 - return self.value + def value(): + def fget(self): + # you need to protect against mt-access at caller side! + self.num += 1 + return self._value + return property(fget, None, None) + value = value() + +class BasicCache(object): + def __init__(self, maxentries=128): + self.maxentries = maxentries + self.prunenum = maxentries - int(maxentries/8) + self._lock = py.std.threading.RLock() + self._dict = {} + + def getentry(self, key): + lock = self._lock + lock.acquire() + try: + return self._dict.get(key, None) + finally: + lock.release() + + def putentry(self, key, entry): + self._lock.acquire() + try: + self._prunelowestweight() + self._dict[key] = entry + finally: + self._lock.release() + + def delentry(self, key, raising=False): + self._lock.acquire() + try: + try: + del self._dict[key] + except KeyError: + if raising: + raise + finally: + self._lock.release() -class BTACache(object): + def getorbuild(self, key, builder, *args, **kwargs): + entry = self.getentry(key) + if entry is None: + entry = self.build(key, builder, *args, **kwargs) + return entry.value + + def _prunelowestweight(self): + """ prune out entries with lowest weight. """ + # note: must be called with acquired self._lock! + numentries = len(self._dict) + if numentries >= self.maxentries: + # evict according to entry's weight + items = [(entry.weight, key) for key, entry in self._dict.iteritems()] + items.sort() + index = numentries - self.prunenum + if index > 0: + for weight, key in items[:index]: + del self._dict[key] + +class BuildcostAccessCache(BasicCache): """ A BuildTime/Access-counting cache implementation. the weight of a value is computed as the product of num-accesses-of-a-value * time-to-build-the-value The values with the least such weights are evicted - if the cache size threshold is superceded. + if the cache maxentries threshold is superceded. For implementation flexibility more than one object might be evicted at a time. """ # time function to use for measuring build-times - _time = py.std.time.time + _time = gettime - def __init__(self, size=64): - self.size = size - self.prunenum = int(size / 8) - self._dict = {} - self._lock = py.std.threading.RLock() + def __init__(self, maxentries=64): + super(BuildcostAccessCache, self).__init__(maxentries) - def getorbuild(self, key, builder, *args, **kwargs): - try: - return self[key] - except KeyError: - entry = self.build(builder, *args, **kwargs) - self._lock.acquire() + def build(self, key, builder, *args, **kwargs): + start = self._time() + val = builder(*args, **kwargs) + end = self._time() + entry = WeightedCountingEntry(val, end-start) + self.putentry(key, entry) + return entry + +class AgingCache(BasicCache): + """ This cache prunes out cache entries that are too old. + """ + def __init__(self, maxentries=128, maxseconds=10.0): + super(AgingCache, self).__init__(maxentries) + self.maxseconds = maxseconds + + def getentry(self, key): + self._lock.acquire() + try: try: - self._prune() - self._dict[key] = entry - return entry.get() - finally: - self._lock.release() - - def __getitem__(self, key): - lock = self._lock - lock.acquire() - try: - return self._dict[key].get() + entry = self._dict[key] + except KeyError: + entry = None + else: + if entry.isexpired(): + del self._dict[key] + entry = None + return entry finally: - lock.release() + self._lock.release() - def build(self, builder, *args, **kwargs): - start = self._time() + def build(self, key, builder, *args, **kwargs): + ctime = gettime() val = builder(*args, **kwargs) - end = self._time() - return WValue(val, end-start) + entry = AgingEntry(val, ctime + self.maxseconds) + self.putentry(key, entry) + return entry - def _prune(self): - # must be called with acquired lock - if len(self._dict) >= self.size: - # evict according to entry's weight - items = [(entry.weight, key) for key, entry in self._dict.iteritems()] - items.sort() - for weight, key in items[:-(self.size-self.prunenum)]: - del self._dict[key] +class AgingEntry(object): + def __init__(self, value, expirationtime): + self.value = value + self.expirationtime = expirationtime + + def isexpired(self): + t = py.std.time.time() + return t >= self.expirationtime Modified: py/dist/py/misc/test_cache.py ============================================================================== --- py/dist/py/misc/test_cache.py (original) +++ py/dist/py/misc/test_cache.py Sun Jan 2 11:59:37 2005 @@ -1,27 +1,55 @@ import py -from cache import BTACache +from cache import BuildcostAccessCache, AgingCache -def test_cache_works_somewhat_simple(): - cache = BTACache() - for x in range(cache.size): - y = cache.getorbuild(x, lambda: x) - assert x == y - for x in range(cache.size): - assert cache.getorbuild(x, None) == x - for x in range(cache.size/2): - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(x, None) == x - val = cache.getorbuild(cache.size * 2, lambda: 42) - assert val == 42 - # check that recently used ones are still there - # and are not build again - for x in range(cache.size/2): - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(cache.size*2, None) == 42 - -def test_cache_get_key_error(): - cache = BTACache() - cache.getorbuild(0, lambda: 0) - py.test.raises(KeyError, "cache[1]") - +class BasicCacheAPITest: + cache = None + def test_getorbuild(self): + val = self.cache.getorbuild(-42, lambda: 42) + assert val == 42 + val = self.cache.getorbuild(-42, lambda: 23) + assert val == 42 + + def test_cache_get_key_error(self): + assert self.cache.getentry(-23) == None + + def test_delentry_non_raising(self): + val = self.cache.getorbuild(100, lambda: 100) + self.cache.delentry(100) + assert self.cache.getentry(100) is None + + def test_delentry_raising(self): + val = self.cache.getorbuild(100, lambda: 100) + self.cache.delentry(100) + py.test.raises(KeyError, "self.cache.delentry(100, raising=True)") + +class TestBuildcostAccess(BasicCacheAPITest): + cache = BuildcostAccessCache(maxentries=128) + + def test_cache_works_somewhat_simple(self): + cache = BuildcostAccessCache() + for x in range(cache.maxentries): + y = cache.getorbuild(x, lambda: x) + assert x == y + for x in range(cache.maxentries): + assert cache.getorbuild(x, None) == x + for x in range(cache.maxentries/2): + assert cache.getorbuild(x, None) == x + assert cache.getorbuild(x, None) == x + assert cache.getorbuild(x, None) == x + val = cache.getorbuild(cache.maxentries * 2, lambda: 42) + assert val == 42 + # check that recently used ones are still there + # and are not build again + for x in range(cache.maxentries/2): + assert cache.getorbuild(x, None) == x + assert cache.getorbuild(cache.maxentries*2, None) == 42 + + +class TestAging(BasicCacheAPITest): + maxsecs = 0.02 + cache = AgingCache(maxentries=128, maxseconds=maxsecs) + + def test_cache_eviction(self): + self.cache.getorbuild(17, lambda: 17) + py.std.time.sleep(self.maxsecs*1.1) + assert self.cache.getentry(17) is None From hpk at codespeak.net Sun Jan 2 12:30:05 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 2 Jan 2005 12:30:05 +0100 (MET) Subject: [py-svn] r8030 - py/dist/py/test/report/text Message-ID: <20050102113005.A1DB85AA66@thoth.codespeak.net> Author: hpk Date: Sun Jan 2 12:30:05 2005 New Revision: 8030 Modified: py/dist/py/test/report/text/reporter.py Log: always show lineno+1 to humans Modified: py/dist/py/test/report/text/reporter.py ============================================================================== --- py/dist/py/test/report/text/reporter.py (original) +++ py/dist/py/test/report/text/reporter.py Sun Jan 2 12:30:05 2005 @@ -149,7 +149,7 @@ if writeinfo is not None: realpath, lineno = item.extpy.getfilelineno() - location = "%s:%d" % (realpath.basename, lineno) + location = "%s:%d" % (realpath.basename, lineno+1) resultstring = self.namemap.get(restype, result.__class__.__name__) self.out.rewrite("%.3f %-2s %-20s %s%s" % ( elapsed, resultstring, location, item.reprcall(), writeinfo From hpk at codespeak.net Sun Jan 2 12:31:02 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 2 Jan 2005 12:31:02 +0100 (MET) Subject: [py-svn] r8031 - py/dist/py/code Message-ID: <20050102113102.0B4FB5AA66@thoth.codespeak.net> Author: hpk Date: Sun Jan 2 12:31:01 2005 New Revision: 8031 Modified: py/dist/py/code/excinfo.py py/dist/py/code/frame.py Log: - return None if source code cannot be found or read - a more telling __repr__ for TracebackEntries Modified: py/dist/py/code/excinfo.py ============================================================================== --- py/dist/py/code/excinfo.py (original) +++ py/dist/py/code/excinfo.py Sun Jan 2 12:31:01 2005 @@ -95,3 +95,6 @@ def path(self): return self.frame.path path = property(path, None, None, "path to the full source code") + + def __repr__(self): + return "" %(self.frame.code.path, self.lineno + 1) Modified: py/dist/py/code/frame.py ============================================================================== --- py/dist/py/code/frame.py (original) +++ py/dist/py/code/frame.py Sun Jan 2 12:31:01 2005 @@ -16,7 +16,10 @@ try: return fn.__source__ except AttributeError: - return py.code.Source(self.path.read(mode="rU")) + try: + return py.code.Source(self.path.read(mode="rU")) + except py.path.NotFound: + return None fullsource = property(fullsource, None, None, "full source containing this code object") From hpk at codespeak.net Sun Jan 2 12:35:29 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 2 Jan 2005 12:35:29 +0100 (MET) Subject: [py-svn] r8032 - py/dist/py/path/svn Message-ID: <20050102113529.C315B5AA66@thoth.codespeak.net> Author: hpk Date: Sun Jan 2 12:35:29 2005 New Revision: 8032 Modified: py/dist/py/path/svn/svncommon.py py/dist/py/path/svn/urlcommand.py Log: - introduce a cache for reading svn listdir entries. there are two caches, one AgingCache for rev==None and one BuildcostAccess cache for rev != None. The latter has no consistency problems while the former cannot account for changes made in other processes (it does invalidate the cache on mkdir/remove/copy invocations, though) - get rid of other uncleaner caching in the checkers. Modified: py/dist/py/path/svn/svncommon.py ============================================================================== --- py/dist/py/path/svn/svncommon.py (original) +++ py/dist/py/path/svn/svncommon.py Sun Jan 2 12:35:29 2005 @@ -210,16 +210,9 @@ # return rev class Checkers(common.FSCheckers): - def _info(self): - try: - return self._infocache - except AttributeError: - self._infocache = self.path.info() - return self._infocache - def dir(self): try: - return self._info().kind == 'dir' + return self.path.info().kind == 'dir' except IOError: return self._listdirworks() @@ -233,13 +226,13 @@ def file(self): try: - return self._info().kind == 'file' + return self.path.info().kind == 'file' except (IOError, error.FileNotFound): return False def exists(self): try: - return self._info() + return self.path.info() except IOError: return self._listdirworks() Modified: py/dist/py/path/svn/urlcommand.py ============================================================================== --- py/dist/py/path/svn/urlcommand.py (original) +++ py/dist/py/path/svn/urlcommand.py Sun Jan 2 12:35:29 2005 @@ -10,14 +10,18 @@ from py.__impl__.path import common from py.__impl__.path import error from py.__impl__.path.svn import svncommon +from py.__impl__.misc.cache import BuildcostAccessCache, AgingCache class SvnCommandPath(svncommon.SvnPathBase): + _lsrevcache = BuildcostAccessCache(maxentries=128) + _lsnorevcache = AgingCache(maxentries=1000, maxseconds=60.0) + def __new__(cls, path, rev=None): - if isinstance(path, cls): - if path.rev == rev: - return path self = object.__new__(cls) - self.strpath = path.rstrip('/') + if not isinstance(path, str): + path = str(path) + path = path.rstrip('/') + self.strpath = path self.rev = rev return self @@ -64,22 +68,24 @@ return popen(svncommon.fixlocale() + 'svn cat -r %s "%s"' % (self.rev, self.strpath)) - def mkdir(self, commit_msg=None): - if commit_msg: - self._svnwrite('mkdir', '-m', commit_msg) - else: - self._svnwrite('mkdir') + # modifying methods (cache must be invalidated) + def mkdir(self, commit_msg="copied by py lib invocation"): + self._svnwrite('mkdir', '-m', commit_msg) + self._lsnorevcache.delentry(self.strpath) - def copy(self, target, msg='auto'): + def copy(self, target, msg='copied by py lib invocation'): if getattr(target, 'rev', None) is not None: raise path.Invalid("target can't have a revision: %r" % target) process.cmdexec("svn copy -m %r %s %s" %(msg, str(self), str(target))) + self._lsnorevcache.delentry(target.dirpath().strpath) - def remove(self, rec=1, msg='auto'): + def remove(self, rec=1, msg='removed by py lib invocation'): if self.rev is not None: raise path.Invalid("cannot remove revisioned object: %r" % self) process.cmdexec("svn rm -m %r %s" %(msg, str(self))) + self._lsnorevcache.delentry(self.dirpath().strpath) + # end of modifying methods def _propget(self, name): res = self._svn('propget', name) return res[:-1] # strip trailing newline @@ -92,25 +98,30 @@ def _listdir_nameinfo(self): """ return sequence of name-info directory entries of self """ - try: - res = self._svn('ls', '-v') - except process.cmdexec.Error, e: - if e.err.find('non-existent in that revision') != -1: - raise error.FileNotFound(self, e.err) - elif e.err.find('not part of a repository')!=-1: - raise IOError, e.err - elif e.err.find('Unable to open')!=-1: - raise IOError, e.err - elif e.err.lower().find('method not allowed')!=-1: - raise IOError, e.err - raise - lines = res.split('\n') - nameinfo_seq = [] - for lsline in lines: - if lsline: - info = InfoSvnCommand(lsline) - nameinfo_seq.append((info._name, info)) - return nameinfo_seq + def builder(): + try: + res = self._svn('ls', '-v') + except process.cmdexec.Error, e: + if e.err.find('non-existent in that revision') != -1: + raise error.FileNotFound(self, e.err) + elif e.err.find('not part of a repository')!=-1: + raise IOError, e.err + elif e.err.find('Unable to open')!=-1: + raise IOError, e.err + elif e.err.lower().find('method not allowed')!=-1: + raise IOError, e.err + raise + lines = res.split('\n') + nameinfo_seq = [] + for lsline in lines: + if lsline: + info = InfoSvnCommand(lsline) + nameinfo_seq.append((info._name, info)) + return nameinfo_seq + if self.rev is not None: + return self._lsrevcache.getorbuild((self.strpath, self.rev), builder) + else: + return self._lsnorevcache.getorbuild(self.strpath, builder) def log(self, rev_start=None, rev_end=1, verbose=False): assert self.check() #make it simpler for the pipe From hpk at codespeak.net Sun Jan 2 12:45:55 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 2 Jan 2005 12:45:55 +0100 (MET) Subject: [py-svn] r8033 - py/dist/py/code Message-ID: <20050102114555.4DF615AA66@thoth.codespeak.net> Author: hpk Date: Sun Jan 2 12:45:54 2005 New Revision: 8033 Modified: py/dist/py/code/frame.py Log: revert bogus idea of returning None on a non-existing path. It's probably better to just let the exception pass through. Modified: py/dist/py/code/frame.py ============================================================================== --- py/dist/py/code/frame.py (original) +++ py/dist/py/code/frame.py Sun Jan 2 12:45:54 2005 @@ -16,10 +16,7 @@ try: return fn.__source__ except AttributeError: - try: - return py.code.Source(self.path.read(mode="rU")) - except py.path.NotFound: - return None + return py.code.Source(self.path.read(mode="rU")) fullsource = property(fullsource, None, None, "full source containing this code object") From hpk at codespeak.net Mon Jan 3 00:36:34 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 00:36:34 +0100 (MET) Subject: [py-svn] r8039 - in py/dist/py: . magic misc path path/extpy path/local path/svn path/test test Message-ID: <20050102233634.666C35A6DA@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 00:36:33 2005 New Revision: 8039 Added: py/dist/py/misc/error.py py/dist/py/misc/test_error.py Removed: py/dist/py/path/error.py Modified: py/dist/py/__init__.py py/dist/py/magic/assertion.py py/dist/py/misc/test_api.py py/dist/py/misc/test_initpkg.py py/dist/py/path/common.py py/dist/py/path/extpy/extpy.py py/dist/py/path/extpy/test_extpy.py py/dist/py/path/local/api.py py/dist/py/path/local/local.py py/dist/py/path/local/posix.py py/dist/py/path/local/test_local.py py/dist/py/path/svn/svncommon.py py/dist/py/path/svn/svntestbase.py py/dist/py/path/svn/test_wccommand.py py/dist/py/path/svn/urlcommand.py py/dist/py/path/svn/wccommand.py py/dist/py/path/test/common.py py/dist/py/path/test/fscommon.py py/dist/py/test/run.py py/dist/py/test/test_collect.py Log: Major refactoring towards an easier, more informative and more predicatable error handling. Now path implementations usually raise py.error.* exceptions which directly map POSIX errors and show an explanation of the error type as well as the invocation that caused the error. This together gives a much better and cleaner clue for what is going on and allows to handle specific problems easily. If we want we can later on add more readable error-class names in a backward compatible way. Examples: >>> py.path.local('/tmp').mkdir() ------------------------------------------------------------ Traceback (most recent call last): File "", line 1, in ? File "/home/hpk/projects/py/dist/py/path/local/local.py", line 253, in mkdir self._callex(os.mkdir, str(p)) File "/home/hpk/projects/py/dist/py/path/common.py", line 181, in _callex return func(*args) EEXIST: [File exists]: mkdir('/tmp',) >>> py.path.local('/tmp').chown('hpk','hpk') ------------------------------------------------------------ Traceback (most recent call last): File "", line 1, in ? File "/home/hpk/projects/py/dist/py/path/local/posix.py", line 56, in chown self._callex(os.chown, str(self), uid, gid) File "/home/hpk/projects/py/dist/py/path/common.py", line 181, in _callex return func(*args) EPERM: [Operation not permitted]: chown('/tmp', 500, 500) which reminds me that finally integrating doctests would be nice :-) Modified: py/dist/py/__init__.py ============================================================================== --- py/dist/py/__init__.py (original) +++ py/dist/py/__init__.py Mon Jan 3 00:36:33 2005 @@ -6,12 +6,12 @@ 'test.exit' : ('./test/drive.py', 'exit'), 'test.config' : ('./test/config.py', 'config'), 'test.compat.TestCase' : ('./test/compat.py', 'TestCase'), + 'test.collect.Directory' : ('./test/collect.py', 'Directory'), 'test.collect.PyCollector': ('./test/collect.py', 'PyCollector'), 'test.collect.Module' : ('./test/collect.py', 'Module'), + 'test.collect.Class' : ('./test/collect.py', 'Class'), 'test.collect.Error' : ('./test/collect.py', 'Error'), - 'test.collect.Directory' : ('./test/collect.py', 'Directory'), 'test.collect.Collector' : ('./test/collect.py', 'Collector'), - 'test.collect.Class' : ('./test/collect.py', 'Class'), 'test.TextReporter' : ('./test/report/text/reporter.py', 'TextReporter'), 'test.Option' : ('./test/tool/optparse.py', 'Option'), @@ -29,10 +29,6 @@ 'path.local' : ('./path/local/local.py', 'LocalPath'), 'path.extpy' : ('./path/extpy/extpy.py', 'Extpy'), 'path.checker' : ('./path/common.py', 'checker'), - 'path.NotFound' : ('./path/error.py', 'FileNotFound'), - 'path.NoDirectory' : ('./path/error.py', 'NoDirectory'), - 'path.Invalid' : ('./path/error.py', 'Invalid'), - 'path.Denied' : ('./path/error.py', 'PermissionDenied'), 'magic.invoke' : ('./magic/invoke.py', 'invoke'), 'magic.revoke' : ('./magic/invoke.py', 'revoke'), @@ -55,4 +51,6 @@ 'execnet.SocketGateway' : ('./execnet/register.py', 'SocketGateway'), 'execnet.PopenGateway' : ('./execnet/register.py', 'PopenGateway'), 'execnet.SshGateway' : ('./execnet/register.py', 'SshGateway'), + + 'error' : ('./misc/error.py', 'error'), }) Modified: py/dist/py/magic/assertion.py ============================================================================== --- py/dist/py/magic/assertion.py (original) +++ py/dist/py/magic/assertion.py Mon Jan 3 00:36:33 2005 @@ -11,7 +11,7 @@ try: source = py.code.Frame(f).statement source = str(source).strip() - except py.path.NotFound: + except py.error.ENOENT: source = None # this can also occur during reinterpretation, when the # co_filename is set to "". Added: py/dist/py/misc/error.py ============================================================================== --- (empty file) +++ py/dist/py/misc/error.py Mon Jan 3 00:36:33 2005 @@ -0,0 +1,62 @@ + +import py + +class Error(EnvironmentError): + __module__ = 'py.error' + + def __repr__(self): + return "%s.%s %r: %s " %(self.__class__.__module__, + self.__class__.__name__, + self.__class__.__doc__, + " ".join(map(str, self.args)), + #repr(self.args) + ) + + def __str__(self): + return "[%s]: %s" %(self.__class__.__doc__, + " ".join(map(str, self.args)), + ) + +ModuleType = type(py) + +class py_error(ModuleType): + """ py.error contains higher level Exception classes + for each possible POSIX errno (as defined per + the 'errno' module. All such Exceptions derive + from py.error.Error, which itself is a subclass + of EnvironmentError. + """ + Error = Error + + def _geterrnoclass(eno, _errno2class = {}): + try: + return _errno2class[eno] + except KeyError: + clsname = py.std.errno.errorcode[eno] + cls = py.std.new.classobj(clsname, (Error,), + {'__module__':'py.error', + '__doc__': py.std.os.strerror(eno)}) + _errno2class[eno] = cls + return cls + _geterrnoclass = staticmethod(_geterrnoclass) + + def __getattr__(self, name): + eno = getattr(py.std.errno, name) + cls = self._geterrnoclass(eno) + setattr(self, name, cls) + return cls + + def getdict(self, done=[]): + try: + return done[0] + except IndexError: + for name in py.std.errno.errorcode.values(): + hasattr(self, name) # force attribute to be loaded, ignore errors + dictdescr = ModuleType.__dict__['__dict__'] + done.append(dictdescr.__get__(self)) + return done[0] + + __dict__ = property(getdict) + del getdict + +error = py_error('py.error', py_error.__doc__) Modified: py/dist/py/misc/test_api.py ============================================================================== --- py/dist/py/misc/test_api.py (original) +++ py/dist/py/misc/test_api.py Mon Jan 3 00:36:33 2005 @@ -12,8 +12,6 @@ assert_class('py.path', 'svnurl') assert_class('py.path', 'extpy') assert_class('py.path', 'checker') - assert_class('py.path', 'NotFound') - assert_class('py.path', 'Denied') def test_magic_entrypoints(self): assert_class('py.magic', 'View') Added: py/dist/py/misc/test_error.py ============================================================================== --- (empty file) +++ py/dist/py/misc/test_error.py Mon Jan 3 00:36:33 2005 @@ -0,0 +1,10 @@ + +import py + +import errno + +def test_error_classes(): + for name in errno.errorcode.values(): + x = getattr(py.error, name) + assert issubclass(x, py.error.Error) + assert issubclass(x, EnvironmentError) Modified: py/dist/py/misc/test_initpkg.py ============================================================================== --- py/dist/py/misc/test_initpkg.py (original) +++ py/dist/py/misc/test_initpkg.py Mon Jan 3 00:36:33 2005 @@ -2,10 +2,11 @@ import types def test_dir(): + from py.__impl__.initpkg import Module for name in dir(py): if not name.startswith('_'): obj = getattr(py, name) - if isinstance(obj, types.ModuleType): + if hasattr(obj, '__map__'): # isinstance(obj, Module): keys = dir(obj) assert len(keys) > 0 assert getattr(obj, '__map__') == {} @@ -52,7 +53,7 @@ d = py.__package__.getrev() try: svnversion = py.path.local.sysfind('svnversion') - except py.path.NotFound: + except py.error.ENOENT: py.test.skip("cannot test svnversion, 'svnversion' binary not found") v = svnversion.sysexec(py.path.local(py.__file__).dirpath()) assert v.startswith(str(d)) Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Mon Jan 3 00:36:33 2005 @@ -68,7 +68,7 @@ else: if bool(value) ^ bool(meth()) ^ invert: return False - except (py.path.NotFound, py.path.NoDirectory): + except (py.error.ENOENT, py.error.ENOTDIR): for name in self._depend_on_existence: if name in kw: if kw.get(name): @@ -82,7 +82,6 @@ class PathBase(object): """ shared implementation for filesystem path objects.""" Checkers = Checkers - from py.path import NotFound def check(self, **kw): if kw: @@ -152,10 +151,6 @@ def __repr__(self): return repr(str(self)) - def _except(self, excinfo): - """ default exception handling is to reraise it. """ - raise excinfo[0], excinfo[1], excinfo[2] - def visit(self, fil=None, rec=None, ignore=None): if isinstance(fil, str): fil = fnmatch(fil) @@ -180,6 +175,20 @@ for i in p.visit(fil, rec, ignore=ignore): yield i + def _callex(self, func, *args): + """ call a function and raise errno-exception if applicable. """ + try: + return func(*args) + except (py.error.Error, KeyboardInterrupt, SystemExit): + raise + except EnvironmentError, e: + if not hasattr(e, 'errno'): + raise + cls, value, tb = sys.exc_info() + cls = py.error._geterrnoclass(e.errno) + value = cls("%s%r" % (func.__name__, args)) + raise cls, value, tb + class fnmatch: def __init__(self, pattern): self.pattern = pattern @@ -228,7 +237,6 @@ class FSPathBase(PathBase): """ shared implementation for filesystem path objects.""" Checkers = FSCheckers - from py.path import NotFound def __div__(self, other): return self.join(str(other)) @@ -261,10 +269,10 @@ def readlines(self, cr=1): if not cr: - content = self.read() + content = self.read('rU') return content.split('\n') else: - f = self.open('r') + f = self.open('rU') try: return f.readlines() finally: @@ -308,7 +316,7 @@ return mod def getpycodeobj(self): - s = self.read() + s = self.read('rU') # XXX str(self) should show up somewhere in the code's filename return py.code.compile(s) Deleted: /py/dist/py/path/error.py ============================================================================== --- /py/dist/py/path/error.py Mon Jan 3 00:36:33 2005 +++ (empty file) @@ -1,82 +0,0 @@ -""" -Error module -""" - -import py - -class Error(Exception): - def __init__(self, *args): - self.args = args - -class Invalid(Error): - pass - -class FileNotFound(Invalid): - pass -class FileExists(Invalid): - pass -class NoSpace(Invalid): - pass -class IsDirectory(Invalid): - pass -class NoDirectory(Invalid): - pass -class PermissionDenied(Invalid): - pass -class NestedLink(Invalid): - pass -class NotPermitted(Invalid): - pass - - -#__________________________________________________________ -# XXX use module errno -_errnoclass = {} -for errno, name in { - 1 : 'NotPermitted', - 2 : 'FileNotFound', - 3 : 'FileExists', - 13 : 'PermissionDenied', - 17 : 'FileExists', - 20 : 'NoDirectory', - 21 : 'IsDirectory', - 28 : 'NoSpace', - 40 : 'NestedLink', - }.items(): - - exec """ -class %(name)s(%(name)s): - pass -""" % locals() - _errnoclass[errno] = eval(name) - -def error_enhance((cls, error, tb)): - assert cls is not None - if isinstance(error, (Error, KeyboardInterrupt, SystemExit, - MemoryError)) or not hasattr(error, 'errno'): - raise cls, error, tb - #assert isinstance(error, IOError) - ncls = _errnoclass.get(error.errno) - if not ncls: - raise cls, error, tb - ncls = enhanceclass(error.__class__, ncls) - newerror = ncls() - newerror.__dict__.update(error.__dict__) - raise ncls, newerror, tb # XXX traceback shows wrong data? - -def enhanceclass(baseclass, newclass, cache={}): - if issubclass(newclass, baseclass): - return newclass - else: - try: - return cache[baseclass, newclass] - except KeyError: - import new - Mixed = py.std.new.classobj( - newclass.__name__, - (newclass, baseclass), - {}) - - cache[baseclass, newclass] = Mixed - return Mixed - Modified: py/dist/py/path/extpy/extpy.py ============================================================================== --- py/dist/py/path/extpy/extpy.py (original) +++ py/dist/py/path/extpy/extpy.py Mon Jan 3 00:36:33 2005 @@ -83,7 +83,7 @@ try: target = getattr(target, name) except AttributeError: - raise py.path.NotFound("%r in %s" %(self.modpath, self)) + raise py.error.ENOENT(target, name) return target def getpymodule(self): Modified: py/dist/py/path/extpy/test_extpy.py ============================================================================== --- py/dist/py/path/extpy/test_extpy.py (original) +++ py/dist/py/path/extpy/test_extpy.py Mon Jan 3 00:36:33 2005 @@ -164,20 +164,20 @@ def test_invalid1(self): p = path.py('os.path.qwe("a", "b")') - s = test.raises(path.NotFound, "p.resolve()") + s = test.raises(py.error.ENOENT, "p.resolve()") def test_syntaxerror(self): p = path.py('os.path.qwe("a", ') s = test.raises(ValueError, "p.resolve()") class TestErrors: - def test_FileNotFound(self): + def test_ENOENT(self): p = py.path.extpy(mypath, 'somesuch') - py.test.raises(py.path.NotFound, p.resolve) + py.test.raises(py.error.ENOENT, p.resolve) - def test_FileNotFound_really(self): + def test_ENOENT_really(self): p = py.path.extpy(mypath.new(basename='notexist'), 'somesuch') - py.test.raises(py.path.NotFound, p.resolve) + py.test.raises(py.error.ENOENT, p.resolve) #def test_ImportError(): # p = path.py('__std.utest.test.data.failingimport.someattr') Modified: py/dist/py/path/local/api.py ============================================================================== --- py/dist/py/path/local/api.py (original) +++ py/dist/py/path/local/api.py Mon Jan 3 00:36:33 2005 @@ -25,7 +25,7 @@ except path.FileExists: continue return dpath - raise NotFound, "could not create tempdir, %d tries" % tries + raise py.error.EAGAIN("could not create tempdir, %d tries" % tries) def make_numbered_dir(rootdir=None, base = 'session-', keep=3): """ return unique directory with a number greater than the current Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Mon Jan 3 00:36:33 2005 @@ -7,7 +7,6 @@ """ import sys, os, stat import py -from py.__impl__.path import error from py.__impl__.path import common if sys.platform == 'win32': @@ -27,7 +26,7 @@ except AttributeError: try: self._statcache = self.path.stat() - except error.NestedLink: + except py.error.ELOOP: self._statcache = self.path.lstat() return self._statcache @@ -170,7 +169,7 @@ def open(self, mode='r'): """ return an opened file with the given mode. """ - return callex(open, self.strpath, mode) + return self._callex(open, self.strpath, mode) def listdir(self, fil=None, sort=None): """ list directory contents, possibly filter by the given fil func @@ -179,7 +178,7 @@ if isinstance(fil, str): fil = common.fnmatch(fil) res = [] - for name in callex(os.listdir, self.strpath): + for name in self._callex(os.listdir, self.strpath): childurl = self.join(name) if fil is None or fil(childurl): res.append(childurl) @@ -210,11 +209,11 @@ """ remove a file or directory (or a directory tree if rec=1). """ if self.check(dir=1, link=0): if rec: - callex(py.std.shutil.rmtree, self.strpath) + self._callex(py.std.shutil.rmtree, self.strpath) else: - callex(os.rmdir, self.strpath) + self._callex(os.rmdir, self.strpath) else: - callex(os.remove, self.strpath) + self._callex(os.remove, self.strpath) def copy(self, target, archive=False): assert not archive, "XXX archive-mode not supported" @@ -238,20 +237,20 @@ newx.ensure(dir=1) def rename(self, target): - return callex(os.rename, str(self), str(target)) + return self._callex(os.rename, str(self), str(target)) def dumpobj(self, obj): """ pickle object into path location""" f = self.open('wb') try: - callex(py.std.cPickle.dump, obj, f) + self._callex(py.std.cPickle.dump, obj, f) finally: f.close() def mkdir(self, *args): """ create & return the directory joined with args. """ p = self.join(*args) - callex(os.mkdir, str(p)) + self._callex(os.mkdir, str(p)) return p def write(self, content): @@ -288,11 +287,11 @@ def stat(self): """ Return an os.stat() tuple. """ - return callex(os.stat, self.strpath) + return self._callex(os.stat, self.strpath) def lstat(self): """ Return an os.lstat() tuple. """ - return callex(os.lstat, self.strpath) + return self._callex(os.lstat, self.strpath) # xlocal implementation def setmtime(self, mtime=None): @@ -302,19 +301,19 @@ Note that the resolution for 'mtime' is platform dependent. """ if mtime is None: - return callex(os.utime, self.strpath, mtime) + return self._callex(os.utime, self.strpath, mtime) try: return os.utime(self.strpath, (-1, mtime)) except OSError, e: if e.errno != 22: error.error_enhance(sys.exc_info()) raise - return callex(os.utime, self.strpath, (self.atime(), mtime)) + return self._callex(os.utime, self.strpath, (self.atime(), mtime)) def chdir(self): """ change directory to self and return old current directory """ old = self.__class__() - callex(os.chdir, self.strpath) + self._callex(os.chdir, self.strpath) return old def realpath(self): @@ -357,7 +356,7 @@ return py.std.marshal.load(f) finally: f.close() - except IOError: + except py.error.Error: pass s = self.read(mode='rU') + '\n' codeobj = compile(s, str(self), 'exec') @@ -394,8 +393,10 @@ def sysfind(self, name, checker=None): """ return a path object found by looking at the systems underlying PATH specification. If the checker is not None - it will be invoked to filter matching paths. - Note: This is probably not working on plain win32 systems yet. + it will be invoked to filter matching paths. If a binary + cannot be found, py.error.ENOENT is raised. + Note: This is probably not working on plain win32 systems + but may work on cygwin. """ for x in py.std.os.environ['PATH'].split(':'): p = py.path.local(x).join(name) @@ -404,7 +405,7 @@ if not checker(p): continue return p - raise py.path.NotFound(self) + raise py.error.ENOENT(self) sysfind = classmethod(sysfind) #""" #special class constructors for local filesystem paths @@ -434,7 +435,7 @@ except path.FileExists: continue return dpath - raise NotFound, "could not create tempdir, %d tries" % tries + raise py.error.ENOENT("could not create tempdir, %d tries" % tries) mkdtemp = classmethod(mkdtemp) def make_numbered_dir(cls, rootdir=None, base = 'session-', keep=3): @@ -493,7 +494,7 @@ #parentdirmatch = classmethod(parentdirmatch) def copychunked(src, dest): - chunksize = 524288 # bytes + chunksize = 524288 # half a meg of bytes fsrc = src.open('rb') try: fdest = dest.open('wb') @@ -508,14 +509,6 @@ finally: fsrc.close() -def callex(func, *args, **kwargs): - try: - return func(*args, **kwargs) - except (KeyboardInterrupt, SystemExit): - raise - except: - error.error_enhance(sys.exc_info() ) - def make_module_from_c(cfile): from distutils.core import setup from distutils.extension import Extension Modified: py/dist/py/path/local/posix.py ============================================================================== --- py/dist/py/path/local/posix.py (original) +++ py/dist/py/path/local/posix.py Mon Jan 3 00:36:33 2005 @@ -14,19 +14,15 @@ # an instance needs to be a local path instance def owner(self): """ return owner name of file. """ - try: - from pwd import getpwuid - return getpwuid(self.stat().st_uid)[0] - except: - self._except(sys.exc_info()) + uid = self.stat().st_uid + entry = self._callex(py.std.pwd.getpwuid, uid) + return entry[0] def group(self): """ return group name of file. """ - try: - from grp import getgrgid - return getgrgid(self.stat().st_gid)[0] - except: - self._except(sys.exc_info()) + gid = self.stat().st_gid + entry = self._callex(py.std.grp.getgrgid, gid) + return entry[0] def mode(self): """ return permission mode of the path object """ @@ -39,15 +35,12 @@ in '/bin/chmod' style, e.g. a+r). if rec is True perform recursively. """ - try: - if not isinstance(mode, int): - raise NotImplementedError - if rec: - for x in self.visit(): - os.chmod(str(x), mode) - os.chmod(str(self), mode) - except: - self._except(sys.exc_info()) + if not isinstance(mode, int): + raise TypeError("mode %r must be an integer" % (mode,)) + if rec: + for x in self.visit(): + self._callex(os.chmod, str(x), mode) + self._callex(os.chmod, str(self), mode) def chown(self, user, group, rec=0): """ change ownership to the given user and group. @@ -57,44 +50,31 @@ """ uid = getuserid(user) gid = getgroupid(group) - try: - if rec: - for x in self.visit(rec=py.path.checker(link=0)): - os.chown(str(x), uid, gid) - os.chown(str(self), uid, gid) - except: - self._except(sys.exc_info()) + if rec: + for x in self.visit(rec=py.path.checker(link=0)): + self._callex(os.chown, str(x), uid, gid) + self._callex(os.chown, str(self), uid, gid) def readlink(self): """ return value of a symbolic link. """ - try: - return os.readlink(self.strpath) - except: - self._except(sys.exc_info()) + return self._callex(os.readlink, self.strpath) def mklinkto(self, oldname): """ posix style hard link to another name. """ - try: - os.link(str(oldname), str(self)) - except: - self._except(sys.exc_info()) + self._callex(os.link, str(oldname), str(self)) def mksymlinkto(self, value, absolute=1): """ create a symbolic link with the given value (pointing to another name). """ - try: - if absolute: - os.symlink(str(value), self.strpath) - else: - base = self.common(value) - # with posix local paths '/' is always a common base - relsource = self.__class__(value).relto(base) - reldest = self.relto(base) - n = reldest.count(self.sep) - target = self.sep.join(('..', )*n + (relsource, )) - os.symlink(target, self.strpath) - except: - self._except(sys.exc_info()) - + if absolute: + self._callex(os.symlink, str(value), self.strpath) + else: + base = self.common(value) + # with posix local paths '/' is always a common base + relsource = self.__class__(value).relto(base) + reldest = self.relto(base) + n = reldest.count(self.sep) + target = self.sep.join(('..', )*n + (relsource, )) + self._callex(os.symlink, target, self.strpath) def getuserid(user): import pwd Modified: py/dist/py/path/local/test_local.py ============================================================================== --- py/dist/py/path/local/test_local.py (original) +++ py/dist/py/path/local/test_local.py Mon Jan 3 00:36:33 2005 @@ -96,16 +96,6 @@ finally: d.remove(rec=1) - def test_mkdir(self): - tmpdir = self.tmpdir - new = tmpdir.join('test1') - new.mkdir() - assert new.check(dir=1) - - new = tmpdir.mkdir('test2') - assert new.check(dir=1) - assert tmpdir.join('test2') == new - def test_chdir(self): tmpdir = self.tmpdir.realpath() old = local() @@ -142,7 +132,7 @@ def test_sysfind(self): x = py.path.local.sysfind('test') assert x.check(file=1) - py.test.raises(py.path.NotFound, """ + py.test.raises(py.error.ENOENT, """ py.path.local.sysfind('jaksdkasldqwe') """) @@ -159,7 +149,7 @@ assert x.basename == 'a' assert x.dirpath().basename == 'b' checker = lambda x: None - py.test.raises(py.path.NotFound, """ + py.test.raises(py.error.ENOENT, """ py.path.local.sysfind('a', checker=checker) """) finally: @@ -192,8 +182,8 @@ assert not numdir.new(ext=str(i-3)).check() def test_error_preservation(self): - py.test.raises (OSError, self.root.join('qwoeqiwe').mtime) - py.test.raises (IOError, self.root.join('qwoeqiwe').read) + py.test.raises (EnvironmentError, self.root.join('qwoeqiwe').mtime) + py.test.raises (EnvironmentError, self.root.join('qwoeqiwe').read) #def test_parentdirmatch(self): # local.parentdirmatch('std', startmodule=__name__) Modified: py/dist/py/path/svn/svncommon.py ============================================================================== --- py/dist/py/path/svn/svncommon.py (original) +++ py/dist/py/path/svn/svncommon.py Mon Jan 3 00:36:33 2005 @@ -2,8 +2,8 @@ module with a base subversion path object. """ import os, sys, time, re +import py from py import path, process -from py.__impl__.path import error from py.__impl__.path import common #_______________________________________________________________ @@ -151,7 +151,7 @@ for name, info in nameinfo_seq: if name == bn: return info - raise error.FileNotFound(self) + raise py.error.ENOENT(self) def size(self): """ Return the size of the file content of the Path. """ @@ -219,7 +219,7 @@ def _listdirworks(self): try: self.path.listdir() - except error.FileNotFound: + except py.error.ENOENT: return False else: return True @@ -227,13 +227,13 @@ def file(self): try: return self.path.info().kind == 'file' - except (IOError, error.FileNotFound): - return False + except py.error.ENOENT: + return False def exists(self): try: return self.path.info() - except IOError: + except py.error.ENOENT: return self._listdirworks() def parse_apr_time(timestr): Modified: py/dist/py/path/svn/svntestbase.py ============================================================================== --- py/dist/py/path/svn/svntestbase.py (original) +++ py/dist/py/path/svn/svntestbase.py Mon Jan 3 00:36:33 2005 @@ -54,7 +54,7 @@ #def test_nonexisting_listdir_rev(self): # url = self.root.__class__(self.rooturl, rev=500) - # raises(error.FileNotFound, url.listdir) + # raises(py.error.ENOENT, url.listdir) #def test_newrev(self): # url = self.root.new(rev=None) Modified: py/dist/py/path/svn/test_wccommand.py ============================================================================== --- py/dist/py/path/svn/test_wccommand.py (original) +++ py/dist/py/path/svn/test_wccommand.py Mon Jan 3 00:36:33 2005 @@ -108,7 +108,7 @@ r.update(rev=1) s = r.status(updates=1, rec=1) assert r.join('anotherfile') in s.update_available - assert len(s.update_available) == 1 + #assert len(s.update_available) == 1 finally: r.update() Modified: py/dist/py/path/svn/urlcommand.py ============================================================================== --- py/dist/py/path/svn/urlcommand.py (original) +++ py/dist/py/path/svn/urlcommand.py Mon Jan 3 00:36:33 2005 @@ -6,9 +6,9 @@ """ import os, sys, time, re +import py from py import path, process from py.__impl__.path import common -from py.__impl__.path import error from py.__impl__.path.svn import svncommon from py.__impl__.misc.cache import BuildcostAccessCache, AgingCache @@ -68,10 +68,14 @@ return popen(svncommon.fixlocale() + 'svn cat -r %s "%s"' % (self.rev, self.strpath)) + # modifying methods (cache must be invalidated) - def mkdir(self, commit_msg="copied by py lib invocation"): - self._svnwrite('mkdir', '-m', commit_msg) - self._lsnorevcache.delentry(self.strpath) + def mkdir(self, *args, **kwargs): + commit_msg=kwargs.get('msg', "mkdir by py lib invocation") + createpath = self.join(*args) + createpath._svnwrite('mkdir', '-m', commit_msg) + self._lsnorevcache.delentry(createpath.dirpath().strpath) + return createpath def copy(self, target, msg='copied by py lib invocation'): if getattr(target, 'rev', None) is not None: @@ -103,14 +107,14 @@ res = self._svn('ls', '-v') except process.cmdexec.Error, e: if e.err.find('non-existent in that revision') != -1: - raise error.FileNotFound(self, e.err) + raise py.error.ENOENT(self, e.err) elif e.err.find('not part of a repository')!=-1: - raise IOError, e.err + raise py.error.ENOENT(self, e.err) elif e.err.find('Unable to open')!=-1: - raise IOError, e.err + raise py.error.ENOENT(self, e.err) elif e.err.lower().find('method not allowed')!=-1: - raise IOError, e.err - raise + raise py.error.EACCES(self, e.err) + raise py.error.Error(e.err) lines = res.split('\n') nameinfo_seq = [] for lsline in lines: Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Mon Jan 3 00:36:33 2005 @@ -303,10 +303,10 @@ output = self._svn('info') except py.process.cmdexec.Error, e: if e.err.find('Path is not a working copy directory') != -1: - raise path.NotFound, e.err + raise py.error.ENOENT(self, e.err) raise if output.find('Not a versioned resource') != -1: - raise path.NotFound, output + raise py.error.ENOENT(self, output) info = InfoSvnWCCommand(path.local(self.strpath), output) cache.info[self] = info self.rev = info.rev Modified: py/dist/py/path/test/common.py ============================================================================== --- py/dist/py/path/test/common.py (original) +++ py/dist/py/path/test/common.py Mon Jan 3 00:36:33 2005 @@ -1,4 +1,4 @@ -from py.path import checker, NotFound +from py.path import checker import py class CommonPathTests: @@ -168,7 +168,7 @@ def test_visit_ignore(self): p = self.root.join('nonexisting') - assert list(p.visit(ignore=NotFound)) == [] + assert list(p.visit(ignore=py.error.ENOENT)) == [] def test_visit_endswith(self): l = [] Modified: py/dist/py/path/test/fscommon.py ============================================================================== --- py/dist/py/path/test/fscommon.py (original) +++ py/dist/py/path/test/fscommon.py Mon Jan 3 00:36:33 2005 @@ -183,6 +183,18 @@ p.remove() assert not p.check() + def test_mkdir_and_remove(self): + tmpdir = self.root + new = tmpdir.join('mktest1') + new.mkdir() + assert new.check(dir=1) + new.remove() + + new = tmpdir.mkdir('mktest2') + assert new.check(dir=1) + new.remove() + assert tmpdir.join('mktest2') == new + def test_move_file(self): p = self.root.ensure('tomove') newp = p.new(basename='moved') Modified: py/dist/py/test/run.py ============================================================================== --- py/dist/py/test/run.py (original) +++ py/dist/py/test/run.py Mon Jan 3 00:36:33 2005 @@ -14,7 +14,7 @@ oldstat = statcache.get(path, None) try: statcache[path] = curstat = path.stat() - except path.NotFound: + except py.error.ENOENT: if oldstat: del statcache[path] print "# WARN: race condition on", path Modified: py/dist/py/test/test_collect.py ============================================================================== --- py/dist/py/test/test_collect.py (original) +++ py/dist/py/test/test_collect.py Mon Jan 3 00:36:33 2005 @@ -31,7 +31,7 @@ l = list(collect.Module(fn)) assert len(l) == 1 assert isinstance(l[0], collect.Error) - assert isinstance(l[0].excinfo.value, py.path.NotFound) + assert isinstance(l[0].excinfo.value, py.error.ENOENT) def test_syntax_error_in_module(): modpath = py.path.extpy(datadir.join('syntax_error.py')) From hpk at codespeak.net Mon Jan 3 01:21:52 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 01:21:52 +0100 (MET) Subject: [py-svn] r8042 - in py/dist/py: path/local path/svn process test Message-ID: <20050103002152.6BD085A1E0@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 01:21:51 2005 New Revision: 8042 Modified: py/dist/py/path/local/local.py py/dist/py/path/svn/svncommon.py py/dist/py/process/cmdexec.py py/dist/py/test/collect.py py/dist/py/test/run.py Log: some error handling fixes (while we are at it) Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Mon Jan 3 01:21:51 2005 @@ -369,7 +369,7 @@ f.seek(0) f.write(py.std.struct.pack('<4si', my_magic, my_timestamp)) f.close() - except IOError: + except py.error.Error: pass return codeobj Modified: py/dist/py/path/svn/svncommon.py ============================================================================== --- py/dist/py/path/svn/svncommon.py (original) +++ py/dist/py/path/svn/svncommon.py Mon Jan 3 01:21:51 2005 @@ -213,7 +213,7 @@ def dir(self): try: return self.path.info().kind == 'dir' - except IOError: + except py.error.Error: return self._listdirworks() def _listdirworks(self): Modified: py/dist/py/process/cmdexec.py ============================================================================== --- py/dist/py/process/cmdexec.py (original) +++ py/dist/py/process/cmdexec.py Mon Jan 3 01:21:51 2005 @@ -11,6 +11,7 @@ """ import os, sys +import py #----------------------------------------------------------- # posix external command execution @@ -89,7 +90,7 @@ return out -class ExecutionFailed(Exception): +class ExecutionFailed(py.error.Error): def __init__(self, status, systemstatus, cmd, out, err): Exception.__init__(self) self.status = status Modified: py/dist/py/test/collect.py ============================================================================== --- py/dist/py/test/collect.py (original) +++ py/dist/py/test/collect.py Mon Jan 3 01:21:51 2005 @@ -10,7 +10,7 @@ elif fspath.check(dir=1): col = py.test.config.getconfigvalue(fspath, 'Directory') else: - raise IOError, "%r does not exist" % fspath + raise py.error.ENOENT(fspath) return col(fspath) def configproperty(name): Modified: py/dist/py/test/run.py ============================================================================== --- py/dist/py/test/run.py (original) +++ py/dist/py/test/run.py Mon Jan 3 01:21:51 2005 @@ -64,7 +64,7 @@ while 1: try: channel.waitclose(0.1) - except IOError: + except py.error.Error: continue else: failures = channel.receive() From hpk at codespeak.net Mon Jan 3 01:44:23 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 01:44:23 +0100 (MET) Subject: [py-svn] r8044 - in py/dist/py: . test/report/text Message-ID: <20050103004423.DFEA65AA11@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 01:44:23 2005 New Revision: 8044 Modified: py/dist/py/initpkg.py py/dist/py/test/report/text/reporter.py Log: small fixes Modified: py/dist/py/initpkg.py ============================================================================== --- py/dist/py/initpkg.py (original) +++ py/dist/py/initpkg.py Mon Jan 3 01:44:23 2005 @@ -63,7 +63,10 @@ assert fspath.startswith('./'), \ "%r is not an implementation path (XXX)" % extpyish implmodule = self._loadimpl(fspath[:-3]) - return getattr(implmodule, modpath) + current = implmodule + for x in modpath.split('.'): + current = getattr(current, x) + return current def _loadimpl(self, relfile): """ load implementation for the given relfile. """ @@ -154,7 +157,7 @@ if hasattr(result, '__module__'): try: setattr(result, '__module__', self.__name__) - except TypeError: + except (AttributeError, TypeError): pass if hasattr(result, '__bases__'): try: Modified: py/dist/py/test/report/text/reporter.py ============================================================================== --- py/dist/py/test/report/text/reporter.py (original) +++ py/dist/py/test/report/text/reporter.py Mon Jan 3 01:44:23 2005 @@ -161,9 +161,9 @@ import pdb self.out.rewrite( '\n%s: %s\n' - % (result.excinfo[1].__class__.__name__, - result.excinfo[1])) - pdb.post_mortem(result.excinfo[2]) + % (result.excinfo.type.__name__, + result.excinfo.value)) + pdb.post_mortem(result.excinfo._excinfo[2]) def report_collect_error(self, error): restype, c = self.processresult(error) From hpk at codespeak.net Mon Jan 3 12:33:53 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 12:33:53 +0100 (MET) Subject: [py-svn] r8047 - in py/dist/py/path: svn test Message-ID: <20050103113353.6D6155AA52@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 12:33:52 2005 New Revision: 8047 Modified: py/dist/py/path/svn/test_urlcommand.py py/dist/py/path/svn/test_wccommand.py py/dist/py/path/svn/urlcommand.py py/dist/py/path/svn/wccommand.py py/dist/py/path/test/fscommon.py Log: a couple of small fixes and better error handling (uniform py.error.EEXIST for mkdir() and possibly others) Modified: py/dist/py/path/svn/test_urlcommand.py ============================================================================== --- py/dist/py/path/svn/test_urlcommand.py (original) +++ py/dist/py/path/svn/test_urlcommand.py Mon Jan 3 12:33:52 2005 @@ -1,7 +1,7 @@ import sys, os import py -from py.__impl__.path.svn.svntestbase import CommonCommandAndBindingTests -from py.__impl__.path.svn.test_wccommand import getrepowc +from svntestbase import CommonCommandAndBindingTests +from test_wccommand import getrepowc class TestSvnCommandPath(CommonCommandAndBindingTests): def __init__(self): Modified: py/dist/py/path/svn/test_wccommand.py ============================================================================== --- py/dist/py/path/svn/test_wccommand.py (original) +++ py/dist/py/path/svn/test_wccommand.py Mon Jan 3 12:33:52 2005 @@ -1,5 +1,5 @@ import py -from py.__impl__.path.svn.svntestbase import CommonSvnTests +from svntestbase import CommonSvnTests from py.__impl__.path.test.fscommon import setuptestfs # make a wc directory out of a given root url Modified: py/dist/py/path/svn/urlcommand.py ============================================================================== --- py/dist/py/path/svn/urlcommand.py (original) +++ py/dist/py/path/svn/urlcommand.py Mon Jan 3 12:33:52 2005 @@ -53,7 +53,12 @@ # fixing the locale because we can't otherwise parse string = svncommon.fixlocale() + " ".join(l) #print "execing", string - out = process.cmdexec(string) + try: + out = process.cmdexec(string) + except py.process.cmdexec.Error, e: + if e.err.find('File Exists'): + raise py.error.EEXIST(self) + raise return out def open(self, mode='r'): Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Mon Jan 3 12:33:52 2005 @@ -62,7 +62,12 @@ string = svncommon.fixlocale() + " ".join(l) if DEBUG: print "execing", string - out = py.process.cmdexec(string) + try: + out = py.process.cmdexec(string) + except py.process.cmdexec.Error, e: + if e.err.find('File Exists'): + raise py.error.EEXIST(self) + raise return out def checkout(self, url=None, rev = None): Modified: py/dist/py/path/test/fscommon.py ============================================================================== --- py/dist/py/path/test/fscommon.py (original) +++ py/dist/py/path/test/fscommon.py Mon Jan 3 12:33:52 2005 @@ -185,6 +185,7 @@ def test_mkdir_and_remove(self): tmpdir = self.root + py.test.raises(py.error.EEXIST, tmpdir.mkdir, 'sampledir') new = tmpdir.join('mktest1') new.mkdir() assert new.check(dir=1) From hpk at codespeak.net Mon Jan 3 13:14:28 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 13:14:28 +0100 (MET) Subject: [py-svn] r8048 - in py/dist/py: documentation documentation/example/test documentation/example/testing documentation/testing execnet execnet/test execnet/testing execnet/testing/test magic magic/testing misc misc/testing path/extpy path/extpy/test_data path/extpy/testing path/extpy/testing/test_data path/local path/local/popen5 path/local/popen5/testing path/local/testing path/svn path/svn/testing path/test process process/testing test test/report test/report/testing test/test test/testing test/testing/test test/tool test/tool/testing Message-ID: <20050103121428.A75C55AB03@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 13:14:26 2005 New Revision: 8048 Added: py/dist/py/documentation/example/testing/ - copied from r8046, py/dist/py/documentation/example/test/ py/dist/py/documentation/testing/ py/dist/py/documentation/testing/__init__.py py/dist/py/documentation/testing/rest_test.py - copied unchanged from r8046, py/dist/py/documentation/rest_test.py py/dist/py/execnet/testing/ py/dist/py/execnet/testing/__init__.py py/dist/py/execnet/testing/sshtesting.py - copied unchanged from r8046, py/dist/py/execnet/sshtesting.py py/dist/py/execnet/testing/test/ - copied from r8046, py/dist/py/execnet/test/ py/dist/py/execnet/testing/test_gateway.py - copied, changed from r8046, py/dist/py/execnet/test_gateway.py py/dist/py/magic/testing/ py/dist/py/magic/testing/__init__.py py/dist/py/magic/testing/test_assertion.py - copied unchanged from r8046, py/dist/py/magic/test_assertion.py py/dist/py/magic/testing/test_autopath.py - copied unchanged from r8046, py/dist/py/magic/test_autopath.py py/dist/py/magic/testing/test_exprinfo.py - copied unchanged from r8046, py/dist/py/magic/test_exprinfo.py py/dist/py/magic/testing/test_invoke.py - copied unchanged from r8046, py/dist/py/magic/test_invoke.py py/dist/py/magic/testing/test_patch.py - copied unchanged from r8046, py/dist/py/magic/test_patch.py py/dist/py/magic/testing/test_viewtype.py - copied unchanged from r8046, py/dist/py/magic/test_viewtype.py py/dist/py/misc/testing/ py/dist/py/misc/testing/__init__.py py/dist/py/misc/testing/test_api.py - copied unchanged from r8046, py/dist/py/misc/test_api.py py/dist/py/misc/testing/test_cache.py - copied, changed from r8046, py/dist/py/misc/test_cache.py py/dist/py/misc/testing/test_error.py - copied unchanged from r8046, py/dist/py/misc/test_error.py py/dist/py/misc/testing/test_initpkg.py - copied, changed from r8046, py/dist/py/misc/test_initpkg.py py/dist/py/misc/testing/test_std.py - copied unchanged from r8046, py/dist/py/misc/test_std.py py/dist/py/path/extpy/testing/ py/dist/py/path/extpy/testing/__init__.py py/dist/py/path/extpy/testing/inc_pseudofs.py - copied unchanged from r8046, py/dist/py/path/extpy/inc_pseudofs.py py/dist/py/path/extpy/testing/inc_test_extpy.py - copied unchanged from r8046, py/dist/py/path/extpy/inc_test_extpy.py py/dist/py/path/extpy/testing/test_data/ - copied from r8046, py/dist/py/path/extpy/test_data/ py/dist/py/path/extpy/testing/test_extpy.py - copied unchanged from r8046, py/dist/py/path/extpy/test_extpy.py py/dist/py/path/local/popen5/testing/ py/dist/py/path/local/popen5/testing/__init__.py py/dist/py/path/local/popen5/testing/test_subprocess.py - copied unchanged from r8046, py/dist/py/path/local/popen5/test_subprocess.py py/dist/py/path/local/testing/ py/dist/py/path/local/testing/__init__.py py/dist/py/path/local/testing/test_local.py - copied unchanged from r8046, py/dist/py/path/local/test_local.py py/dist/py/path/local/testing/test_posix.py - copied unchanged from r8046, py/dist/py/path/local/test_posix.py py/dist/py/path/svn/testing/ py/dist/py/path/svn/testing/__init__.py py/dist/py/path/svn/testing/svntestbase.py - copied unchanged from r8046, py/dist/py/path/svn/svntestbase.py py/dist/py/path/svn/testing/test_urlcommand.py - copied unchanged from r8047, py/dist/py/path/svn/test_urlcommand.py py/dist/py/path/svn/testing/test_wccommand.py - copied unchanged from r8047, py/dist/py/path/svn/test_wccommand.py py/dist/py/process/testing/ py/dist/py/process/testing/__init__.py py/dist/py/process/testing/test_cmdexec.py - copied unchanged from r8046, py/dist/py/process/test_cmdexec.py py/dist/py/test/report/testing/ py/dist/py/test/report/testing/__init__.py py/dist/py/test/report/testing/test_memo.py - copied unchanged from r8046, py/dist/py/test/report/test_memo.py py/dist/py/test/testing/ py/dist/py/test/testing/__init__.py py/dist/py/test/testing/test/ - copied from r8046, py/dist/py/test/test/ py/dist/py/test/testing/test_collect.py - copied unchanged from r8046, py/dist/py/test/test_collect.py py/dist/py/test/testing/test_compat.py - copied unchanged from r8046, py/dist/py/test/test_compat.py py/dist/py/test/testing/test_config.py - copied unchanged from r8046, py/dist/py/test/test_config.py py/dist/py/test/testing/test_raises.py - copied unchanged from r8046, py/dist/py/test/test_raises.py py/dist/py/test/tool/testing/ py/dist/py/test/tool/testing/__init__.py py/dist/py/test/tool/testing/test_outerrcapture.py - copied unchanged from r8046, py/dist/py/test/tool/test_outerrcapture.py Removed: py/dist/py/documentation/example/test/ py/dist/py/documentation/rest_test.py py/dist/py/execnet/sshtesting.py py/dist/py/execnet/test/ py/dist/py/execnet/test_gateway.py py/dist/py/magic/test_assertion.py py/dist/py/magic/test_autopath.py py/dist/py/magic/test_exprinfo.py py/dist/py/magic/test_invoke.py py/dist/py/magic/test_patch.py py/dist/py/magic/test_viewtype.py py/dist/py/misc/test_api.py py/dist/py/misc/test_cache.py py/dist/py/misc/test_error.py py/dist/py/misc/test_initpkg.py py/dist/py/misc/test_std.py py/dist/py/path/extpy/inc_pseudofs.py py/dist/py/path/extpy/inc_test_extpy.py py/dist/py/path/extpy/test_data/ py/dist/py/path/extpy/test_extpy.py py/dist/py/path/local/popen5/test_subprocess.py py/dist/py/path/local/test_local.py py/dist/py/path/local/test_posix.py py/dist/py/path/svn/svntestbase.py py/dist/py/path/svn/test_urlcommand.py py/dist/py/path/svn/test_wccommand.py py/dist/py/process/test_cmdexec.py py/dist/py/test/report/test_memo.py py/dist/py/test/test/ py/dist/py/test/test_collect.py py/dist/py/test/test_compat.py py/dist/py/test/test_config.py py/dist/py/test/test_raises.py py/dist/py/test/tool/test_outerrcapture.py Modified: py/dist/py/path/test/test_api.py Log: separated test files out into their own "testing" directory. it keeps the implementation files cleaner. Deleted: /py/dist/py/documentation/rest_test.py ============================================================================== --- /py/dist/py/documentation/rest_test.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,15 +0,0 @@ -from __future__ import generators - -import py - -pydir = py.magic.autopath(vars(py)).dirpath() -rest = pydir.join('bin', 'py.rest').getpymodule() -docdir = py.path.svnwc(pydir.join('documentation')) - -def restcheck(path): - rest.process(path) - #assert not out - -def test_rest_files(): - for x in docdir.listdir('*.txt'): - yield restcheck, x Added: py/dist/py/documentation/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/documentation/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Deleted: /py/dist/py/execnet/sshtesting.py ============================================================================== --- /py/dist/py/execnet/sshtesting.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,16 +0,0 @@ -""" -A test file that doesn't run by default to test SshGateway. -""" - -import py - -#REMOTE_HOST = 'codespeak.net' -#REMOTE_HOSTNAME = 'thoth.codespeak.net' -REMOTE_HOST = 'localhost' # you need to have a local ssh-daemon running! -REMOTE_HOSTNAME = py.std.socket.gethostname() # the remote's socket.gethostname() - -def test_sshgateway(): - gw = py.execnet.SshGateway(REMOTE_HOST) - c = gw.remote_exec('import socket; channel.send(socket.gethostname())') - msg = c.receive() - assert msg == REMOTE_HOSTNAME Deleted: /py/dist/py/execnet/test_gateway.py ============================================================================== --- /py/dist/py/execnet/test_gateway.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,193 +0,0 @@ -import os, sys -import py -from py.__impl__.execnet import gateway -mypath = py.magic.autopath() - -from StringIO import StringIO - -class TestMessage: - def test_wire_protocol(self): - for cls in gateway.Message._types.values(): - one = StringIO() - cls(42, '23').writeto(one) - two = StringIO(one.getvalue()) - msg = gateway.Message.readfrom(two) - assert isinstance(msg, cls) - assert msg.channelid == 42 - assert msg.data == '23' - assert isinstance(repr(msg), str) - # == "" %(msg.__class__.__name__, ) - -class TestChannel: - def setup_method(self, method): - self.fac = gateway.ChannelFactory(None) - - def test_factory_create(self): - chan1 = self.fac.new() - assert chan1.id == 1 - chan2 = self.fac.new() - assert chan2.id == 3 - - def test_factory_getitem(self): - chan1 = self.fac.new() - assert self.fac[chan1.id] == chan1 - chan2 = self.fac.new() - assert self.fac[chan2.id] == chan2 - - def test_factory_delitem(self): - chan1 = self.fac.new() - assert self.fac[chan1.id] == chan1 - del self.fac[chan1.id] - py.test.raises(KeyError, self.fac.__getitem__, chan1.id) - - def test_factory_setitem(self): - channel = gateway.Channel(None, 12) - self.fac[channel.id] = channel - assert self.fac[channel.id] == channel - - def test_channel_timeouterror(self): - channel = self.fac.new() - py.test.raises(IOError, channel.waitclose, timeout=0.01) - -class PopenGatewayTestSetup: - def setup_class(cls): - cls.gw = py.execnet.PopenGateway() - - def teardown_class(cls): - cls.gw.exit() - -class BasicRemoteExecution: - def test_correct_setup(self): - assert self.gw.workerthreads and self.gw.iothreads - - def test_remote_exec_waitclose(self): - channel = self.gw.remote_exec('pass') - channel.waitclose(timeout=3.0) - - def test_remote_exec_channel_anonymous(self): - channel = self.gw.remote_exec(''' - obj = channel.receive() - channel.send(obj) - ''') - channel.send(42) - result = channel.receive() - assert result == 42 - - def test_channel_close_and_then_receive_error(self): - channel = self.gw.remote_exec('raise ValueError') - py.test.raises(gateway.RemoteError, channel.receive) - - def test_channel_close_and_then_receive_error_multiple(self): - channel = self.gw.remote_exec('channel.send(42) ; raise ValueError') - x = channel.receive() - assert x == 42 - py.test.raises(gateway.RemoteError, channel.receive) - - def test_channel_close(self): - channel = self.gw.channelfactory.new() - channel._close() - channel.waitclose(0.1) - - def test_channel_close_error(self): - channel = self.gw.channelfactory.new() - channel._close(gateway.RemoteError("error")) - py.test.raises(gateway.RemoteError, channel.waitclose, 0.01) - - def test_channel_passing_over_channel(self): - channel = self.gw.remote_exec(''' - c = channel.newchannel() - channel.send(c) - c.send(42) - ''') - c = channel.receive() - x = c.receive() - assert x == 42 - - # check that the both sides previous channels are really gone - channel.waitclose(0.3) - assert channel.id not in self.gw.channelfactory - #assert c.id not in self.gw.channelfactory - newchan = self.gw.remote_exec(''' - assert %d not in channel.gateway.channelfactory - ''' % (channel.id)) - newchan.waitclose(0.3) - -class TestBasicPopenGateway(PopenGatewayTestSetup, BasicRemoteExecution): - def test_many_popen(self): - num = 4 - l = [] - for i in range(num): - l.append(py.execnet.PopenGateway()) - channels = [] - for gw in l: - channel = gw.remote_exec("""channel.send(42)""") - channels.append(channel) - try: - while channels: - channel = channels.pop() - try: - ret = channel.receive() - assert ret == 42 - finally: - channel.gateway.exit() - finally: - for x in channels: - x.gateway.exit() - -class SocketGatewaySetup: - def setup_class(cls): - portrange = (7770, 7800) - cls.proxygw = py.execnet.PopenGateway() - socketserverbootstrap = py.code.Source( - mypath.dirpath('bin', 'startserver.py').read(), - """ - import socket - portrange = channel.receive() - for i in portrange: - try: - sock = bind_and_listen(("localhost", i)) - except socket.error: - print "got error" - import traceback - traceback.print_exc() - continue - else: - channel.send(i) - startserver(sock) - break - else: - channel.send(None) - """) - # open a gateway to a fresh child process - cls.proxygw = py.execnet.PopenGateway() - - # execute asynchronously the above socketserverbootstrap on the other - channel = cls.proxygw.remote_exec(socketserverbootstrap) - - # send parameters for the for-loop - channel.send((7770, 7800)) - # - # the other side should start the for loop now, we - # wait for the result - # - cls.listenport = channel.receive() - if cls.listenport is None: - raise IOError, "could not setup remote SocketServer" - cls.gw = py.execnet.SocketGateway('localhost', cls.listenport) - print "initialized socket gateway on port", cls.listenport - - def teardown_class(cls): - print "trying to tear down remote socket gateway" - cls.gw.exit() - if cls.gw.port: - print "trying to tear down remote socket loop" - import socket - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect(('localhost', cls.listenport)) - sock.sendall('"raise KeyboardInterrupt"') - sock.shutdown(2) - print "trying to tear proxy gateway" - cls.proxygw.exit() - -class TestSocketGateway(SocketGatewaySetup, BasicRemoteExecution): - pass Added: py/dist/py/execnet/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/execnet/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Copied: py/dist/py/execnet/testing/test_gateway.py (from r8046, py/dist/py/execnet/test_gateway.py) ============================================================================== --- py/dist/py/execnet/test_gateway.py (original) +++ py/dist/py/execnet/testing/test_gateway.py Mon Jan 3 13:14:26 2005 @@ -139,7 +139,7 @@ portrange = (7770, 7800) cls.proxygw = py.execnet.PopenGateway() socketserverbootstrap = py.code.Source( - mypath.dirpath('bin', 'startserver.py').read(), + mypath.dirpath().dirpath('bin', 'startserver.py').read(), """ import socket portrange = channel.receive() Deleted: /py/dist/py/magic/test_assertion.py ============================================================================== --- /py/dist/py/magic/test_assertion.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,53 +0,0 @@ -import py - -def setup_module(mod): - py.magic.invoke(assertion=1) - -def teardown_module(mod): - py.magic.revoke(assertion=1) - -def f(): - return 2 - -def test_assert(): - try: - assert f() == 3 - except AssertionError, e: - s = str(e) - assert s.startswith('assert 2 == 3\n') - -def test_assert_within_finally(): - class A: - def f(): - pass - excinfo = py.test.raises(TypeError, """ - try: - A().f() - finally: - i = 42 - """) - s = excinfo.exception_text - assert s.find("takes no argument") != -1 - - #def g(): - # A.f() - #excinfo = getexcinfo(TypeError, g) - #msg = getmsg(excinfo) - #assert msg.find("must be called with A") != -1 - - -def test_assert_multiline_1(): - try: - assert (f() == - 3) - except AssertionError, e: - s = str(e) - assert s.startswith('assert 2 == 3\n') - -def test_assert_multiline_2(): - try: - assert (f() == (4, - 3)[-1]) - except AssertionError, e: - s = str(e) - assert s.startswith('assert 2 ==') Deleted: /py/dist/py/magic/test_autopath.py ============================================================================== --- /py/dist/py/magic/test_autopath.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,89 +0,0 @@ -import py -import sys - -class TestAutoPath: - getauto = "from py.magic import autopath ; autopath = autopath()" - def __init__(self): - self.root = py.test.config.tmpdir.ensure('autoconfigure', dir=1) - self.initdir = self.root.ensure('pkgdir', dir=1) - self.initdir.ensure('__init__.py') - self.initdir2 = self.initdir.ensure('initdir2', dir=1) - self.initdir2.ensure('__init__.py') - - def test_import_autoconfigure__file__with_init(self): - testpath = self.initdir2 / 'autoconfiguretest.py' - d = {'__file__' : str(testpath)} - oldsyspath = sys.path[:] - try: - exec self.getauto in d - conf = d['autopath'] - assert conf.dirpath() == self.initdir2 - assert conf.pkgdir == self.initdir - assert str(self.root) in sys.path - exec self.getauto in d - assert conf is not d['autopath'] - finally: - sys.path[:] = oldsyspath - - def test_import_autoconfigure__file__with_py_exts(self): - for ext in '.pyc', '.pyo': - testpath = self.initdir2 / ('autoconfiguretest' + ext) - d = {'__file__' : str(testpath)} - oldsyspath = sys.path[:] - try: - exec self.getauto in d - conf = d['autopath'] - assert conf == self.initdir2.join('autoconfiguretest.py') - assert conf.pkgdir == self.initdir - assert str(self.root) in sys.path - exec self.getauto in d - assert conf is not d['autopath'] - finally: - sys.path[:] = oldsyspath - - def test_import_autoconfigure___file__without_init(self): - testpath = self.root / 'autoconfiguretest.py' - d = {'__file__' : str(testpath)} - oldsyspath = sys.path[:] - try: - exec self.getauto in d - conf = d['autopath'] - assert conf.dirpath() == self.root - assert conf.pkgdir == self.root - syspath = sys.path[:] - assert str(self.root) in syspath - exec self.getauto in d - assert conf is not d['autopath'] - finally: - sys.path[:] = oldsyspath - - def test_import_autoconfigure__nofile(self): - p = self.initdir2 / 'autoconfiguretest.py' - oldsysarg = sys.argv - sys.argv = [str(p)] - oldsyspath = sys.path[:] - try: - d = {} - exec self.getauto in d - conf = d['autopath'] - assert conf.dirpath() == self.initdir2 - assert conf.pkgdir == self.initdir - syspath = sys.path[:] - assert str(self.root) in syspath - finally: - sys.path[:] = oldsyspath - sys.argv = sys.argv - - - def test_import_autoconfigure__nofile_interactive(self): - oldsysarg = sys.argv - sys.argv = [''] - oldsyspath = sys.path[:] - try: - py.test.raises(ValueError,''' - d = {} - exec self.getauto in d - ''') - finally: - sys.path[:] = oldsyspath - sys.argv = sys.argv Deleted: /py/dist/py/magic/test_exprinfo.py ============================================================================== --- /py/dist/py/magic/test_exprinfo.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,103 +0,0 @@ - -import sys -import py -from py.__impl__.magic.exprinfo import getmsg, interpret - -def getexcinfo(exc, obj, *args, **kwargs): - try: - obj(*args, **kwargs) - except KeyboardInterrupt: - raise - except exc: - return sys.exc_info() - else: - raise AssertionError, "%r(*%r, **%r) did not raise" %( - obj, args, kwargs) - -def test_assert_exprinfo(): - def g(): - a = 1 - b = 2 - assert a == b - excinfo = getexcinfo(AssertionError, g) - msg = getmsg(excinfo) - assert msg == 'assert 1 == 2' - -def test_nested_scopes(): - def g(): - a = 1 - def h(): - return a - b = 2 - assert h() == b - excinfo = getexcinfo(AssertionError, g) - msg = getmsg(excinfo) - assert msg.startswith('assert 1 == 2\n + where 1 = ') - -def test_nested_scopes_2(): - a = 1 - def g(): - b = 2 - assert a == b - excinfo = getexcinfo(AssertionError, g) - msg = getmsg(excinfo) - assert msg == 'assert 1 == 2' - -def test_assert_func_argument_type_error(): - def f (): - pass - def g(): - f(1) - excinfo = getexcinfo(TypeError, g) - msg = getmsg(excinfo) - assert msg.find("takes no argument") != -1 - - class A: - def f(): - pass - def g(): - A().f() - excinfo = getexcinfo(TypeError, g) - msg = getmsg(excinfo) - assert msg.find("takes no argument") != -1 - - def g(): - A.f() - excinfo = getexcinfo(TypeError, g) - msg = getmsg(excinfo) - assert msg.find("must be called with A") != -1 - -def global_f(): - return 42 - -def test_exprinfo_funccall(): - def g(): - assert global_f() == 43 - excinfo = getexcinfo(AssertionError, g) - msg = getmsg(excinfo) - assert msg == 'assert 42 == 43\n + where 42 = global_f()' - -def test_keyboard_interrupt(): - # XXX this test is slightly strange because it is not - # clear that "interpret" should execute "raise" statements - # ... but it apparently currently does and it's nice to - # exercise the code because the exprinfo-machinery is - # not much executed when all tests pass ... - - class DummyCode: - co_filename = 'dummy' - co_firstlineno = 0 - co_name = 'dummy' - class DummyFrame: - f_globals = f_locals = {} - f_code = DummyCode - f_lineno = 0 - - for exstr in "SystemExit", "KeyboardInterrupt", "MemoryError": - ex = eval(exstr) - try: - interpret("raise %s" % exstr, py.code.Frame(DummyFrame)) - except ex: - pass - else: - raise AssertionError, "ex %s didn't pass through" %(exstr, ) Deleted: /py/dist/py/magic/test_invoke.py ============================================================================== --- /py/dist/py/magic/test_invoke.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,15 +0,0 @@ -import __builtin__ as bltin -import py -import inspect - -def check_assertion(): - excinfo = py.test.raises(AssertionError, "assert 1 == 2") - assert excinfo.exception_text == "assert 1 == 2" - -def test_invoke_assertion(): - py.magic.invoke(assertion=True) - try: - check_assertion() - finally: - py.magic.revoke(assertion=True) - Deleted: /py/dist/py/magic/test_patch.py ============================================================================== --- /py/dist/py/magic/test_patch.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,31 +0,0 @@ -from py.test import raises -from py.magic import patch, revert - -def test_patch_revert(): - class a: - pass - raises(AttributeError, "patch(a, 'i', 42)") - - a.i = 42 - patch(a, 'i', 23) - assert a.i == 23 - revert(a, 'i') - assert a.i == 42 - -def test_double_patch(): - class a: - i = 42 - assert patch(a, 'i', 2) == 42 - assert patch(a, 'i', 3) == 2 - assert a.i == 3 - assert revert(a, 'i') == 3 - assert a.i == 2 - assert revert(a, 'i') == 2 - assert a.i == 42 - -def test_valueerror(): - class a: - i = 2 - pass - raises(ValueError, "revert(a, 'i')") - Deleted: /py/dist/py/magic/test_viewtype.py ============================================================================== --- /py/dist/py/magic/test_viewtype.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,55 +0,0 @@ -from py.magic import View - -def test_class_dispatch(): - ### Use a custom class hierarchy with existing instances - - class Picklable(View): - pass - - class Simple(Picklable): - __view__ = object - def pickle(self): - return repr(self.__obj__) - - class Seq(Picklable): - __view__ = list, tuple, dict - def pickle(self): - return ';'.join([Picklable(item).pickle() for item in self.__obj__]) - - class Dict(Seq): - __view__ = dict - def pickle(self): - return Seq.pickle(self) + '!' + Seq(self.values()).pickle() - - assert Picklable(123).pickle() == '123' - assert Picklable([1,[2,3],4]).pickle() == '1;2;3;4' - assert Picklable({1:2}).pickle() == '1!2' - - -def test_custom_class_hierarchy(): - ### Use a custom class hierarchy based on attributes of existing instances - - class Operation: - "Existing class that I don't want to change." - def __init__(self, opname, *args): - self.opname = opname - self.args = args - - existing = [Operation('+', 4, 5), - Operation('getitem', '', 'join'), - Operation('setattr', 'x', 'y', 3), - Operation('-', 12, 1)] - - class PyOp(View): - def __viewkey__(self): - return self.opname - def generate(self): - return '%s(%s)' % (self.opname, ', '.join(map(repr, self.args))) - - class PyBinaryOp(PyOp): - __view__ = ('+', '-', '*', '/') - def generate(self): - return '%s %s %s' % (self.args[0], self.opname, self.args[1]) - - codelines = [PyOp(op).generate() for op in existing] - assert codelines == ["4 + 5", "getitem('', 'join')", "setattr('x', 'y', 3)", "12 - 1"] Added: py/dist/py/magic/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/magic/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Deleted: /py/dist/py/misc/test_api.py ============================================================================== --- /py/dist/py/misc/test_api.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,43 +0,0 @@ - -from py.test import raises -import py -import sys -import inspect - -class TestAPI_V0_namespace_consistence: - def test_path_entrypoints(self): - assert inspect.ismodule(py.path) - assert_class('py.path', 'local') - assert_class('py.path', 'svnwc') - assert_class('py.path', 'svnurl') - assert_class('py.path', 'extpy') - assert_class('py.path', 'checker') - - def test_magic_entrypoints(self): - assert_class('py.magic', 'View') - assert_function('py.magic', 'invoke') - assert_function('py.magic', 'revoke') - assert_function('py.magic', 'patch') - assert_function('py.magic', 'revoke') - - def test_process_entrypoints(self): - assert_function('py.process', 'cmdexec') - - def XXXtest_utest_entrypoints(self): - # XXX TOBECOMPLETED - assert_function('py.test', 'main') - #assert_module('std.utest', 'collect') - -def assert_class(modpath, name): - mod = __import__(modpath, None, None, [name]) - obj = getattr(mod, name) - fullpath = modpath + '.' + name - assert obj.__module__ == modpath - if sys.version_info >= (2,3): - assert obj.__name__ == name - -def assert_function(modpath, name): - mod = __import__(modpath, None, None, [name]) - obj = getattr(mod, name) - assert hasattr(obj, 'func_doc') - #assert obj.func_name == name Deleted: /py/dist/py/misc/test_cache.py ============================================================================== --- /py/dist/py/misc/test_cache.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,55 +0,0 @@ -import py -from cache import BuildcostAccessCache, AgingCache - -class BasicCacheAPITest: - cache = None - def test_getorbuild(self): - val = self.cache.getorbuild(-42, lambda: 42) - assert val == 42 - val = self.cache.getorbuild(-42, lambda: 23) - assert val == 42 - - def test_cache_get_key_error(self): - assert self.cache.getentry(-23) == None - - def test_delentry_non_raising(self): - val = self.cache.getorbuild(100, lambda: 100) - self.cache.delentry(100) - assert self.cache.getentry(100) is None - - def test_delentry_raising(self): - val = self.cache.getorbuild(100, lambda: 100) - self.cache.delentry(100) - py.test.raises(KeyError, "self.cache.delentry(100, raising=True)") - -class TestBuildcostAccess(BasicCacheAPITest): - cache = BuildcostAccessCache(maxentries=128) - - def test_cache_works_somewhat_simple(self): - cache = BuildcostAccessCache() - for x in range(cache.maxentries): - y = cache.getorbuild(x, lambda: x) - assert x == y - for x in range(cache.maxentries): - assert cache.getorbuild(x, None) == x - for x in range(cache.maxentries/2): - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(x, None) == x - val = cache.getorbuild(cache.maxentries * 2, lambda: 42) - assert val == 42 - # check that recently used ones are still there - # and are not build again - for x in range(cache.maxentries/2): - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(cache.maxentries*2, None) == 42 - - -class TestAging(BasicCacheAPITest): - maxsecs = 0.02 - cache = AgingCache(maxentries=128, maxseconds=maxsecs) - - def test_cache_eviction(self): - self.cache.getorbuild(17, lambda: 17) - py.std.time.sleep(self.maxsecs*1.1) - assert self.cache.getentry(17) is None Deleted: /py/dist/py/misc/test_error.py ============================================================================== --- /py/dist/py/misc/test_error.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,10 +0,0 @@ - -import py - -import errno - -def test_error_classes(): - for name in errno.errorcode.values(): - x = getattr(py.error, name) - assert issubclass(x, py.error.Error) - assert issubclass(x, EnvironmentError) Deleted: /py/dist/py/misc/test_initpkg.py ============================================================================== --- /py/dist/py/misc/test_initpkg.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,80 +0,0 @@ -import py -import types - -def test_dir(): - from py.__impl__.initpkg import Module - for name in dir(py): - if not name.startswith('_'): - obj = getattr(py, name) - if hasattr(obj, '__map__'): # isinstance(obj, Module): - keys = dir(obj) - assert len(keys) > 0 - assert getattr(obj, '__map__') == {} - -def test_virtual_module_identity(): - from py import path as path1 - from py import path as path2 - assert path1 is path2 - from py.path import local as local1 - from py.path import local as local2 - assert local1 is local2 - -def test_importing_all_implementations(): - base = py.path.local(py.__file__).dirpath() - nodirs = ( - base.join('test', 'test', 'data'), - base.join('path', 'extpy', 'test_data'), - base.join('path', 'gateway',), - base.join('documentation',), - base.join('test', 'test', 'import_test'), - base.join('magic', 'greenlet'), - base.join('bin'), - base.join('execnet', 'bin'), - ) - for p in base.visit('*.py', py.path.checker(dotfile=0)): - relpath = p.new(ext='').relto(base) - if base.sep in relpath: # not std/*.py itself - for x in nodirs: - if p.relto(x): - break - else: - relpath = relpath.replace(base.sep, '.') - modpath = 'py.__impl__.%s' % relpath - assert __import__(modpath) - -def test_shahexdigest(): - hex = py.__package__.shahexdigest() - assert len(hex) == 40 - -def test_getzipdata(): - s = py.__package__.getzipdata() - -def test_getrev(): - d = py.__package__.getrev() - try: - svnversion = py.path.local.sysfind('svnversion') - except py.error.ENOENT: - py.test.skip("cannot test svnversion, 'svnversion' binary not found") - v = svnversion.sysexec(py.path.local(py.__file__).dirpath()) - assert v.startswith(str(d)) - -# the following test should abasically work in the future -def XXXtest_virtual_on_the_fly(): - py.initpkg('my', { - 'x.abspath' : 'os.path.abspath', - 'x.local' : 'py.path.local', - 'y' : 'smtplib', - 'z.cmdexec' : 'py.process.cmdexec', - }) - from my.x import abspath - from my.x import local - import smtplib - from my import y - assert y is smtplib - from my.z import cmdexec - from py.process import cmdexec as cmdexec2 - assert cmdexec is cmdexec2 - -##def test_help(): -# help(std.path) -# #assert False Deleted: /py/dist/py/misc/test_std.py ============================================================================== --- /py/dist/py/misc/test_std.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,13 +0,0 @@ - -import py - -def test_os(): - import os - assert py.std.os is os - -def test_import_error_converts_to_attributeerror(): - py.test.raises(AttributeError, "py.std.xyzalskdj") - -def test_std_gets_it(): - for x in py.std.sys.modules: - assert x in py.std.__dict__ Added: py/dist/py/misc/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/misc/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Copied: py/dist/py/misc/testing/test_cache.py (from r8046, py/dist/py/misc/test_cache.py) ============================================================================== --- py/dist/py/misc/test_cache.py (original) +++ py/dist/py/misc/testing/test_cache.py Mon Jan 3 13:14:26 2005 @@ -1,5 +1,5 @@ import py -from cache import BuildcostAccessCache, AgingCache +from py.__impl__.misc.cache import BuildcostAccessCache, AgingCache class BasicCacheAPITest: cache = None Copied: py/dist/py/misc/testing/test_initpkg.py (from r8046, py/dist/py/misc/test_initpkg.py) ============================================================================== --- py/dist/py/misc/test_initpkg.py (original) +++ py/dist/py/misc/testing/test_initpkg.py Mon Jan 3 13:14:26 2005 @@ -22,11 +22,11 @@ def test_importing_all_implementations(): base = py.path.local(py.__file__).dirpath() nodirs = ( - base.join('test', 'test', 'data'), - base.join('path', 'extpy', 'test_data'), + base.join('test', 'testing', 'test'), + base.join('path', 'extpy', 'testing', 'test_data'), base.join('path', 'gateway',), base.join('documentation',), - base.join('test', 'test', 'import_test'), + base.join('test', 'testing', 'import_test'), base.join('magic', 'greenlet'), base.join('bin'), base.join('execnet', 'bin'), Deleted: /py/dist/py/path/extpy/inc_pseudofs.py ============================================================================== --- /py/dist/py/path/extpy/inc_pseudofs.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,12 +0,0 @@ - -samplefile = 'samplefile\n' -samplepickle = {} - -class sampledir: - otherfile = 'otherfile' - -class otherdir: - init = 42 - -class execfile: - x = 42 Deleted: /py/dist/py/path/extpy/inc_test_extpy.py ============================================================================== --- /py/dist/py/path/extpy/inc_test_extpy.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,18 +0,0 @@ -from __future__ import generators - -class A: - x1 = 42 - def func(self): - pass - - def genfunc(self): - yield 2 - -class B: - x2 = 23 - -class Nested: - class Class: - def borgfunc(self): pass - - Deleted: /py/dist/py/path/extpy/test_extpy.py ============================================================================== --- /py/dist/py/path/extpy/test_extpy.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,201 +0,0 @@ -import os -import py - -from py.__impl__.path.test import common - -mypath = py.magic.autopath().dirpath('inc_test_extpy.py') - -class TestExtPyCommonTests(common.CommonPathTests): - def setup_class(cls): - cls.root = py.path.extpy( - py.magic.autopath().dirpath('inc_pseudofs.py')) - - def test_file(self): - assert self.root.join('samplefile').check(file=1) - assert self.root.join('otherdir').check(file=0) - -class TestExtPy: - def setup_class(cls): - cls.root = py.path.extpy(mypath) - - def test_join(self): - p = self.root.join('A') - obj = p.resolve() - assert hasattr(obj, '__bases__') - assert obj.x1 == 42 - - def test_listdir_module(self): - l = self.root.listdir() - basenames = [x.basename for x in l] - dlist = dir(self.root.resolve()) - for name in dlist: - assert name in basenames - for name in basenames: - assert name in dlist - - def test_listdir_class(self): - l = self.root.join('A').listdir() - basenames = [x.basename for x in l] - dlist = dir(self.root.resolve().A) - for name in dlist: - assert name in basenames - for name in basenames: - assert name in dlist - - def listobj(self): - l = self.root.listobj(basestarts='path') - assert len(l) == 1 - assert l[0] == path - - def test_visit(self): - l = list(self.root.visit(py.path.checker(basename='borgfunc'))) - assert len(l) == 1 - obj = l[0] - assert str(obj).endswith('Nested.Class.borgfunc') - assert obj.resolve() == self.root.resolve().Nested.Class.borgfunc - - def test_visit_fnmatch(self): - l = list(self.root.visit('borg*')) - assert len(l) == 1 - obj = l[0] - assert str(obj).endswith('Nested.Class.borgfunc') - assert obj.resolve() == self.root.resolve().Nested.Class.borgfunc - - #def test_join_from_empty(self): - # p = path.py('') - # n = p.join('tokenize') - # assert str(n) == 'tokenize' - # - # p = path.py('', ns=os) - # n = p.join('getlogin') - # assert str(n) == 'getlogin' - - #def test_unspecifiedpypath_lists_modules(self): - # p = path.py('') - # l = p.listdir() - # for i in l: - # assert '.' not in str(i) - # - # for j in sys.modules: - # for i in l: - # if j.startswith(str(i)): - # break - # else: - # self.fail("%s is not in sys.modules") - - #def test_main_works(self): - # m = path.py('__main__') - # import __main__ - # assert m.resolve() is __main__ - - def test_relto(self): - m1 = self.root.new(modpath='a.b.c.d') - m2 = self.root.new(modpath='a.b') - m3 = self.root.new(modpath='') - res = m1.relto(m2) - assert str(res) == 'c.d' - assert m2.relto(m3) == 'a.b' - - def test_basename(self): - m1 = self.root.new(modpath='a.b.hello') - assert m1.basename == 'hello' - assert m1.check(basename='hello') - assert not m1.check(basename='nono') - assert m1.check(basestarts='he') - assert not m1.check(basestarts='42') - - def test_dirpath(self): - m1 = self.root.new(modpath='a.b.hello') - m2 = self.root.new(modpath='a.b') - m3 = self.root.new(modpath='a') - m4 = self.root.new(modpath='') - assert m1.dirpath() == m2 - assert m2.dirpath() == m3 - assert m3.dirpath() == m4 - - def test_function(self): - p = self.root.join('A.func') - assert p.check(func=1) - p = self.root.join('A.x1') - assert p.check(func=0) - - def test_generatorfunction(self): - p = self.root.join('A.genfunc') - assert p.check(genfunc=1) - p = self.root.join('A.func') - assert p.check(genfunc=0) - p = self.root.join('A') - assert p.check(genfunc=0) - - def test_class(self): - p = self.root.join('A') - assert p.check(class_=1) - - def test_hashing_equality(self): - x = self.root - y = self.root.new() - assert x == y - assert hash(x) == hash(y) - - def test_parts2(self): - x = self.root.new(modpath='os.path.abspath') - l = x.parts() - assert len(l) == 4 - assert self.root.join('') == l[0] - assert self.root.join('os') == l[1] - assert self.root.join('os.path') == l[2] - assert self.root.join('os.path.abspath') == l[3] - -#class TestExtPyWithModule: -# def test_module(self): -# import os -# x = py.path.extpy(os, 'path.abspath') -# assert x.check() -# assert x.resolve() is os.path.abspath -# #def setup_class(cls): - # cls.root = py.path.extpy(mypath) - -class TestEval: - disabled = True - def test_funccall(self): - p = path.py('os.path.join("a", "b")') - s = p.resolve() - assert s == os.path.join("a", "b") - - def test_invalid1(self): - p = path.py('os.path.qwe("a", "b")') - s = test.raises(py.error.ENOENT, "p.resolve()") - - def test_syntaxerror(self): - p = path.py('os.path.qwe("a", ') - s = test.raises(ValueError, "p.resolve()") - -class TestErrors: - def test_ENOENT(self): - p = py.path.extpy(mypath, 'somesuch') - py.test.raises(py.error.ENOENT, p.resolve) - - def test_ENOENT_really(self): - p = py.path.extpy(mypath.new(basename='notexist'), 'somesuch') - py.test.raises(py.error.ENOENT, p.resolve) - - #def test_ImportError(): - # p = path.py('__std.utest.test.data.failingimport.someattr') - # utest.raises(ImportError, p.resolve) - -class ExampleClass: - testattr = 1 - -def test_no_newline(): - filepath = mypath.dirpath() / 'test_data' / 'no_trailing_newline.py' - pyc = filepath.dirpath() / 'no_trailing_newline.pyc' - if pyc.check(exists=1): - pyc.remove() - data = filepath.read() - assert not data.endswith('\n') and not data.endswith('\r'), ( - "The file must not end with a newline (that's the point of " - "this test") - #print repr(data) - mod_extpy = py.path.extpy(filepath) - #print mod_extpy.resolve() - assert mod_extpy.resolve().test Added: py/dist/py/path/extpy/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/path/extpy/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Deleted: /py/dist/py/path/local/popen5/test_subprocess.py ============================================================================== --- /py/dist/py/path/local/popen5/test_subprocess.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,551 +0,0 @@ -import sys -import os -import py -from py.__impl__.path.local.popen5 import subprocess - -mswindows = (sys.platform == "win32") - -# -# Depends on the following external programs: Python -# - -if mswindows: - SETBINARY = ('import msvcrt; msvcrt.setmode(sys.stdout.fileno(), ' - 'os.O_BINARY);') -else: - SETBINARY = '' - -# In a debug build, stuff like "[6580 refs]" is printed to stderr at -# shutdown time. That frustrates tests trying to check stderr produced -# from a spawned Python process. -def remove_stderr_debug_decorations(stderr): - return py.std.re.sub(r"\[\d+ refs\]\r?\n?$", "", stderr) - -class TestPopen5(py.test.compat.TestCase): - disabled = True - def mkstemp(self): - """wrapper for mkstemp, calling mktemp if mkstemp is not available""" - if hasattr(tempfile, "mkstemp"): - return py.std.tempfile.mkstemp() - else: - fname = py.std.tempfile.mktemp() - return os.open(fname, os.O_RDWR|os.O_CREAT), fname - - # - # Generic tests - # - def test_call_seq(self): - # call() function with sequence argument - rc = subprocess.call([sys.executable, "-c", - "import sys; sys.exit(47)"]) - self.assertEqual(rc, 47) - - def test_call_kwargs(self): - # call() function with keyword args - newenv = os.environ.copy() - newenv["FRUIT"] = "banana" - rc = subprocess.call([sys.executable, "-c", - 'import sys, os;' \ - 'sys.exit(os.getenv("FRUIT")=="banana")'], - env=newenv) - self.assertEqual(rc, 1) - - def test_stdin_none(self): - # .stdin is None when not redirected - p = subprocess.Popen([sys.executable, "-c", 'print "banana"'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - p.wait() - self.assertEqual(p.stdin, None) - - def test_stdout_none(self): - # .stdout is None when not redirected - p = subprocess.Popen([sys.executable, "-c", - 'print " this bit of output is from a ' - 'test of stdout in a different ' - 'process ..."'], - stdin=subprocess.PIPE, stderr=subprocess.PIPE) - p.wait() - self.assertEqual(p.stdout, None) - - def test_stderr_none(self): - # .stderr is None when not redirected - p = subprocess.Popen([sys.executable, "-c", 'print "banana"'], - stdin=subprocess.PIPE, stdout=subprocess.PIPE) - p.wait() - self.assertEqual(p.stderr, None) - - def test_executable(self): - p = subprocess.Popen(["somethingyoudonthave", - "-c", "import sys; sys.exit(47)"], - executable=sys.executable) - p.wait() - self.assertEqual(p.returncode, 47) - - def test_stdin_pipe(self): - # stdin redirection - p = subprocess.Popen([sys.executable, "-c", - 'import sys; sys.exit(sys.stdin.read() == "pear")'], - stdin=subprocess.PIPE) - p.stdin.write("pear") - p.stdin.close() - p.wait() - self.assertEqual(p.returncode, 1) - - def test_stdin_filedes(self): - # stdin is set to open file descriptor - tf = py.std.tempfile.TemporaryFile() - d = tf.fileno() - os.write(d, "pear") - os.lseek(d, 0, 0) - p = subprocess.Popen([sys.executable, "-c", - 'import sys; sys.exit(sys.stdin.read() == "pear")'], - stdin=d) - p.wait() - self.assertEqual(p.returncode, 1) - - def test_stdin_fileobj(self): - # stdin is set to open file object - tf = py.std.tempfile.TemporaryFile() - tf.write("pear") - tf.seek(0) - p = subprocess.Popen([sys.executable, "-c", - 'import sys; sys.exit(sys.stdin.read() == "pear")'], - stdin=tf) - p.wait() - self.assertEqual(p.returncode, 1) - - def test_stdout_pipe(self): - # stdout redirection - p = subprocess.Popen([sys.executable, "-c", - 'import sys; sys.stdout.write("orange")'], - stdout=subprocess.PIPE) - self.assertEqual(p.stdout.read(), "orange") - - def test_stdout_filedes(self): - # stdout is set to open file descriptor - tf = py.std.tempfile.TemporaryFile() - d = tf.fileno() - p = subprocess.Popen([sys.executable, "-c", - 'import sys; sys.stdout.write("orange")'], - stdout=d) - p.wait() - os.lseek(d, 0, 0) - self.assertEqual(os.read(d, 1024), "orange") - - def test_stdout_fileobj(self): - # stdout is set to open file object - tf = py.std.tempfile.TemporaryFile() - p = subprocess.Popen([sys.executable, "-c", - 'import sys; sys.stdout.write("orange")'], - stdout=tf) - p.wait() - tf.seek(0) - self.assertEqual(tf.read(), "orange") - - def test_stderr_pipe(self): - # stderr redirection - p = subprocess.Popen([sys.executable, "-c", - 'import sys; sys.stderr.write("strawberry")'], - stderr=subprocess.PIPE) - self.assertEqual(remove_stderr_debug_decorations(p.stderr.read()), - "strawberry") - - def test_stderr_filedes(self): - # stderr is set to open file descriptor - tf = py.std.tempfile.TemporaryFile() - d = tf.fileno() - p = subprocess.Popen([sys.executable, "-c", - 'import sys; sys.stderr.write("strawberry")'], - stderr=d) - p.wait() - os.lseek(d, 0, 0) - self.assertEqual(remove_stderr_debug_decorations(os.read(d, 1024)), - "strawberry") - - def test_stderr_fileobj(self): - # stderr is set to open file object - tf = py.std.tempfile.TemporaryFile() - p = subprocess.Popen([sys.executable, "-c", - 'import sys; sys.stderr.write("strawberry")'], - stderr=tf) - p.wait() - tf.seek(0) - self.assertEqual(remove_stderr_debug_decorations(tf.read()), - "strawberry") - - def test_stdout_stderr_pipe(self): - # capture stdout and stderr to the same pipe - p = subprocess.Popen([sys.executable, "-c", - 'import sys;' \ - 'sys.stdout.write("apple");' \ - 'sys.stdout.flush();' \ - 'sys.stderr.write("orange")'], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - output = p.stdout.read() - stripped = remove_stderr_debug_decorations(output) - self.assertEqual(stripped, "appleorange") - - def test_stdout_stderr_file(self): - # capture stdout and stderr to the same open file - tf = py.std.tempfile.TemporaryFile() - p = subprocess.Popen([sys.executable, "-c", - 'import sys;' \ - 'sys.stdout.write("apple");' \ - 'sys.stdout.flush();' \ - 'sys.stderr.write("orange")'], - stdout=tf, - stderr=tf) - p.wait() - tf.seek(0) - output = tf.read() - stripped = remove_stderr_debug_decorations(output) - self.assertEqual(stripped, "appleorange") - - def test_cwd(self): - tmpdir = os.getenv("TEMP", "/tmp") - tmpdir = os.path.realpath(tmpdir) - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' \ - 'sys.stdout.write(os.getcwd())'], - stdout=subprocess.PIPE, - cwd=tmpdir) - normcase = os.path.normcase - self.assertEqual(normcase(p.stdout.read()), normcase(tmpdir)) - - def test_env(self): - newenv = os.environ.copy() - newenv["FRUIT"] = "orange" - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' \ - 'sys.stdout.write(os.getenv("FRUIT"))'], - stdout=subprocess.PIPE, - env=newenv) - self.assertEqual(p.stdout.read(), "orange") - - def test_communicate(self): - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' \ - 'sys.stderr.write("pineapple");' \ - 'sys.stdout.write(sys.stdin.read())'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - (stdout, stderr) = p.communicate("banana") - self.assertEqual(stdout, "banana") - self.assertEqual(remove_stderr_debug_decorations(stderr), - "pineapple") - - def test_communicate_returns(self): - # communicate() should return None if no redirection is active - p = subprocess.Popen([sys.executable, "-c", - "import sys; sys.exit(47)"]) - (stdout, stderr) = p.communicate() - self.assertEqual(stdout, None) - self.assertEqual(stderr, None) - - def test_communicate_pipe_buf(self): - # communicate() with writes larger than pipe_buf - # This test will probably deadlock rather than fail, if - # communicate() does not work properly. - x, y = os.pipe() - if mswindows: - pipe_buf = 512 - else: - pipe_buf = os.fpathconf(x, "PC_PIPE_BUF") - os.close(x) - os.close(y) - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' - 'sys.stdout.write(sys.stdin.read(47));' \ - 'sys.stderr.write("xyz"*%d);' \ - 'sys.stdout.write(sys.stdin.read())' % pipe_buf], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - string_to_write = "abc"*pipe_buf - (stdout, stderr) = p.communicate(string_to_write) - self.assertEqual(stdout, string_to_write) - - def test_writes_before_communicate(self): - # stdin.write before communicate() - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' \ - 'sys.stdout.write(sys.stdin.read())'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - p.stdin.write("banana") - (stdout, stderr) = p.communicate("split") - self.assertEqual(stdout, "bananasplit") - self.assertEqual(remove_stderr_debug_decorations(stderr), "") - - def test_universal_newlines(self): - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' + SETBINARY + - 'sys.stdout.write("line1\\n");' - 'sys.stdout.flush();' - 'sys.stdout.write("line2\\r");' - 'sys.stdout.flush();' - 'sys.stdout.write("line3\\r\\n");' - 'sys.stdout.flush();' - 'sys.stdout.write("line4\\r");' - 'sys.stdout.flush();' - 'sys.stdout.write("\\nline5");' - 'sys.stdout.flush();' - 'sys.stdout.write("\\nline6");'], - stdout=subprocess.PIPE, - universal_newlines=1) - stdout = p.stdout.read() - if hasattr(open, 'newlines'): - # Interpreter with universal newline support - self.assertEqual(stdout, - "line1\nline2\nline3\nline4\nline5\nline6") - else: - # Interpreter without universal newline support - self.assertEqual(stdout, - "line1\nline2\rline3\r\nline4\r\nline5\nline6") - - def test_universal_newlines_communicate(self): - # universal newlines through communicate() - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' + SETBINARY + - 'sys.stdout.write("line1\\n");' - 'sys.stdout.flush();' - 'sys.stdout.write("line2\\r");' - 'sys.stdout.flush();' - 'sys.stdout.write("line3\\r\\n");' - 'sys.stdout.flush();' - 'sys.stdout.write("line4\\r");' - 'sys.stdout.flush();' - 'sys.stdout.write("\\nline5");' - 'sys.stdout.flush();' - 'sys.stdout.write("\\nline6");'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE, - universal_newlines=1) - (stdout, stderr) = p.communicate() - if hasattr(open, 'newlines'): - # Interpreter with universal newline support - self.assertEqual(stdout, - "line1\nline2\nline3\nline4\nline5\nline6") - else: - # Interpreter without universal newline support - self.assertEqual(stdout, "line1\nline2\rline3\r\nline4\r\nline5\nline6") - - def test_no_leaking(self): - # Make sure we leak no resources - max_handles = 1026 # too much for most UNIX systems - if mswindows: - max_handles = 65 # a full test is too slow on Windows - for i in range(max_handles): - p = subprocess.Popen([sys.executable, "-c", - "import sys;sys.stdout.write(sys.stdin.read())"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - data = p.communicate("lime")[0] - self.assertEqual(data, "lime") - - - def test_list2cmdline(self): - self.assertEqual(subprocess.list2cmdline(['a b c', 'd', 'e']), - '"a b c" d e') - self.assertEqual(subprocess.list2cmdline(['ab"c', '\\', 'd']), - 'ab\\"c \\ d') - self.assertEqual(subprocess.list2cmdline(['a\\\\\\b', 'de fg', 'h']), - 'a\\\\\\b "de fg" h') - self.assertEqual(subprocess.list2cmdline(['a\\"b', 'c', 'd']), - 'a\\\\\\"b c d') - self.assertEqual(subprocess.list2cmdline(['a\\\\b c', 'd', 'e']), - '"a\\\\b c" d e') - self.assertEqual(subprocess.list2cmdline(['a\\\\b\\ c', 'd', 'e']), - '"a\\\\b\\ c" d e') - - - def test_poll(self): - p = subprocess.Popen([sys.executable, - "-c", "import time; time.sleep(1)"]) - count = 0 - while p.poll() is None: - py.std.time.sleep(0.1) - count += 1 - # We expect that the poll loop probably went around about 10 times, - # but, based on system scheduling we can't control, it's possible - # poll() never returned None. It "should be" very rare that it - # didn't go around at least twice. - self.assert_(count >= 2) - # Subsequent invocations should just return the returncode - self.assertEqual(p.poll(), 0) - - - def test_wait(self): - p = subprocess.Popen([sys.executable, - "-c", "import time; time.sleep(2)"]) - self.assertEqual(p.wait(), 0) - # Subsequent invocations should just return the returncode - self.assertEqual(p.wait(), 0) - - # - # POSIX tests - # - if not mswindows: - def test_exceptions(self): - # catched & re-raised exceptions - try: - p = subprocess.Popen([sys.executable, "-c", ""], - cwd="/this/path/does/not/exist") - except OSError, e: - # The attribute child_traceback should contain "os.chdir" - # somewhere. - self.assertNotEqual(e.child_traceback.find("os.chdir"), -1) - else: - self.fail("Expected OSError") - - def test_run_abort(self): - # returncode handles signal termination - p = subprocess.Popen([sys.executable, - "-c", "import os; os.abort()"]) - p.wait() - self.assertEqual(-p.returncode, py.std.signal.SIGABRT) - - def test_preexec(self): - # preexec function - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' \ - 'sys.stdout.write(os.getenv("FRUIT"))'], - stdout=subprocess.PIPE, - preexec_fn=lambda: os.putenv("FRUIT", "apple")) - self.assertEqual(p.stdout.read(), "apple") - - def test_close_fds(self): - # Make sure we have some fds open - os.pipe() - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' \ - 'sys.stdout.write(str(os.dup(0)))'], - stdout=subprocess.PIPE, close_fds=1) - # When all fds are closed, the next free fd should be 3. - self.assertEqual(p.stdout.read(), "3") - - def test_args_string(self): - # args is a string - f, fname = self.mkstemp() - os.write(f, "#!/bin/sh\n") - os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % - sys.executable) - os.close(f) - os.chmod(fname, 0700) - p = subprocess.Popen(fname) - p.wait() - self.assertEqual(p.returncode, 47) - os.remove(fname) - - def test_invalid_args(self): - # invalid arguments should raise ValueError - self.assertRaises(ValueError, subprocess.call, - [sys.executable, - "-c", "import sys; sys.exit(47)"], - startupinfo=47) - self.assertRaises(ValueError, subprocess.call, - [sys.executable, - "-c", "import sys; sys.exit(47)"], - creationflags=47) - - def test_shell_sequence(self): - # Run command through the shell (sequence) - newenv = os.environ.copy() - newenv["FRUIT"] = "apple" - p = subprocess.Popen(["echo $FRUIT"], shell=1, - stdout=subprocess.PIPE, - env=newenv) - self.assertEqual(p.stdout.read().strip(), "apple") - - def test_shell_string(self): - # Run command through the shell (string) - newenv = os.environ.copy() - newenv["FRUIT"] = "apple" - p = subprocess.Popen("echo $FRUIT", shell=1, - stdout=subprocess.PIPE, - env=newenv) - self.assertEqual(p.stdout.read().strip(), "apple") - - def test_call_string(self): - # call() function with string argument on UNIX - f, fname = self.mkstemp() - os.write(f, "#!/bin/sh\n") - os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % - sys.executable) - os.close(f) - os.chmod(fname, 0700) - rc = subprocess.call(fname) - self.assertEqual(rc, 47) - - - # - # Windows tests - # - if mswindows: - def test_startupinfo(self): - # startupinfo argument - # We uses hardcoded constants, because we do not want to - # depend on win32all. - STARTF_USESHOWWINDOW = 1 - SW_MAXIMIZE = 3 - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags = STARTF_USESHOWWINDOW - startupinfo.wShowWindow = SW_MAXIMIZE - # Since Python is a console process, it won't be affected - # by wShowWindow, but the argument should be silently - # ignored - subprocess.call([sys.executable, "-c", "import sys; sys.exit(0)"], - startupinfo=startupinfo) - - def test_creationflags(self): - # creationflags argument - CREATE_NEW_CONSOLE = 16 - sys.stderr.write(" a DOS box should flash briefly ...\n") - subprocess.call(sys.executable + - ' -c "import time; time.sleep(0.25)"', - creationflags=CREATE_NEW_CONSOLE) - - def test_invalid_args(self): - # invalid arguments should raise ValueError - self.assertRaises(ValueError, subprocess.call, - [sys.executable, - "-c", "import sys; sys.exit(47)"], - preexec_fn=lambda: 1) - self.assertRaises(ValueError, subprocess.call, - [sys.executable, - "-c", "import sys; sys.exit(47)"], - close_fds=True) - - def test_shell_sequence(self): - # Run command through the shell (sequence) - newenv = os.environ.copy() - newenv["FRUIT"] = "physalis" - p = subprocess.Popen(["set"], shell=1, - stdout=subprocess.PIPE, - env=newenv) - self.assertNotEqual(p.stdout.read().find("physalis"), -1) - - def test_shell_string(self): - # Run command through the shell (string) - newenv = os.environ.copy() - newenv["FRUIT"] = "physalis" - p = subprocess.Popen("set", shell=1, - stdout=subprocess.PIPE, - env=newenv) - self.assertNotEqual(p.stdout.read().find("physalis"), -1) - - def test_call_string(self): - # call() function with string argument on Windows - rc = subprocess.call(sys.executable + - ' -c "import sys; sys.exit(47)"') - self.assertEqual(rc, 47) - - -#def test_main(): -# test_support.run_unittest(ProcessTestCase) -# -#if __name__ == "__main__": -# test_main() Added: py/dist/py/path/local/popen5/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/path/local/popen5/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Deleted: /py/dist/py/path/local/test_local.py ============================================================================== --- /py/dist/py/path/local/test_local.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,199 +0,0 @@ -import py -from py.path import local, checker -from py.__impl__.path.test.fscommon import CommonFSTests, setuptestfs - -class LocalSetup: - def setup_class(cls): - cls.root = py.test.config.tmpdir / 'TestLocalPath' - cls.root.ensure(dir=1) - setuptestfs(cls.root) - - def setup_method(self, method): - self.tmpdir = self.root.ensure('tmpdir', dir=1) - - def teardown_method(self, method): - self.tmpdir.remove(rec=1) - -class TestLocalPath(LocalSetup, CommonFSTests): - def test_initialize_curdir(self): - assert str(local()) == py.std.os.getcwd() - - def test_initialize_reldir(self): - curdir = py.std.os.curdir - try: - py.std.os.chdir(str(self.root)) - p = local('samplefile') - assert p.check() - finally: - py.std.os.chdir(curdir) - - def test_eq_with_strings(self): - path1 = self.root.join('sampledir') - path2 = str(path1) - assert path1 == path2 - assert path2 == path1 - path3 = self.root.join('samplefile') - assert path3 != path2 - assert path2 != path3 - - def test_dump(self): - import tempfile - try: - fd, name = tempfile.mkstemp() - f = py.std.os.fdopen(fd) - except AttributeError: - name = tempfile.mktemp() - f = open(name, 'w+') - try: - d = {'answer' : 42} - path = local(name) - path.dumpobj(d) - from cPickle import load - dnew = load(f) - assert d == dnew - finally: - f.close() - py.std.os.remove(name) - - def test_setmtime(self): - import tempfile - import time - try: - fd, name = tempfile.mkstemp() - py.std.os.close(fd) - except AttributeError: - name = tempfile.mktemp() - open(name, 'w').close() - try: - mtime = int(time.time())-100 - path = local(name) - assert path.mtime() != mtime - path.setmtime(mtime) - assert path.mtime() == mtime - path.setmtime() - assert path.mtime() != mtime - finally: - py.std.os.remove(name) - - def test_normpath(self): - new1 = self.root.join("/otherdir") - new2 = self.root.join("otherdir") - assert str(new1) == str(new2) - - def test_mkdtemp_creation(self): - d = local.mkdtemp() - try: - assert d.check(dir=1) - finally: - d.remove(rec=1) - - def test_tmproot(self): - d = local.mkdtemp() - tmproot = local.get_temproot() - try: - assert d.check(dir=1) - assert d.dirpath() == tmproot - finally: - d.remove(rec=1) - - def test_chdir(self): - tmpdir = self.tmpdir.realpath() - old = local() - try: - res = tmpdir.chdir() - assert str(res) == str(old) - assert py.std.os.getcwd() == str(tmpdir) - finally: - old.chdir() - - def test_ensure_filepath_withdir(self): - tmpdir = self.tmpdir - newfile = tmpdir.join('test1','test2') - newfile.ensure() - assert newfile.check(file=1) - - def test_ensure_filepath_withoutdir(self): - tmpdir = self.tmpdir - newfile = tmpdir.join('test1') - t = newfile.ensure() - assert t == newfile - assert newfile.check(file=1) - - def test_ensure_dirpath(self): - tmpdir = self.tmpdir - newfile = tmpdir.join('test1','test2') - t = newfile.ensure(dir=1) - assert t == newfile - assert newfile.check(dir=1) - -class TestExecution(LocalSetup): - disabled = py.std.sys.platform == 'win32' - - def test_sysfind(self): - x = py.path.local.sysfind('test') - assert x.check(file=1) - py.test.raises(py.error.ENOENT, """ - py.path.local.sysfind('jaksdkasldqwe') - """) - - def test_sysfind_multiple(self): - dir = py.test.config.tmpdir.ensure('sysfind', dir=1) - env = py.std.os.environ - oldpath = env['PATH'] - try: - env['PATH'] += ":%s:%s" % (dir.ensure('a'), - dir.join('b')) - dir.ensure('b', 'a') - checker = lambda x: x.dirpath().basename == 'b' - x = py.path.local.sysfind('a', checker=checker) - assert x.basename == 'a' - assert x.dirpath().basename == 'b' - checker = lambda x: None - py.test.raises(py.error.ENOENT, """ - py.path.local.sysfind('a', checker=checker) - """) - finally: - env['PATH'] = oldpath - #dir.remove() - - def test_sysexec(self): - x = py.path.local.sysfind('ls') - out = x.sysexec() - for x in py.path.local(): - assert out.find(x.basename) != -1 - - def test_sysexec_failing(self): - x = py.path.local.sysfind('false') - py.test.raises(py.process.cmdexec.Error, """ - x.sysexec('aksjdkasjd') - """) - - def test_make_numbered_dir(self): - root = self.tmpdir - for i in range(10): - numdir = local.make_numbered_dir(root, 'base.', keep=2) - assert numdir.check() - assert numdir.basename == 'base.%d' %i - if i>=1: - assert numdir.new(ext=str(i-1)).check() - if i>=2: - assert numdir.new(ext=str(i-2)).check() - if i>=3: - assert not numdir.new(ext=str(i-3)).check() - - def test_error_preservation(self): - py.test.raises (EnvironmentError, self.root.join('qwoeqiwe').mtime) - py.test.raises (EnvironmentError, self.root.join('qwoeqiwe').read) - - #def test_parentdirmatch(self): - # local.parentdirmatch('std', startmodule=__name__) - -#class XTestLocalPath(TestLocalPath): -# def __init__(self): -# TestLocalPath.__init__(self) -# self.root = local(self.root) -# -#class XXTestLocalPath(TestLocalPath): -# def __init__(self): -# TestLocalPath.__init__(self) -# self.root = local(self.root) Deleted: /py/dist/py/path/local/test_posix.py ============================================================================== --- /py/dist/py/path/local/test_posix.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,178 +0,0 @@ -import py -import sys -from py.__impl__.path.test.fscommon import setuptestfs -checker = py.path.checker -local = py.path.local - -class TestPOSIXLocalPath: - #root = local(TestLocalPath.root) - disabled = sys.platform == 'win32' - - def setup_class(cls): - cls.root = py.test.config.tmpdir / 'TestPosixLocalPath' - cls.root.ensure(dir=1) - setuptestfs(cls.root) - - def test_hardlink(self): - tmpdir = local(local.mkdtemp()) - try: - linkpath = tmpdir.join('test') - filepath = tmpdir.join('file') - filepath.write("Hello") - linkpath.mklinkto(filepath) - assert filepath.read() == linkpath.read() - finally: - tmpdir.remove(rec=1) - - def test_symlink_are_identical(self): - tmpdir = local(local.mkdtemp()) - try: - filepath = tmpdir.join('file') - filepath.write("Hello") - linkpath = tmpdir.join('test') - linkpath.mksymlinkto(filepath) - assert filepath.read() == linkpath.read() - finally: - tmpdir.remove(rec=1) - - def test_symlink_isfile(self): - tmpdir = local(local.mkdtemp()) - try: - linkpath = tmpdir.join('test') - filepath = tmpdir.join('file') - filepath.write("") - linkpath.mksymlinkto(filepath) - assert linkpath.check(file=1) - assert not linkpath.check(link=0, file=1) - finally: - tmpdir.remove(rec=1) - - def test_symlink_relative(self): - tmpdir = local(local.mkdtemp()) - try: - linkpath = tmpdir.join('test') - filepath = tmpdir.join('file') - filepath.write("Hello") - linkpath.mksymlinkto(filepath, absolute=False) - assert linkpath.readlink() == "file" - assert filepath.read() == linkpath.read() - finally: - tmpdir.remove(rec=1) - - def test_relto_with_root(self): - y = self.root.join('x').relto(py.path.local('/')) - assert y[0] == str(self.root)[1] - - def test_visit_recursive_symlink(self): - tmpdir = local.mkdtemp() - try: - linkpath = tmpdir.join('test') - linkpath.mksymlinkto(tmpdir) - visitor = tmpdir.visit(None, checker(link=0)) - assert list(visitor) == [linkpath] - #check.equal(list(tmpdir.visit()), [linkpath]) - finally: - tmpdir.remove(rec=1) - - def test_symlink_isdir(self): - tmpdir = local.mkdtemp() - try: - linkpath = tmpdir.join('test') - linkpath.mksymlinkto(tmpdir) - assert linkpath.check(dir=1) - assert not linkpath.check(link=0, dir=1) - finally: - tmpdir.remove(rec=1) - - def test_symlink_remove(self): - tmpdir = local.mkdtemp().realpath() - try: - linkpath = tmpdir.join('test') - linkpath.mksymlinkto(linkpath) # point to itself - assert linkpath.check(link=1) - linkpath.remove() - assert not linkpath.check() - finally: - tmpdir.remove(rec=1) - - def test_realpath_file(self): - tmpdir = local.mkdtemp() - try: - linkpath = tmpdir.join('test') - filepath = tmpdir.join('file') - filepath.write("") - linkpath.mksymlinkto(filepath) - realpath = linkpath.realpath() - assert realpath.basename == 'file' - finally: - tmpdir.remove(rec=1) - - 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() - - def XXXtest_atime(self): - # XXX disabled. this test is just not platform independent enough - # because acesstime resolution is very different through - # filesystems even on one platform. - import time - path = self.root.join('samplefile') - atime = path.atime() - time.sleep(1) - path.read(1) - assert path.atime() != atime - - def testcommondir(self): - # XXX This is here in local until we find a way to implement this - # using the subversion command line api. - p1 = self.root.join('something') - p2 = self.root.join('otherthing') - assert p1.commondir(p2) == self.root - assert p2.commondir(p1) == self.root - - def testcommondir_nocommon(self): - # XXX This is here in local until we find a way to implement this - # using the subversion command line api. - p1 = self.root.join('something') - p2 = local(os.sep+'blabla') - assert p1.commondir(p2) is None - - - def test_chmod_simple_int(self): - print "self.root is", self.root - mode = self.root.mode() - self.root.chmod(mode/2) - try: - assert self.root.mode() != mode - finally: - self.root.chmod(mode) - assert self.root.mode() == mode - - def test_chmod_rec_int(self): - # XXX fragile test - print "self.root is", self.root - recfilter = checker(dotfile=0) - oldmodes = {} - for x in self.root.visit(rec=recfilter): - oldmodes[x] = x.mode() - self.root.chmod(0772, rec=1) - try: - for x in self.root.visit(rec=recfilter): - assert x.mode() & 0777 == 0772 - finally: - for x,y in oldmodes.items(): - x.chmod(y) - - def test_chown_identity(self): - owner = self.root.owner() - group = self.root.group() - self.root.chown(owner, group) - - def test_chown_identity_rec_mayfail(self): - owner = self.root.owner() - group = self.root.group() - self.root.chown(owner, group) Added: py/dist/py/path/local/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/path/local/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Deleted: /py/dist/py/path/svn/svntestbase.py ============================================================================== --- /py/dist/py/path/svn/svntestbase.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,107 +0,0 @@ -import py -from py import path, test, process -from py.__impl__.path.test.fscommon import CommonFSTests -from py.__impl__.path.svn import cache - -class CommonSvnTests(CommonFSTests): - - def setup_method(self, meth): - bn = meth.func_name - for x in 'test_remove', 'test_move': - if bn.startswith(x): - py.test.skip( - "tests for modifying svn needs better test state management") - - def test_propget(self): - url = self.root.join("samplefile") - value = url.propget('svn:eol-style') - assert value == 'native' - - def test_proplist(self): - url = self.root.join("samplefile") - res = url.proplist() - assert res['svn:eol-style'] == 'native' - - def test_info(self): - url = self.root.join("samplefile") - res = url.info() - assert res.size > len("samplefile") and res.created_rev >= 0 - - def xxxtest_info_log(self): - url = self.root.join("samplefile") - res = url.log(rev_start=1155, rev_end=1155, verbose=True) - assert res[0].revision == 1155 and res[0].author == "jum" - from time import gmtime - t = gmtime(res[0].date) - assert t.tm_year == 2003 and t.tm_mon == 7 and t.tm_mday == 17 - -class CommonCommandAndBindingTests(CommonSvnTests): - def test_trailing_slash_is_stripped(self): - # XXX we need to test more normalizing properties - url = self.root.join("/") - assert self.root == url - - #def test_different_revs_compare_unequal(self): - # newpath = self.root.new(rev=1199) - # assert newpath != self.root - - def test_exists_svn_root(self): - assert self.root.check() - - #def test_not_exists_rev(self): - # url = self.root.__class__(self.rooturl, rev=500) - # assert url.check(exists=0) - - #def test_nonexisting_listdir_rev(self): - # url = self.root.__class__(self.rooturl, rev=500) - # raises(py.error.ENOENT, url.listdir) - - #def test_newrev(self): - # url = self.root.new(rev=None) - # assert url.rev == None - # assert url.strpath == self.root.strpath - # url = self.root.new(rev=10) - # assert url.rev == 10 - - #def test_info_rev(self): - # url = self.root.__class__(self.rooturl, rev=1155) - # url = url.join("samplefile") - # res = url.info() - # assert res.size > len("samplefile") and res.created_rev == 1155 - - # the following tests are easier if we have a path class - def test_repocache_simple(self): - repocache = cache.RepoCache() - repocache.put(self.root.strpath, 42) - url, rev = repocache.get(self.root.join('test').strpath) - assert rev == 42 - assert url == self.root.strpath - - def test_repocache_notimeout(self): - repocache = cache.RepoCache() - repocache.timeout = 0 - repocache.put(self.root.strpath, self.root.rev) - url, rev = repocache.get(self.root.strpath) - assert rev == -1 - assert url == self.root.strpath - - def test_repocache_outdated(self): - repocache = cache.RepoCache() - repocache.put(self.root.strpath, 42, timestamp=0) - url, rev = repocache.get(self.root.join('test').strpath) - assert rev == -1 - assert url == self.root.strpath - - def _test_getreporev(self): - """ this test runs so slow it's usually disabled """ - old = cache.repositories.repos - try: - _repocache.clear() - root = self.root.new(rev=-1) - url, rev = cache.repocache.get(root.strpath) - assert rev>=0 - assert url == svnrepourl - finally: - repositories.repos = old - -#cache.repositories.put(svnrepourl, 1200, 0) Deleted: /py/dist/py/path/svn/test_urlcommand.py ============================================================================== --- /py/dist/py/path/svn/test_urlcommand.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,23 +0,0 @@ -import sys, os -import py -from svntestbase import CommonCommandAndBindingTests -from test_wccommand import getrepowc - -class TestSvnCommandPath(CommonCommandAndBindingTests): - def __init__(self): - repo, wc = getrepowc() - self.root = py.path.svnurl(repo) - - def xtest_copy_file(self): - raise py.test.Skipped(msg="XXX fix svnurl first") - - def xtest_copy_dir(self): - py.test.skipp("XXX fix svnurl first") - - def XXXtest_info_log(self): - url = self.root.join("samplefile") - res = url.log(rev_start=1155, rev_end=1155, verbose=True) - assert res[0].revision == 1155 and res[0].author == "jum" - from time import gmtime - t = gmtime(res[0].date) - assert t.tm_year == 2003 and t.tm_mon == 7 and t.tm_mday == 17 Deleted: /py/dist/py/path/svn/test_wccommand.py ============================================================================== --- /py/dist/py/path/svn/test_wccommand.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,209 +0,0 @@ -import py -from svntestbase import CommonSvnTests -from py.__impl__.path.test.fscommon import setuptestfs - -# make a wc directory out of a given root url -# cache previously obtained wcs! -# -def getrepowc(): - repo = py.test.config.tmpdir / 'path' / 'repo' - wcdir = py.test.config.tmpdir / 'path' / 'wc' - if not repo.check(): - assert not wcdir.check() - repo.ensure(dir=1) - try: - py.process.cmdexec('svnadmin create %s' % repo) - except py.process.cmdexec.Error: - repo.remove() - raise py.test.skip('could not create temporary svn test repository') - wcdir.ensure(dir=1) - print "created svn repository", repo - wc = py.path.svnwc(wcdir) - wc.checkout(url='file://%s' % repo) - print "checked out new repo into", wc - setuptestfs(wc) - wc.join('samplefile').propset('svn:eol-style', 'native') - wc.commit("testrepo setup rev 1") - wc.ensure('anotherfile').write('hello') - wc.commit('second rev') - wc.join('anotherfile').write('world') - wc.commit('third rev') - else: - print "using repository at %s" % repo - wc = py.path.svnwc(wcdir) - return ("file://%s" % repo, wc) - -class TestWCSvnCommandPath(CommonSvnTests): - def __init__(self): - repo, self.root = getrepowc() - - def test_status_attributes_simple(self): - def assert_nochange(p): - s = p.status() - assert not s.modified - assert not s.prop_modified - assert not s.added - assert not s.deleted - - dpath = self.root.join('sampledir') - assert_nochange(self.root.join('sampledir')) - assert_nochange(self.root.join('samplefile')) - - def test_status_added(self): - nf = self.root.join('newfile') - nf.write('hello') - nf.add() - try: - s = nf.status() - assert s.added - assert not s.modified - assert not s.prop_modified - finally: - nf.revert() - - def test_status_change(self): - nf = self.root.join('samplefile') - try: - nf.write(nf.read() + 'change') - s = nf.status() - assert not s.added - assert s.modified - assert not s.prop_modified - finally: - nf.revert() - - def test_status_added_ondirectory(self): - sampledir = self.root.join('sampledir') - try: - t2 = sampledir.mkdir('t2') - t1 = t2.join('t1') - t1.write('test') - t1.add() - s = sampledir.status(rec=1) - assert t1 in s.added - assert t2 in s.added - finally: - t2.revert(rec=1) - t2.localpath.remove(rec=1) - - def test_status_unknown(self): - t1 = self.root.join('un1') - try: - t1.write('test') - s = self.root.status() - assert t1 in s.unknown - finally: - t1.localpath.remove() - - def test_status_unchanged(self): - r = self.root - s = self.root.status(rec=1) - assert r.join('samplefile') in s.unchanged - assert r.join('sampledir') in s.unchanged - assert r.join('sampledir/otherfile') in s.unchanged - - def test_status_update(self): - r = self.root - try: - r.update(rev=1) - s = r.status(updates=1, rec=1) - assert r.join('anotherfile') in s.update_available - #assert len(s.update_available) == 1 - finally: - r.update() - - def test_diff(self): - p = self.root / 'anotherfile' - out = p.diff(rev=2) - assert out.find('hello') != -1 - - def test_join_abs(self): - s = str(self.root.localpath) - n = self.root.join(s, abs=1) - assert self.root == n - - def test_join_abs2(self): - assert self.root.join('samplefile', abs=1) == self.root.join('samplefile') - - def test_str_gives_localpath(self): - assert str(self.root) == str(self.root.localpath) - - def test_versioned(self): - assert self.root.check(versioned=1) - assert self.root.join('samplefile').check(versioned=1) - assert not self.root.join('notexisting').check(versioned=1) - notexisting = self.root.join('hello').localpath - try: - notexisting.write("") - assert self.root.join('hello').check(versioned=0) - finally: - notexisting.remove() - - def test_properties(self): - try: - self.root.propset('gaga', 'this') - assert self.root.propget('gaga') == 'this' - assert self.root in self.root.status().prop_modified - assert 'gaga' in self.root.proplist() - assert self.root.proplist()['gaga'] == 'this' - - finally: - self.root.propdel('gaga') - - def test_proplist_recursive(self): - s = self.root.join('samplefile') - s.propset('gugu', 'that') - try: - p = self.root.proplist(rec=1) - assert self.root / 'samplefile' in p - finally: - s.propdel('gugu') - - def test_long_properties(self): - value = """ - vadm:posix : root root 0100755 - Properties on 'chroot/dns/var/bind/db.net.xots': - """ - try: - self.root.propset('gaga', value) - backvalue = self.root.propget('gaga') - assert backvalue == value - #assert len(backvalue.split('\n')) == 1 - finally: - self.root.propdel('gaga') - - - def test_ensure(self): - newpath = self.root.ensure('a', 'b', 'c') - try: - assert newpath.check(exists=1, versioned=1) - finally: - self.root.join('a').remove(force=1) - - def test_not_versioned(self): - p = self.root.localpath.mkdir('whatever') - f = self.root.localpath.ensure('testcreatedfile') - try: - assert self.root.join('whatever').check(versioned=0) - assert self.root.join('testcreatedfile').check(versioned=0) - assert not self.root.join('testcreatedfile').check(versioned=1) - finally: - p.remove(rec=1) - f.remove() - - #def test_log(self): - # l = self.root.log() - # assert len(l) == 3 # might need to be upped if more tests are added - -class XTestWCSvnCommandPathSpecial: - - rooturl = 'http://codespeak.net/svn/py.path/trunk/dist/py.path/test/data' - #def test_update_none_rev(self): - # path = tmpdir.join('checkouttest') - # wcpath = newpath(xsvnwc=str(path), url=self.rooturl) - # try: - # wcpath.checkout(rev=2100) - # wcpath.update() - # assert wcpath.info().rev > 2100 - # finally: - # wcpath.localpath.remove(rec=1) Added: py/dist/py/path/svn/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/path/svn/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Modified: py/dist/py/path/test/test_api.py ============================================================================== --- py/dist/py/path/test/test_api.py (original) +++ py/dist/py/path/test/test_api.py Mon Jan 3 13:14:26 2005 @@ -1,5 +1,5 @@ from py import path, test -from py.__impl__.path.svn.test_wccommand import getrepowc +from py.__impl__.path.svn.testing.test_wccommand import getrepowc class TestAPI: def __init__(self): Deleted: /py/dist/py/process/test_cmdexec.py ============================================================================== --- /py/dist/py/process/test_cmdexec.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,25 +0,0 @@ -from py import test -from py.process import cmdexec - -class Test_exec_cmd: - def test_simple(self): - out = cmdexec('echo hallo') - assert out.strip() == 'hallo' - - def test_simple_error(self): - test.raises (cmdexec.Error, cmdexec, 'exit 1') - - def test_simple_error_exact_status(self): - try: - cmdexec('exit 1') - except cmdexec.Error, e: - assert e.status == 1 - - def test_err(self): - try: - cmdexec('echoqweqwe123 hallo') - raise AssertionError, "command succeeded but shouldn't" - except cmdexec.Error, e: - assert hasattr(e, 'err') - assert hasattr(e, 'out') - assert e.err or e.out Added: py/dist/py/process/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/process/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Deleted: /py/dist/py/test/report/test_memo.py ============================================================================== --- /py/dist/py/test/report/test_memo.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,27 +0,0 @@ -import py - -def setup_module(mod): - mod.tmpdir = py.path.local.make_numbered_dir() -def teardown_module(mod): - mod.tmpdir.remove() - del mod.tmpdir - -#def test_equal_should_raise(): -# check.equal(1,2) - -#class MyUnit(collect.Auto, collect.Unit): -# def execute(self, runner): -# try: -# -def test_memoreporter(): - reporter = py.test.MemoReporter() - p = tmpdir.join('memoimport.py') - p.write('raise IOError') - collector = py.test.collect.Module(p) - #main(collector=collector, reporter=reporter) - #collect_errors = reporter.getlist(collect.Error) - #assert len(collect_errors) == 1 - ##print collect_errors - -if __name__=='__main__': - test.main() Added: py/dist/py/test/report/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/test/report/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Deleted: /py/dist/py/test/test_collect.py ============================================================================== --- /py/dist/py/test/test_collect.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,143 +0,0 @@ -from __future__ import generators -import py -from py.__impl__.test import collect -autopath = py.magic.autopath() -testdir = autopath.dirpath('test') -assert testdir.check(dir=1) -datadir = testdir / 'data' - - -def test_failing_import_execfile(): - fn = datadir / 'failingimport.py' - l = list(collect.Module(py.path.extpy(fn))) - assert l - ex, = l - assert issubclass(ex.excinfo.type, ImportError) - -def test_failing_import_directory(): - class MyDirectory(collect.Directory): - fil = py.path.checker(basestarts="testspecial_", ext='.py') - l = list(MyDirectory(datadir)) - assert len(l) == 1 - assert isinstance(l[0], collect.Module) - l2 = list(l[0]) - assert l2 - exc = l2[0] - assert isinstance(exc, collect.Error) - assert issubclass(exc.excinfo.type, ImportError) - -def test_module_file_not_found(): - fn = testdir.join('nada','no') - l = list(collect.Module(fn)) - assert len(l) == 1 - assert isinstance(l[0], collect.Error) - assert isinstance(l[0].excinfo.value, py.error.ENOENT) - -def test_syntax_error_in_module(): - modpath = py.path.extpy(datadir.join('syntax_error.py')) - l2 = list(collect.Module(modpath)) - assert len(l2) == 1 - assert isinstance(l2[0], collect.Error) - assert issubclass(l2[0].excinfo.type, SyntaxError) - -def test_disabled_class(): - extpy = py.path.extpy(datadir.join('disabled.py')) - l = list(collect.Class(extpy)) - assert len(l) == 0 - -class TestCustomCollector: - def test_custom_collect(self): - l = list(collect.Module(datadir.join('Collector.py'))) - for item in l: - assert isinstance(item, py.test.Item) - assert len(l) == 3 - #for x in l2: - # assert isinstance(x, Unit) - # x.execute() - -class Testsomeclass: - disabled = True - def test_something(): - raise ValueError - -l = [] -def test_1(): - l.append(1) -def test_2(): - l.append(2) -def test_3(): - assert l == [1,2] -class Testmygroup: - reslist = [] - def test_1(self): - self.reslist.append(1) - def test_2(self): - self.reslist.append(2) - def test_3(self): - self.reslist.append(3) - def test_4(self): - assert self.reslist == [1,2,3] - -# -# some tests related to "generating tests" -# -l2=[] - -def func1(): - print "in func1" - l2.append(1) - -def func2(i): - print "in func2 with param %d" % i - l2.append(i) - -def test_generator(): - yield func1 - yield func2, 2 - yield func2, 3 - -def test_stateful_previous(): - x = l2 - assert x == [1,2,3] - -class TestGeneratorMethod: - l3 = [] - def func1(self, i): - self.l3.append(i) - - def test_generator(self): - yield self.func1, 4 - yield self.func1, 5 - - def test_previous_generator_worked(self): - assert self.l3 == [4,5] - -def test_custom_collection_from_conftest(): - o = py.test.config.tmpdir.ensure('customconfigtest', dir=1) - o.ensure('conftest.py').write("""if 1: - import py - class MyItem(py.test.Item): - pass - class Directory(py.test.collect.Directory): - def fil(self, fspath): - return fspath.check(basestarts='check_') - class Module(py.test.collect.Module): - def collect_function(self, extpy): - if extpy.check(basestarts='check_', func=1): - yield self.Item(extpy) - class Class(py.test.collect.Class): - def collect_method(self, extpy): - if extpy.check(basestarts='check_', func=1): - yield MyItem(extpy) - """) - o.ensure('somedir', 'check_something').write("""if 1: - def check_func(): - assert 42 == 42 - class TestClass: - def check_method(self): - assert 23 == 23 - """) - from py.__impl__.test.collect import getfscollector - units = list(getfscollector(o).iterunits()) - assert len(units) == 2 - assert units[1].__class__.__name__ == 'MyItem' Deleted: /py/dist/py/test/test_compat.py ============================================================================== --- /py/dist/py/test/test_compat.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,51 +0,0 @@ -from __future__ import generators -import py - -class TestCompatTestCaseSetupSemantics(py.test.compat.TestCase): - globlist = [] - - def setUp(self): - self.__dict__.setdefault('l', []).append(42) - self.globlist.append(self) - - def tearDown(self): - self.l.pop() - - def test_issetup(self): - l = self.l - assert len(l) == 1 - assert l[-1] == 42 - self.checkmultipleinstances() - - def test_issetup2(self): - l = self.l - assert len(l) == 1 - assert l[-1] == 42 - self.checkmultipleinstances() - - def checkmultipleinstances(self): - for x,y in zip(self.globlist, self.globlist[1:]): - assert x is not y - -class TestCompatAssertions(py.test.compat.TestCase): - nameparamdef = { - 'failUnlessEqual,assertEqual,assertEquals': ('1, 1', '1, 0'), - 'assertNotEquals,failIfEqual': ('0, 1', '0,0'), - 'failUnless,assert_': ('1', 'None'), - 'failIf': ('0', '1'), - } - - sourcelist = [] - for names, (paramok, paramfail) in nameparamdef.items(): - for name in names.split(','): - source = """ - def test_%(name)s(self): - self.%(name)s(%(paramok)s) - #self.%(name)s(%(paramfail)s) - - def test_%(name)s_failing(self): - self.assertRaises(py.test.Item.Failed, - self.%(name)s, %(paramfail)s) - """ % locals() - co = py.code.Source(source).compile() - exec co Deleted: /py/dist/py/test/test_config.py ============================================================================== --- /py/dist/py/test/test_config.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,52 +0,0 @@ -from __future__ import generators -import py -config = py.test.config - -class MyClass: - def getoptions(self): - yield config.Option('-v', action="count", dest="verbose", help="verbose") - -def xtest_verbose(): - obj = MyClass() - args = config.parseargs(['-v', 'hello'], obj) - assert args == ['hello'] - assert hasattr(obj, 'option') - assert hasattr(obj.option, 'verbose') - assert obj.option.verbose - -def xtest_verbose_default(): - obj = MyClass() - args = config.parseargs(['hello'], obj) - assert args, ['hello'] - assert hasattr(obj, 'option') - assert hasattr(obj.option, 'verbose') - assert not obj.option.verbose - -def test_tmpdir(): - d1 = config.tmpdir - d2 = config.tmpdir - assert d1 == d2 - -def test_config_order(): - from py.__impl__.test import config - o = py.test.config.tmpdir.ensure('configorder', dir=1) - o.ensure('conftest.py').write('x=1 ; import py ; py._x = [x]') - o.ensure('a/conftest.py').write('x=2 ; import py ; py._x.append(x)') - o.ensure('a/b/c/conftest.py').write('x=3 ; import py ; py._x.append(x)') - cfg = config.Config() - cfg.readconfiguration(o) - assert cfg.getfirst('x') == 1 - assert py._x == [1] - - cfg = config.Config() - cfg.readconfiguration(o.join('a/b/c')) - assert cfg.getfirst('x') == 1 - assert py._x == [1,2,3] - -def test_getconfigvalue(): - from py.__impl__.test import config - cfg = config.Config() - o = py.test.config.tmpdir.ensure('configtest', dir=1) - o.ensure('conftest.py').write('x=1') - assert cfg.getconfigvalue(o, 'x') == 1 - py.test.raises(ValueError, "cfg.getconfigvalue(o, 'y')") Deleted: /py/dist/py/test/test_raises.py ============================================================================== --- /py/dist/py/test/test_raises.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,14 +0,0 @@ -from py import test - -def somefunc(x, y): - assert x == y - -class TestClass: - def test_raises(self): - test.raises(ValueError, "int('qwe')") - - def test_raises_syntax_error(self): - test.raises(SyntaxError, "qwe qwe qwe") - - def test_raises_function(self): - test.raises(ValueError, int, 'hello') Added: py/dist/py/test/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/test/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file Deleted: /py/dist/py/test/tool/test_outerrcapture.py ============================================================================== --- /py/dist/py/test/tool/test_outerrcapture.py Mon Jan 3 13:14:26 2005 +++ (empty file) @@ -1,24 +0,0 @@ -import sys -from py import test -from py.__impl__.test.tool.outerrcapture import SimpleOutErrCapture - -def test_capturing_simple(): - cap = SimpleOutErrCapture() - print "hello world" - print >>sys.stderr, "hello error" - out, err = cap.reset() - assert out == "hello world\n" - assert err == "hello error\n" - -def test_capturing_error(): - cap = SimpleOutErrCapture() - print "hello" - cap.reset() - test.raises(AttributeError, "cap.reset()") - -def test_capturing_error_recursive(): - cap = SimpleOutErrCapture() - cap2 = SimpleOutErrCapture() - print "hello" - cap2.reset() - test.raises(AttributeError, "cap2.reset()") Added: py/dist/py/test/tool/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/test/tool/testing/__init__.py Mon Jan 3 13:14:26 2005 @@ -0,0 +1 @@ +# \ No newline at end of file From hpk at codespeak.net Mon Jan 3 13:19:09 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 13:19:09 +0100 (MET) Subject: [py-svn] r8049 - in py/dist/py/documentation: . example/pytest example/testing testing Message-ID: <20050103121909.7D91E5AB03@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 13:19:09 2005 New Revision: 8049 Added: py/dist/py/documentation/example/pytest/ - copied from r8048, py/dist/py/documentation/example/testing/ py/dist/py/documentation/rest_test.py - copied, changed from r8048, py/dist/py/documentation/testing/rest_test.py Removed: py/dist/py/documentation/example/testing/ py/dist/py/documentation/testing/ Modified: py/dist/py/documentation/test.txt Log: (of course) fixed accidental changes in the documentation directory. Copied: py/dist/py/documentation/rest_test.py (from r8048, py/dist/py/documentation/testing/rest_test.py) ============================================================================== --- py/dist/py/documentation/testing/rest_test.py (original) +++ py/dist/py/documentation/rest_test.py Mon Jan 3 13:19:09 2005 @@ -11,5 +11,9 @@ #assert not out def test_rest_files(): + try: + import docutils + except ImportError: + py.test.skip("docutils not importable") for x in docdir.listdir('*.txt'): yield restcheck, x Modified: py/dist/py/documentation/test.txt ============================================================================== --- py/dist/py/documentation/test.txt (original) +++ py/dist/py/documentation/test.txt Mon Jan 3 13:19:09 2005 @@ -157,7 +157,7 @@ A lot of care is taken to present nice tracebacks in case of test failure. Try:: - py.test py/documentation/example/test/failure_demo.py + py.test py/documentation/example/pytest/failure_demo.py to see a variety of 17 tracebacks, each tailored to a different failure situation. @@ -259,7 +259,7 @@ Here is a working example for what goes on when you setup modules, classes and methods:: - # [[from py/documentation/example/test/test_setup_flow_example.py]] + # [[from py/documentation/example/pytest/test_setup_flow_example.py]] def setup_module(module): module.TestStateFullThing.classcount = 0 From hpk at codespeak.net Mon Jan 3 18:11:33 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 18:11:33 +0100 (MET) Subject: [py-svn] r8052 - py/dist/py/execnet Message-ID: <20050103171133.EAD4A5AEB0@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 18:11:33 2005 New Revision: 8052 Modified: py/dist/py/execnet/register.py Log: only mirror PYTHONPATH because transmitting sys.path across python versions is, um, dubious. Modified: py/dist/py/execnet/register.py ============================================================================== --- py/dist/py/execnet/register.py (original) +++ py/dist/py/execnet/register.py Mon Jan 3 18:11:33 2005 @@ -70,7 +70,8 @@ # of the py lib, but only works for PopenGateways # --> we need proper remote imports working # across any kind of gateway! - s = "import sys ; sys.path[:] = %r" % (sys.path,) + plist = os.environ['PYTHONPATH'].split(':') + s = "import sys ; sys.path[:0] = %r" % (plist,) s = "\n".join([extra, s]) super(PopenGateway, self).remote_bootstrap_gateway(io, s) From hpk at codespeak.net Mon Jan 3 18:12:29 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 18:12:29 +0100 (MET) Subject: [py-svn] r8053 - py/dist/py/code Message-ID: <20050103171229.DD81B5AEB0@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 18:12:29 2005 New Revision: 8053 Modified: py/dist/py/code/excinfo.py py/dist/py/code/source.py Log: python2.2 fixes Modified: py/dist/py/code/excinfo.py ============================================================================== --- py/dist/py/code/excinfo.py (original) +++ py/dist/py/code/excinfo.py Mon Jan 3 18:12:29 2005 @@ -1,3 +1,4 @@ +from __future__ import generators import sys import py Modified: py/dist/py/code/source.py ============================================================================== --- py/dist/py/code/source.py (original) +++ py/dist/py/code/source.py Mon Jan 3 18:12:29 2005 @@ -23,12 +23,15 @@ lines.extend(partlines) def __getitem__(self, key): - if isinstance(key, slice): - newsource = Source() - newsource.lines = self.lines[key] - return newsource - else: + if isinstance(key, int): return self.lines[key] + else: + return self.__getslice__(key) + + def __getslice__(self, start, end): + newsource = Source() + newsource.lines = self.lines[start:end] + return newsource def strip(self): """ return new source object with trailing @@ -127,7 +130,7 @@ else: source = str(self) try: - parser.suite(source) + parser.suite(source+'\n') except (parser.ParserError, SyntaxError): return False else: From hpk at codespeak.net Mon Jan 3 18:13:03 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 18:13:03 +0100 (MET) Subject: [py-svn] r8054 - py/dist/py/builtin/testing Message-ID: <20050103171303.C64905AEB0@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 18:13:03 2005 New Revision: 8054 Modified: py/dist/py/builtin/testing/test_enumerate.py Log: test enumerate across all python versions Modified: py/dist/py/builtin/testing/test_enumerate.py ============================================================================== --- py/dist/py/builtin/testing/test_enumerate.py (original) +++ py/dist/py/builtin/testing/test_enumerate.py Mon Jan 3 18:13:03 2005 @@ -1,7 +1,7 @@ import sys +import py -if sys.version_info < (2,3,0): - def test_enumerate(self): - l = [0,1,2] - for i,x in enumerate(l): - assert i == x +def test_enumerate(): + l = [0,1,2] + for i,x in py.builtin.enumerate(l): + assert i == x From hpk at codespeak.net Mon Jan 3 18:16:44 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 18:16:44 +0100 (MET) Subject: [py-svn] r8055 - in py/dist/py: . bin documentation path/local Message-ID: <20050103171644.1668E5AEB0@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 18:16:43 2005 New Revision: 8055 Modified: py/dist/py/bin/py.rest py/dist/py/documentation/rest_test.py py/dist/py/initpkg.py py/dist/py/path/local/local.py Log: some more cross-version and dependency detection fixes Modified: py/dist/py/bin/py.rest ============================================================================== --- py/dist/py/bin/py.rest (original) +++ py/dist/py/bin/py.rest Mon Jan 3 18:16:43 2005 @@ -14,7 +14,7 @@ import sys, os, traceback -if os.isatty(sys.stdout.fileno()): +if hasattr(sys.stdout, 'fileno') and os.isatty(sys.stdout.fileno()): def log(msg): print msg else: Modified: py/dist/py/documentation/rest_test.py ============================================================================== --- py/dist/py/documentation/rest_test.py (original) +++ py/dist/py/documentation/rest_test.py Mon Jan 3 18:16:43 2005 @@ -7,13 +7,13 @@ docdir = py.path.svnwc(pydir.join('documentation')) def restcheck(path): - rest.process(path) - #assert not out - -def test_rest_files(): try: import docutils except ImportError: py.test.skip("docutils not importable") + rest.process(path) + #assert not out + +def test_rest_files(): for x in docdir.listdir('*.txt'): yield restcheck, x Modified: py/dist/py/initpkg.py ============================================================================== --- py/dist/py/initpkg.py (original) +++ py/dist/py/initpkg.py Mon Jan 3 18:16:43 2005 @@ -23,6 +23,7 @@ """ from __future__ import generators import sys +assert sys.version_info >= (2,2,0), "py lib requires python 2.2 or higher" ModuleType = type(sys.modules[__name__]) Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Mon Jan 3 18:16:43 2005 @@ -5,6 +5,7 @@ and so on that may only make sense on unix. """ +from __future__ import generators import sys, os, stat import py from py.__impl__.path import common @@ -359,7 +360,7 @@ except py.error.Error: pass s = self.read(mode='rU') + '\n' - codeobj = compile(s, str(self), 'exec') + codeobj = compile(s, str(self), 'exec', generators.compiler_flag) if dotpy: try: f = pycfile.open('wb') @@ -405,7 +406,7 @@ if not checker(p): continue return p - raise py.error.ENOENT(self) + raise py.error.ENOENT(name) sysfind = classmethod(sysfind) #""" #special class constructors for local filesystem paths @@ -526,11 +527,15 @@ lastdir = dirpath.chdir() try: modname = cfile.purebasename + lib = py.path.local(modname+'.so') + # argl! we need better "build"-locations alltogether! + if lib.check(): + lib.remove() c = stdoutcapture.Capture(mixed_out_err = True) try: try: setup( - name = "testmodules", + name = "pylibmodules", ext_modules=[ Extension(modname, [str(cfile)]) ], From hpk at codespeak.net Mon Jan 3 18:24:38 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 18:24:38 +0100 (MET) Subject: [py-svn] r8056 - in py/dist/py/test: . report/text Message-ID: <20050103172438.C57885B0EF@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 18:24:37 2005 New Revision: 8056 Modified: py/dist/py/test/cmdline.py py/dist/py/test/config.py py/dist/py/test/defaultconfig.py py/dist/py/test/report/text/reporter.py py/dist/py/test/run.py Log: a new option "--exec" which allows to specify an alternate python executable. If specified, tests will run in a child process (which is pretty stable but probably not completly). Modified: py/dist/py/test/cmdline.py ============================================================================== --- py/dist/py/test/cmdline.py (original) +++ py/dist/py/test/cmdline.py Mon Jan 3 18:24:37 2005 @@ -24,8 +24,9 @@ filenames = py.test.config.parseargs(args) if not filenames: filenames.append(str(py.path.local())) + option = py.test.config.option try: - if py.test.config.option.session: + if option.session or option.executable: run.session(args, filenames) else: run.inprocess(args, filenames) Modified: py/dist/py/test/config.py ============================================================================== --- py/dist/py/test/config.py (original) +++ py/dist/py/test/config.py Mon Jan 3 18:24:37 2005 @@ -29,13 +29,16 @@ def readconfiguration(self, *anchors): """ read configuration files left-to-right for the given anchor file. """ self.configpaths = [] + d = {} for anchor in anchors: for p in anchor.parts(): x = p.join(configbasename) if x.check(file=1): extpy = py.path.extpy(x) extpy.resolve() # trigger loading it - self.configpaths.append(extpy) + if extpy not in d: + self.configpaths.append(extpy) + d[extpy] = True self.configpaths.sort(lambda x,y: cmp(len(str(x)), len(str(y)))) self.configpaths.append(defaultconfig) @@ -87,7 +90,7 @@ # parse cmdline args cmdlineoption, remaining = parser.parse_args(args, self.option) - self.checkoptions() + self.fixoptions() # override previously computed defaults #for name in cmdlineoption.__dict__: # if not name.startswith('_'): @@ -96,9 +99,19 @@ return remaining - def checkoptions(self): + def fixoptions(self): if self.option.session and self.option.usepdb: raise ValueError, "--session together with --pdb not supported yet." + if self.option.executable and self.option.usepdb: + raise ValueError, "--exec together with --pdb not supported yet." + + # setting a correct executable + if self.option.executable is not None: + exe = py.path.local(py.std.os.path.expanduser(self.option.executable)) + if not exe.check(): + exe = py.path.local.sysfind(self.option.executable) + assert exe.check() + self.option.executable = exe config = Config() Modified: py/dist/py/test/defaultconfig.py ============================================================================== --- py/dist/py/test/defaultconfig.py (original) +++ py/dist/py/test/defaultconfig.py Mon Jan 3 18:24:37 2005 @@ -23,6 +23,9 @@ Option('-l', '--showlocals', action="store_true", dest="showlocals", default=False, help="show locals in tracebacks (disabled by default)"), + Option('', '--exec', + action="store", dest="executable", default=None, + help="python executable to run the tests with. "), Option('', '--session', action="store_true", dest="session", default=False, help="run a test session/rerun only failing tests. "), Modified: py/dist/py/test/report/text/reporter.py ============================================================================== --- py/dist/py/test/report/text/reporter.py (original) +++ py/dist/py/test/report/text/reporter.py Mon Jan 3 18:24:37 2005 @@ -34,8 +34,13 @@ def start(self): self.out.sep("=", "test process starts") - mode = py.test.config.option.session and \ - 'session/child process' or 'inprocess' + option = py.test.config.option + if option.session: + mode = 'session/child process' + elif option.executable: + mode = 'child process' + else: + mode = 'inprocess' self.out.line("testing-mode: %s" % mode) self.out.line("executable : %s (%s)" % (py.std.sys.executable, repr_pythonversion())) Modified: py/dist/py/test/run.py ============================================================================== --- py/dist/py/test/run.py (original) +++ py/dist/py/test/run.py Mon Jan 3 18:24:37 2005 @@ -64,7 +64,7 @@ while 1: try: channel.waitclose(0.1) - except py.error.Error: + except (IOError, py.error.Error): continue else: failures = channel.receive() @@ -76,7 +76,8 @@ channel.gateway.exit() def failure_master(args, filenames, failures): - gw = py.execnet.PopenGateway() + exe = py.test.config.option.executable + gw = py.execnet.PopenGateway(python=exe or sys.executable) outproxy = StdouterrProxy(gw) outproxy.setup() try: @@ -84,21 +85,22 @@ from py.__impl__.test.run import failure_slave failure_slave(channel) """) - channel.send((args, filenames)) - channel.send(failures) + channel.send((args, filenames, failures)) return waitfinish(channel) finally: outproxy.teardown() def failure_slave(channel): """ we run this on the other side. """ - args, filenames = channel.receive() + args, filenames, failures = channel.receive() filenames = map(py.path.local, filenames) py.test.config.readconfiguration(*filenames) py.test.config.parseargs(args) - failures = channel.receive() - col = FailureCollector(failures) + if failures: + col = FailureCollector(failures) + else: + col = list(getcollectors(filenames)) driver = py.test.Driver(channel) failures = driver.run(col) channel.send(failures) @@ -111,32 +113,6 @@ extpy = py.path.extpy(root, modpath) yield self.Item(extpy) -def master(args, filenames): - gw = py.execnet.PopenGateway() - outproxy = StdouterrProxy(gw) - outproxy.setup() - try: - channel = gw.remote_exec(""" - from py.__impl__.test.run import slave - slave(channel) - """) - channel.send((args, filenames)) - return waitfinish(channel) - finally: - outproxy.teardown() - -def slave(channel): - """ we run this on the other side. """ - args, filenames = channel.receive() - filenames = map(py.path.local, filenames) - py.test.config.readconfiguration(*filenames) - py.test.config.parseargs(args) - fncollectors = list(getcollectors(filenames)) - - driver = py.test.Driver(channel) - failures = driver.run(fncollectors) - channel.send(failures) - def getcollectors(filenames): current = py.path.local() for fn in filenames: @@ -166,16 +142,18 @@ def session(args, filenames): statcache = {} - failures = [] + # XXX find out rootdir automatically with + # something like py.magic.autopath() ? rootdir = py.path.local(py.test.config.getfirst('rootdir', py.path.local())) l = len(str(rootdir)) + failures = [] while 1: - while not checkpyfilechange(rootdir, statcache): - py.std.time.sleep(0.4) - if failures: - failures = failure_master(args, filenames, failures) - else: - failures = master(args, filenames) + if py.test.config.option.session: + while not checkpyfilechange(rootdir, statcache): + py.std.time.sleep(0.4) + failures = failure_master(args, filenames, failures) + if not py.test.config.option.session: + break print "#" * 60 print "# session mode: %d failures remaining" % len(failures) for x in failures: From hpk at codespeak.net Mon Jan 3 18:42:48 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 18:42:48 +0100 (MET) Subject: [py-svn] r8057 - py/dist/py/documentation Message-ID: <20050103174248.CE97C5B0EF@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 18:42:48 2005 New Revision: 8057 Modified: py/dist/py/documentation/test.txt Log: mention the --exec flag in the documentation. Modified: py/dist/py/documentation/test.txt ============================================================================== --- py/dist/py/documentation/test.txt (original) +++ py/dist/py/documentation/test.txt Mon Jan 3 18:42:48 2005 @@ -107,6 +107,14 @@ to get run, notably ``check(42)``, ``check(17)`` and ``check(49)`` of which the middle one will obviously fail. +testing with multiple python versions / executables +--------------------------------------------------- + +With ``--exec=EXECUTABLE`` you can specify a python +executable (e.g. ``python2.2``) with which the tests +will be executed. + + testing starts immediately -------------------------- From hpk at codespeak.net Mon Jan 3 19:19:43 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 3 Jan 2005 19:19:43 +0100 (MET) Subject: [py-svn] r8059 - in py/dist/py: documentation test/testing test/testing/test/data Message-ID: <20050103181943.477DF5B385@thoth.codespeak.net> Author: hpk Date: Mon Jan 3 19:19:33 2005 New Revision: 8059 Removed: py/dist/py/test/testing/test/data/Collector.py Modified: py/dist/py/documentation/test.txt py/dist/py/test/testing/test_collect.py Log: get rid of the old "Collector at module-level" hack because we have generative tests now. Fix documentation. Modified: py/dist/py/documentation/test.txt ============================================================================== --- py/dist/py/documentation/test.txt (original) +++ py/dist/py/documentation/test.txt Mon Jan 3 19:19:33 2005 @@ -88,6 +88,9 @@ can be customized at each level. (see `collection process`_ for some implementation details). + +.. _`generative tests`: + generative tests: yielding more tests ------------------------------------- @@ -423,21 +426,27 @@ If you have a module where you want to take responsibility for collecting your own test Items and possibly even for executing -a test then you can provide your own ``Collector`` at module -level. The default ModuleCollector looks for the name -``Collector`` in the modules namespace and turns over -reponsibility by invoking it with the "module-path". - -The module path is a ``py.path.py()`` instance and carries -information needed to traverse to to the module. In general, -a pypath allows to address a python object on the filesystem. -*Addressability of test Items* is a major concern because we -want to memorize failing tests across py.test invocations. A -``pypath`` has two parts, a filesystem path and a dotted path -leading to the python object. Another benefits, apart from -from addressability, is that invoking setup/teardown operations -can simply be implemented by walking the path to the python -object. +a test then you can provide `generative tests`_ that yield +callables and possibly arguments as a tuple. This should +serve most immediate purposes. + +Another extension possibility goes deeper into the machinery +and allows you to specify a custom test ``Item`` class which +is responsible for setting up and executing an underlying +test. You can integrate your custom ``py.test.Item`` subclass +by putting an ``Item`` binding on a test class. Or you can +take over larger parts of the collection process by tweaking the +``conftest.py`` file. The collection process constantly looks at +such configuration files to determine appropriate collectors at +``Directory``, ``Module`` or ``Class`` level. + +When providing ``Items`` you have to deal with ``py.path.extpy()`` +paths. In general, an extpy-path allows to address a python object +on a filesystem. *Addressability of test Items* is a major concern +because we want to memorize failing tests across py.test invocations. +The extpy-path is also walked in order to setup/teardown resources. +A ``py.path.extpy()`` has two parts, a filesystem path pointing to +a module and a dotted path leading to the python object. Customizing execution of Items ------------------------------ Deleted: /py/dist/py/test/testing/test/data/Collector.py ============================================================================== --- /py/dist/py/test/testing/test/data/Collector.py Mon Jan 3 19:19:33 2005 +++ (empty file) @@ -1,21 +0,0 @@ -from __future__ import generators -import py - -class Collector(py.test.collect.PyCollector): - def collect_function(self, pypath): - if pypath.check(func=1, basestarts='myprefix_'): - yield self.Item(pypath, pypath.basename) - -def myprefix_1(arg): - assert arg == 'myprefix_1' -def myprefix_2(arg): - assert arg == 'myprefix_2' -def myprefix_3(arg): - assert arg == 'myprefix_3' - -def test_this_should_not_be_called(): - assert 1 != 0, "should not be collected" - -class TestA: - def test_this_should_not_be_called(self): - assert 1 != 0, "should not be collected" Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Mon Jan 3 19:19:33 2005 @@ -45,21 +45,22 @@ l = list(collect.Class(extpy)) assert len(l) == 0 -class TestCustomCollector: - def test_custom_collect(self): - l = list(collect.Module(datadir.join('Collector.py'))) - for item in l: - assert isinstance(item, py.test.Item) - assert len(l) == 3 - #for x in l2: - # assert isinstance(x, Unit) - # x.execute() - class Testsomeclass: disabled = True def test_something(): raise ValueError + +class TestWithCustomItem: + class Item(py.test.Item): + flag = [] + def execute(self, target, *args): + self.flag.append(42) + target(*args) + + def test_hello(self): + assert self.Item.flag == [42] + l = [] def test_1(): l.append(1) From hpk at codespeak.net Thu Jan 6 00:00:43 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 6 Jan 2005 00:00:43 +0100 (MET) Subject: [py-svn] r8089 - in py/dist/py/path/local: . testing Message-ID: <20050105230043.1CC315ACEF@thoth.codespeak.net> Author: hpk Date: Thu Jan 6 00:00:42 2005 New Revision: 8089 Modified: py/dist/py/path/local/local.py py/dist/py/path/local/testing/test_local.py Log: make make_numbered_dir more robust. Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Thu Jan 6 00:00:42 2005 @@ -454,7 +454,7 @@ if bn.startswith(base): try: return int(bn[len(base):]) - except TypeError: + except ValueError: pass # compute the maximum number currently in use with the base 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 Thu Jan 6 00:00:42 2005 @@ -170,6 +170,7 @@ def test_make_numbered_dir(self): root = self.tmpdir + root.ensure('base.not_an_int', dir=1) for i in range(10): numdir = local.make_numbered_dir(root, 'base.', keep=2) assert numdir.check() From hpk at codespeak.net Thu Jan 6 00:21:14 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 6 Jan 2005 00:21:14 +0100 (MET) Subject: [py-svn] r8090 - py/dist/py/magic Message-ID: <20050105232114.B03E85ACEF@thoth.codespeak.net> Author: hpk Date: Thu Jan 6 00:21:14 2005 New Revision: 8090 Added: py/dist/py/magic/conftest.py Log: ignore contained greenlet tests when running py lib's tests. Added: py/dist/py/magic/conftest.py ============================================================================== --- (empty file) +++ py/dist/py/magic/conftest.py Thu Jan 6 00:21:14 2005 @@ -0,0 +1,7 @@ +import py + +class Directory(py.test.collect.Directory): + def rec(self, path): + if path.basename != 'testing': + return False + return super(Directory, self).rec(path) From hpk at codespeak.net Fri Jan 7 00:36:45 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 7 Jan 2005 00:36:45 +0100 (MET) Subject: [py-svn] r8120 - py/dist/py/documentation Message-ID: <20050106233645.8B93827B44@code1.codespeak.net> Author: hpk Date: Fri Jan 7 00:36:45 2005 New Revision: 8120 Modified: py/dist/py/documentation/test.txt Log: slight documentation fixes Modified: py/dist/py/documentation/test.txt ============================================================================== --- py/dist/py/documentation/test.txt (original) +++ py/dist/py/documentation/test.txt Fri Jan 7 00:36:45 2005 @@ -435,10 +435,11 @@ is responsible for setting up and executing an underlying test. You can integrate your custom ``py.test.Item`` subclass by putting an ``Item`` binding on a test class. Or you can -take over larger parts of the collection process by tweaking the -``conftest.py`` file. The collection process constantly looks at -such configuration files to determine appropriate collectors at -``Directory``, ``Module`` or ``Class`` level. +take over larger parts of the collection process by putting +Items in a ``conftest.py`` configuration file. +The collection process constantly looks at such configuration files +to determine appropriate collectors at ``Directory``, ``Module`` +or ``Class`` level by looking for these very names. When providing ``Items`` you have to deal with ``py.path.extpy()`` paths. In general, an extpy-path allows to address a python object From hpk at codespeak.net Fri Jan 7 00:46:19 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 7 Jan 2005 00:46:19 +0100 (MET) Subject: [py-svn] r8122 - py/dist/py/documentation Message-ID: <20050106234619.7C72227B3E@code1.codespeak.net> Author: hpk Date: Fri Jan 7 00:46:19 2005 New Revision: 8122 Modified: py/dist/py/documentation/test.txt Log: added a warning about cusotmizihng py.test at deeper levels Modified: py/dist/py/documentation/test.txt ============================================================================== --- py/dist/py/documentation/test.txt (original) +++ py/dist/py/documentation/test.txt Fri Jan 7 00:46:19 2005 @@ -424,6 +424,11 @@ Customizing the collection process in a module ---------------------------------------------- +*Warning: details of the collection process are subject to refactorings +and thus details may change. If you are customizing py.test at +"Item" level then you definitely want to be subscribed to +the `py-dev mailing list`_.* + If you have a module where you want to take responsibility for collecting your own test Items and possibly even for executing a test then you can provide `generative tests`_ that yield @@ -441,7 +446,7 @@ to determine appropriate collectors at ``Directory``, ``Module`` or ``Class`` level by looking for these very names. -When providing ``Items`` you have to deal with ``py.path.extpy()`` +When providing ``Items`` you may have to deal with ``py.path.extpy()`` paths. In general, an extpy-path allows to address a python object on a filesystem. *Addressability of test Items* is a major concern because we want to memorize failing tests across py.test invocations. @@ -469,3 +474,4 @@ allow classes to simply mean "grouping" of tests. .. _`getting started`: getting_started.html +.. _`py-dev mailing list`: http://codespeak.net/mailman/listinfo/py-dev From hpk at codespeak.net Sat Jan 8 00:38:09 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 8 Jan 2005 00:38:09 +0100 (MET) Subject: [py-svn] r8157 - in py/dist/py/path: . extpy local svn test Message-ID: <20050107233809.584DE27B9C@code1.codespeak.net> Author: hpk Date: Sat Jan 8 00:38:09 2005 New Revision: 8157 Modified: py/dist/py/path/common.py py/dist/py/path/extpy/extpy.py py/dist/py/path/local/local.py py/dist/py/path/svn/svncommon.py py/dist/py/path/svn/urlcommand.py py/dist/py/path/test/common.py Log: fixed error handling, made listdir() on a file fail consistently through all path implementations with py.error.ENOTDIR. (on extpy-paths the listdir property is connected to having a __dict__). Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Sat Jan 8 00:38:09 2005 @@ -292,10 +292,10 @@ def move(self, target): if target.relto(self): - raise py.path.Invalid("cannot move path into a subdirectory of itself") + raise py.error.EINVAL(target, "cannot move path into a subdirectory of itself") try: self.rename(target) - except py.path.Invalid: + except py.error.EXDEV: # invalid cross-device link self.copy(target) self.remove() Modified: py/dist/py/path/extpy/extpy.py ============================================================================== --- py/dist/py/path/extpy/extpy.py (original) +++ py/dist/py/path/extpy/extpy.py Sat Jan 8 00:38:09 2005 @@ -116,6 +116,8 @@ obj = self.resolve() l = [] #print "listdir on", self + if not hasattr(obj, '__dict__'): + raise py.error.ENOTDIR(self, "does not have a __dict__ attribute") for name in dir(obj): sub = self.join(name) if not fil or fil(sub): Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Sat Jan 8 00:38:09 2005 @@ -304,11 +304,8 @@ if mtime is None: return self._callex(os.utime, self.strpath, mtime) try: - return os.utime(self.strpath, (-1, mtime)) - except OSError, e: - if e.errno != 22: - error.error_enhance(sys.exc_info()) - raise + return self._callex(os.utime, self.strpath, (-1, mtime)) + except py.error.EINVAL: return self._callex(os.utime, self.strpath, (self.atime(), mtime)) def chdir(self): @@ -436,7 +433,7 @@ except path.FileExists: continue return dpath - raise py.error.ENOENT("could not create tempdir, %d tries" % tries) + raise py.error.ENOENT(dpath, "could not create tempdir, %d tries" % tries) mkdtemp = classmethod(mkdtemp) def make_numbered_dir(cls, rootdir=None, base = 'session-', keep=3): @@ -474,7 +471,7 @@ if num is not None and num <= (maxnum - keep): try: path.remove(rec=1) - except error.Invalid: + except py.error.ENOENT: pass return udir make_numbered_dir = classmethod(make_numbered_dir) Modified: py/dist/py/path/svn/svncommon.py ============================================================================== --- py/dist/py/path/svn/svncommon.py (original) +++ py/dist/py/path/svn/svncommon.py Sat Jan 8 00:38:09 2005 @@ -132,6 +132,11 @@ if isinstance(fil, str): fil = common.fnmatch(fil) nameinfo_seq = self._listdir_nameinfo() + if len(nameinfo_seq) == 1: + name, info = nameinfo_seq[0] + if name == self.basename and info.kind == 'file': + if not self.check(dir=1): + raise py.error.ENOTDIR(self) paths = self._make_path_tuple(nameinfo_seq) if fil or sort: Modified: py/dist/py/path/svn/urlcommand.py ============================================================================== --- py/dist/py/path/svn/urlcommand.py (original) +++ py/dist/py/path/svn/urlcommand.py Sat Jan 8 00:38:09 2005 @@ -84,13 +84,13 @@ def copy(self, target, msg='copied by py lib invocation'): if getattr(target, 'rev', None) is not None: - raise path.Invalid("target can't have a revision: %r" % target) + raise py.error.EINVAL(target, "can't copy to revisioned resource") process.cmdexec("svn copy -m %r %s %s" %(msg, str(self), str(target))) self._lsnorevcache.delentry(target.dirpath().strpath) def remove(self, rec=1, msg='removed by py lib invocation'): if self.rev is not None: - raise path.Invalid("cannot remove revisioned object: %r" % self) + raise py.error.EINVAL(self, "can't remove revisioned resource") process.cmdexec("svn rm -m %r %s" %(msg, str(self))) self._lsnorevcache.delentry(self.dirpath().strpath) Modified: py/dist/py/path/test/common.py ============================================================================== --- py/dist/py/path/test/common.py (original) +++ py/dist/py/path/test/common.py Sat Jan 8 00:38:09 2005 @@ -127,6 +127,8 @@ l = self.root.listdir() assert self.root.join('sampledir') in l assert self.root.join('samplefile') in l + py.test.raises(py.error.ENOTDIR, + "self.root.join('samplefile').listdir()") def test_listdir_fnmatchstring(self): l = self.root.listdir('s*dir') From hpk at codespeak.net Sat Jan 8 00:58:30 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 8 Jan 2005 00:58:30 +0100 (MET) Subject: [py-svn] r8158 - py/dist/py/path/svn/testing Message-ID: <20050107235830.DEC1627B9C@code1.codespeak.net> Author: hpk Date: Sat Jan 8 00:58:30 2005 New Revision: 8158 Added: py/dist/py/path/svn/testing/testrepo.dump Modified: py/dist/py/path/svn/testing/svntestbase.py py/dist/py/path/svn/testing/test_urlcommand.py py/dist/py/path/svn/testing/test_wccommand.py Log: switch svn tests to load from a repository dump instead of laborously recreating it by hand. Modified: py/dist/py/path/svn/testing/svntestbase.py ============================================================================== --- py/dist/py/path/svn/testing/svntestbase.py (original) +++ py/dist/py/path/svn/testing/svntestbase.py Sat Jan 8 00:58:30 2005 @@ -1,8 +1,36 @@ import py from py import path, test, process -from py.__impl__.path.test.fscommon import CommonFSTests +from py.__impl__.path.test.fscommon import CommonFSTests, setuptestfs from py.__impl__.path.svn import cache +mypath = py.magic.autopath() +repodump = mypath.dirpath('testrepo.dump') + +# make a wc directory out of a given root url +# cache previously obtained wcs! +# +def getrepowc(): + repo = py.test.config.tmpdir / 'path' / 'repo' + wcdir = py.test.config.tmpdir / 'path' / 'wc' + if not repo.check(): + assert not wcdir.check() + repo.ensure(dir=1) + try: + py.process.cmdexec('svnadmin create %s' % repo) + py.process.cmdexec('svnadmin load -q %r <%r' % (str(repo), str(repodump))) + except py.process.cmdexec.Error: + repo.remove() + raise py.test.skip('could not create temporary svn test repository') + print "created svn repository", repo + wcdir.ensure(dir=1) + wc = py.path.svnwc(wcdir) + wc.checkout(url='file://%s' % repo) + print "checked out new repo into", wc + else: + print "using repository at", repo + wc = py.path.svnwc(wcdir) + return ("file://%s" % repo, wc) + class CommonSvnTests(CommonFSTests): def setup_method(self, meth): Modified: py/dist/py/path/svn/testing/test_urlcommand.py ============================================================================== --- py/dist/py/path/svn/testing/test_urlcommand.py (original) +++ py/dist/py/path/svn/testing/test_urlcommand.py Sat Jan 8 00:58:30 2005 @@ -1,7 +1,5 @@ -import sys, os import py -from svntestbase import CommonCommandAndBindingTests -from test_wccommand import getrepowc +from svntestbase import CommonCommandAndBindingTests, getrepowc class TestSvnCommandPath(CommonCommandAndBindingTests): def __init__(self): Modified: py/dist/py/path/svn/testing/test_wccommand.py ============================================================================== --- py/dist/py/path/svn/testing/test_wccommand.py (original) +++ py/dist/py/path/svn/testing/test_wccommand.py Sat Jan 8 00:58:30 2005 @@ -1,37 +1,5 @@ import py -from svntestbase import CommonSvnTests -from py.__impl__.path.test.fscommon import setuptestfs - -# make a wc directory out of a given root url -# cache previously obtained wcs! -# -def getrepowc(): - repo = py.test.config.tmpdir / 'path' / 'repo' - wcdir = py.test.config.tmpdir / 'path' / 'wc' - if not repo.check(): - assert not wcdir.check() - repo.ensure(dir=1) - try: - py.process.cmdexec('svnadmin create %s' % repo) - except py.process.cmdexec.Error: - repo.remove() - raise py.test.skip('could not create temporary svn test repository') - wcdir.ensure(dir=1) - print "created svn repository", repo - wc = py.path.svnwc(wcdir) - wc.checkout(url='file://%s' % repo) - print "checked out new repo into", wc - setuptestfs(wc) - wc.join('samplefile').propset('svn:eol-style', 'native') - wc.commit("testrepo setup rev 1") - wc.ensure('anotherfile').write('hello') - wc.commit('second rev') - wc.join('anotherfile').write('world') - wc.commit('third rev') - else: - print "using repository at %s" % repo - wc = py.path.svnwc(wcdir) - return ("file://%s" % repo, wc) +from svntestbase import CommonSvnTests, getrepowc class TestWCSvnCommandPath(CommonSvnTests): def __init__(self): Added: py/dist/py/path/svn/testing/testrepo.dump ============================================================================== --- (empty file) +++ py/dist/py/path/svn/testing/testrepo.dump Sat Jan 8 00:58:30 2005 @@ -0,0 +1,228 @@ +SVN-fs-dump-format-version: 2 + +UUID: 876a30f4-1eed-0310-aeb7-ae314d1e5934 + +Revision-number: 0 +Prop-content-length: 56 +Content-length: 56 + +K 8 +svn:date +V 27 +2005-01-07T23:55:31.755989Z +PROPS-END + +Revision-number: 1 +Prop-content-length: 118 +Content-length: 118 + +K 7 +svn:log +V 20 +testrepo setup rev 1 +K 10 +svn:author +V 3 +hpk +K 8 +svn:date +V 27 +2005-01-07T23:55:37.815386Z +PROPS-END + +Node-path: execfile +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 4 +Text-content-md5: d4b5bc61e16310f08c5d11866eba0a22 +Content-length: 14 + +PROPS-END +x=42 + +Node-path: otherdir +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: otherdir/__init__.py +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 0 +Text-content-md5: d41d8cd98f00b204e9800998ecf8427e +Content-length: 10 + +PROPS-END + + +Node-path: otherdir/a.py +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 30 +Text-content-md5: 247c7daeb2ee5dcab0aba7bd12bad665 +Content-length: 40 + +PROPS-END +from b import stuff as result + + +Node-path: otherdir/b.py +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 15 +Text-content-md5: c1b13503469a7711306d03a4b0721bc6 +Content-length: 25 + +PROPS-END +stuff="got it" + + +Node-path: otherdir/c.py +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 75 +Text-content-md5: 250cdb6b5df68536152c681f48297569 +Content-length: 85 + +PROPS-END +import py; py.magic.autopath() +import otherdir.a +value = otherdir.a.result + + +Node-path: otherdir/d.py +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 72 +Text-content-md5: 940c9c621e7b198e081459642c37f5a7 +Content-length: 82 + +PROPS-END +import py; py.magic.autopath() +from otherdir import a +value2 = a.result + + +Node-path: sampledir +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: sampledir/otherfile +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 0 +Text-content-md5: d41d8cd98f00b204e9800998ecf8427e +Content-length: 10 + +PROPS-END + + +Node-path: samplefile +Node-kind: file +Node-action: add +Prop-content-length: 40 +Text-content-length: 11 +Text-content-md5: 9225ac28b32156979ab6482b8bb5fb8c +Content-length: 51 + +K 13 +svn:eol-style +V 6 +native +PROPS-END +samplefile + + +Node-path: samplepickle +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 56 +Text-content-md5: 719d85c1329a33134bb98f56b756c545 +Content-length: 66 + +PROPS-END +(dp1 +S'answer' +p2 +I42 +sI1 +I2 +sS'hello' +p3 +S'world' +p4 +s. + +Revision-number: 2 +Prop-content-length: 108 +Content-length: 108 + +K 7 +svn:log +V 10 +second rev +K 10 +svn:author +V 3 +hpk +K 8 +svn:date +V 27 +2005-01-07T23:55:39.223202Z +PROPS-END + +Node-path: anotherfile +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 5 +Text-content-md5: 5d41402abc4b2a76b9719d911017c592 +Content-length: 15 + +PROPS-END +hello + +Revision-number: 3 +Prop-content-length: 106 +Content-length: 106 + +K 7 +svn:log +V 9 +third rev +K 10 +svn:author +V 3 +hpk +K 8 +svn:date +V 27 +2005-01-07T23:55:41.556642Z +PROPS-END + +Node-path: anotherfile +Node-kind: file +Node-action: change +Text-content-length: 5 +Text-content-md5: 7d793037a0760186574b0282f2f435e7 +Content-length: 5 + +world + From hpk at codespeak.net Sat Jan 8 10:13:47 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 8 Jan 2005 10:13:47 +0100 (MET) Subject: [py-svn] r8159 - py/dist/py/test Message-ID: <20050108091347.E3B1E27B7B@code1.codespeak.net> Author: hpk Date: Sat Jan 8 10:13:47 2005 New Revision: 8159 Modified: py/dist/py/test/collect.py py/dist/py/test/drive.py py/dist/py/test/item.py Log: slight internal refactoring with respect to Items which now carry methods for the setup/teardown procedure. Modified: py/dist/py/test/collect.py ============================================================================== --- py/dist/py/test/collect.py (original) +++ py/dist/py/test/collect.py Sat Jan 8 10:13:47 2005 @@ -191,10 +191,14 @@ def __iter__(self): try: - sm = self.GenItem.setupmanager - sm.setup_path(self.extpy) - gen, teardown = sm.setup_method(self.extpy) - assert not teardown, "%r not processoable in Generator-Collector (XXX)" + # XXX we need to setup/teardown state here + #sm = self.GenItem.setupmanager + #sm.setup_path(self.extpy) + #gen, teardown = sm.setup_method(self.extpy) + #assert not teardown, "%r not processoable in Generator-Collector (XXX)" + gen = self.extpy.resolve() + if hasattr(gen, 'im_self') and not gen.im_self: + gen = gen.__get__(gen.im_class(), gen.im_class) for call in gen(): yield self.builditem(call) except: Modified: py/dist/py/test/drive.py ============================================================================== --- py/dist/py/test/drive.py (original) +++ py/dist/py/test/drive.py Sat Jan 8 10:13:47 2005 @@ -31,7 +31,7 @@ def teardown(self): """ teardown any resources we know about. """ # XXX a cleaner way to teardown setupmanagers? - py.test.Item.setupmanager.teardown() + py.test.Item.teardownall() def run(self, collectors): """ main loop for running tests. """ Modified: py/dist/py/test/item.py ============================================================================== --- py/dist/py/test/item.py (original) +++ py/dist/py/test/item.py Sat Jan 8 10:13:47 2005 @@ -1,70 +1,92 @@ import py -class SetupManager(object): - """ manage setting up and tearing down objects - along Item paths. Items usually share a single - SetupManager instance in order to reuse - already setup objects. - """ +from inspect import isclass, ismodule + +class SetupState: + """ shared state for setting up/tearing down tests. """ def __init__(self): self._setupstack = [] self._instance = None - - def teardown(self): - while self._setupstack: - self._teardownone(self._setupstack.pop()[1]) + +class SetupItem(object): + state = SetupState() + + def teardownall(cls): + while cls.state._setupstack: + item, extpy, obj = cls.state._setupstack.pop() + item._dispatch_teardown(obj) + teardownall = classmethod(teardownall) + + def _dispatch_teardown(self, obj): + if ismodule(obj): + self.teardown_module(obj) + elif isclass(obj): + self.teardown_class(obj) + + def _dispatch_setup(self, obj): + if ismodule(obj): + self.setup_module(obj) + elif isclass(obj): + self.setup_class(obj) + else: + return False + return True def setup_path(self, extpy): """ setup objects along the path to the test-method (pointed to by extpy). Tear down any previously setup objects which are not directly needed. """ - # _setupstack contains (extpy, obj) tuples of already setup - # objects. Strict ordering is maintained, i.e. each extpy in + # the setupstack contains (item, extpy, obj) tuples of already + # setup objects. Strict ordering is maintained, i.e. each extpy in # the stack is "relto" its previous extpy. - stack = self._setupstack - while stack and not extpy.relto(stack[-1][0]): - self._teardownone(stack.pop()[1]) + stack = self.state._setupstack + while stack and not extpy.relto(stack[-1][1]): + item, addr, obj = stack.pop() + item._dispatch_teardown(obj) rest = extpy.parts()[len(stack):-1] for x in rest: - stack.append((x, self._setupone(x))) + obj = x.resolve() + if self._dispatch_setup(obj): + stack.append((self, x, obj)) + + def setup_module(self, mod): + if hasattr(mod, 'setup_module'): + mod.setup_module(mod) + + def teardown_module(self, mod): + if hasattr(mod, 'teardown_module'): + mod.teardown_module(mod) + + def setup_class(self, cls): + if hasattr(cls, 'setup_class'): + cls.setup_class.im_func(cls) + + def teardown_class(self, cls): + if hasattr(cls, 'teardown_class'): + cls.teardown_class.im_func(cls) - def _setupone(self, extpy): - obj = extpy.resolve() - if py.std.inspect.ismodule(obj): - if hasattr(obj, 'setup_module'): - obj.setup_module(obj) - elif py.std.inspect.isclass(obj): - if hasattr(obj, 'setup_class'): - obj.setup_class.im_func(obj) - return obj - - def _teardownone(self, obj): - if py.std.inspect.ismodule(obj): - if hasattr(obj, 'teardown_module'): - obj.teardown_module(obj) - elif py.std.inspect.isclass(obj): - if hasattr(obj, 'teardown_class'): - obj.teardown_class.im_func(obj) - - def setup_method(self, extpy): + def setup_method(self, method): """ return a tuple of (bound method or callable, teardown method). """ - method = extpy.resolve() + if hasattr(getattr(method, 'im_self', None), 'setup_method'): + method.im_self.setup_method(method) + + def teardown_method(self, method): + if hasattr(getattr(method, 'im_self', None), 'teardown_method'): + method.im_self.teardown_method(method) + + def make_callable(self, method): + assert callable(method) if not hasattr(method, 'im_class'): - return method, None - if self._instance.__class__ != method.im_class: - self._instance = method.im_class() - method = method.__get__(self._instance, method.im_class) - if hasattr(self._instance, 'setup_method'): - #print "execting setup", self._instance.setup_method - self._instance.setup_method(method) - return (method, getattr(self._instance, 'teardown_method', None)) + return method + if self.state._instance.__class__ != method.im_class: + self.state._instance = method.im_class() + return method.__get__(self.state._instance, method.im_class) -class Item(object): +class Item(SetupItem): """ an Item is responsible for locating and executing a Python callable test object. """ - setupmanager = SetupManager() def __init__(self, extpy, *args): self.extpy = extpy @@ -72,13 +94,13 @@ self.args = args def run(self, driver): - self.setupmanager.setup_path(self.extpy) - target, teardown = self.setupmanager.setup_method(self.extpy) + self.setup_path(self.extpy) + method = self.make_callable(self.extpy.resolve()) + self.setup_method(method) try: - self.execute(target, *self.args) + self.execute(method, *self.args) finally: - if teardown: - teardown(target) + self.teardown_method(method) def execute(self, target, *args): """ default implementation for calling a test target is to From hpk at codespeak.net Sat Jan 8 12:32:57 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 8 Jan 2005 12:32:57 +0100 (MET) Subject: [py-svn] r8160 - in py/dist/py: . builtin/testing documentation documentation/example/pytest execnet/testing magic magic/testing misc misc/testing path/extpy/testing path/local path/local/popen5/testing path/local/testing path/svn/testing process/testing test/report/testing test/testing test/tool/testing Message-ID: <20050108113257.EF01827B71@code1.codespeak.net> Author: hpk Date: Sat Jan 8 12:32:57 2005 New Revision: 8160 Modified: py/dist/py/builtin/testing/__init__.py (props changed) py/dist/py/builtin/testing/test_enumerate.py (props changed) py/dist/py/documentation/ (props changed) py/dist/py/documentation/api.txt (props changed) py/dist/py/documentation/coding-style.txt (props changed) py/dist/py/documentation/example/pytest/ (props changed) py/dist/py/documentation/example/pytest/test_setup_flow_example.py (props changed) py/dist/py/documentation/execnet.txt (props changed) py/dist/py/documentation/future.txt (props changed) py/dist/py/documentation/getting_started.txt (props changed) py/dist/py/documentation/index.txt (props changed) py/dist/py/documentation/misc.txt (props changed) py/dist/py/documentation/rest_test.py (props changed) py/dist/py/documentation/test.txt (props changed) py/dist/py/documentation/why_py.txt (props changed) py/dist/py/execnet/testing/ (props changed) py/dist/py/execnet/testing/__init__.py (props changed) py/dist/py/initpkg.py py/dist/py/magic/conftest.py (props changed) py/dist/py/magic/testing/ (props changed) py/dist/py/magic/testing/__init__.py (props changed) py/dist/py/misc/cache.py (props changed) py/dist/py/misc/error.py (props changed) py/dist/py/misc/testing/ (props changed) py/dist/py/misc/testing/__init__.py (props changed) py/dist/py/misc/testing/test_cache.py (props changed) py/dist/py/misc/testing/test_error.py (props changed) py/dist/py/misc/testing/test_initpkg.py py/dist/py/path/extpy/testing/ (props changed) py/dist/py/path/extpy/testing/__init__.py (props changed) py/dist/py/path/local/local.py py/dist/py/path/local/popen5/testing/ (props changed) py/dist/py/path/local/popen5/testing/__init__.py (props changed) py/dist/py/path/local/testing/ (props changed) py/dist/py/path/local/testing/__init__.py (props changed) py/dist/py/path/svn/testing/ (props changed) py/dist/py/path/svn/testing/__init__.py (props changed) py/dist/py/process/testing/ (props changed) py/dist/py/process/testing/__init__.py (props changed) py/dist/py/test/report/testing/ (props changed) py/dist/py/test/report/testing/__init__.py (props changed) py/dist/py/test/testing/ (props changed) py/dist/py/test/testing/__init__.py (props changed) py/dist/py/test/tool/testing/ (props changed) py/dist/py/test/tool/testing/__init__.py (props changed) Log: test fixes (leave out greenlet-autoimport-test) fixeol Modified: py/dist/py/initpkg.py ============================================================================== --- py/dist/py/initpkg.py (original) +++ py/dist/py/initpkg.py Sat Jan 8 12:32:57 2005 @@ -126,7 +126,7 @@ p = py.path.svnwc(self.module.__file__).dirpath() try: return p.info().rev - except (KeyboardError, MemoryError, SystemExit): + except (KeyboardInterrupt, MemoryError, SystemExit): raise except: return 'unknown' Modified: py/dist/py/misc/testing/test_initpkg.py ============================================================================== --- py/dist/py/misc/testing/test_initpkg.py (original) +++ py/dist/py/misc/testing/test_initpkg.py Sat Jan 8 12:32:57 2005 @@ -1,15 +1,20 @@ import py import types +def checksubpackage(name): + obj = getattr(py, name) + if hasattr(obj, '__map__'): # isinstance(obj, Module): + keys = dir(obj) + assert len(keys) > 0 + assert getattr(obj, '__map__') == {} + def test_dir(): from py.__impl__.initpkg import Module for name in dir(py): + if name == 'magic': # greenlets don't work everywhere, we don't care here + continue if not name.startswith('_'): - obj = getattr(py, name) - if hasattr(obj, '__map__'): # isinstance(obj, Module): - keys = dir(obj) - assert len(keys) > 0 - assert getattr(obj, '__map__') == {} + yield checksubpackage, name def test_virtual_module_identity(): from py import path as path1 Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Sat Jan 8 12:32:57 2005 @@ -542,16 +542,17 @@ ) finally: foutput, foutput = c.done() - except (KeyboardInterrupt, SystemExit): - raise - except: - print foutput.read() + except KeyboardInterrupt: raise + except SystemExit: + raise RuntimeError("cannot compile %s:\n%s" % (cfile, foutput.read(),)) # XXX do we need to do some check on fout/ferr? # XXX not a nice way to import a module - if debug: print "inserting path to sys.path", dirpath + if debug: + print "inserting path to sys.path", dirpath sys.path.insert(0, '.') - if debug: print "import %(modname)s as testmodule" % locals() + if debug: + print "import %(modname)s as testmodule" % locals() exec "import %(modname)s as testmodule" % locals() sys.path.pop(0) finally: @@ -559,4 +560,3 @@ #if not debug: #dirpath.rmtree() return testmodule - From hpk at codespeak.net Sat Jan 8 12:53:45 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 8 Jan 2005 12:53:45 +0100 (MET) Subject: [py-svn] r8161 - in py/dist/py: code path/local test Message-ID: <20050108115345.3389027B71@code1.codespeak.net> Author: hpk Date: Sat Jan 8 12:53:45 2005 New Revision: 8161 Modified: py/dist/py/code/frame.py py/dist/py/path/local/local.py py/dist/py/test/collect.py Log: a couple of small fixes and slight hacks :-) Modified: py/dist/py/code/frame.py ============================================================================== --- py/dist/py/code/frame.py (original) +++ py/dist/py/code/frame.py Sat Jan 8 12:53:45 2005 @@ -7,8 +7,10 @@ self.name = f_code.co_name def path(self): - return getattr(self.raw.co_filename, '__path__', - py.path.local(self.raw.co_filename)) + try: + return self.raw.co_filename.__path__ + except AttributeError: + return py.path.local(self.raw.co_filename) path = property(path, None, None, "path of this code object") def fullsource(self): Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Sat Jan 8 12:53:45 2005 @@ -553,7 +553,7 @@ sys.path.insert(0, '.') if debug: print "import %(modname)s as testmodule" % locals() - exec "import %(modname)s as testmodule" % locals() + exec py.code.compile("import %(modname)s as testmodule" % locals()) sys.path.pop(0) finally: lastdir.chdir() Modified: py/dist/py/test/collect.py ============================================================================== --- py/dist/py/test/collect.py (original) +++ py/dist/py/test/collect.py Sat Jan 8 12:53:45 2005 @@ -75,7 +75,8 @@ try: for fspath in self.fspath.listdir(sort=True): if self.rec(fspath): - yield self.Directory(fspath) + # hack to get the correct Directory collector class + yield self.Directory(fspath).Directory(fspath) elif self.fil(fspath): yield self.Module(fspath) except: From hpk at codespeak.net Sat Jan 8 13:46:03 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 8 Jan 2005 13:46:03 +0100 (MET) Subject: [py-svn] r8162 - in py/dist/py/test: . testing/test Message-ID: <20050108124603.1F9FD27B71@code1.codespeak.net> Author: hpk Date: Sat Jan 8 13:46:02 2005 New Revision: 8162 Modified: py/dist/py/test/item.py py/dist/py/test/testing/test/test_setup_nested.py Log: add setup_function/teardown_function hooks which are now called for plain functions whereas setup_method is called for methods. Modified: py/dist/py/test/item.py ============================================================================== --- py/dist/py/test/item.py (original) +++ py/dist/py/test/item.py Sat Jan 8 13:46:02 2005 @@ -67,7 +67,6 @@ cls.teardown_class.im_func(cls) def setup_method(self, method): - """ return a tuple of (bound method or callable, teardown method). """ if hasattr(getattr(method, 'im_self', None), 'setup_method'): method.im_self.setup_method(method) @@ -75,6 +74,16 @@ if hasattr(getattr(method, 'im_self', None), 'teardown_method'): method.im_self.teardown_method(method) + def setup_function(self, function): + x = function.func_globals.get('setup_function', None) + if x is not None: + x(function) + + def teardown_function(self, function): + x = function.func_globals.get('teardown_function', None) + if x is not None: + x(function) + def make_callable(self, method): assert callable(method) if not hasattr(method, 'im_class'): @@ -96,7 +105,10 @@ def run(self, driver): self.setup_path(self.extpy) method = self.make_callable(self.extpy.resolve()) - self.setup_method(method) + if hasattr(method, 'im_self'): + self.setup_method(method) + else: + self.setup_function(method) try: self.execute(method, *self.args) finally: Modified: py/dist/py/test/testing/test/test_setup_nested.py ============================================================================== --- py/dist/py/test/testing/test/test_setup_nested.py (original) +++ py/dist/py/test/testing/test/test_setup_nested.py Sat Jan 8 13:46:02 2005 @@ -10,8 +10,16 @@ def teardown_module(module): modlevel.pop() +def setup_function(function): + function.answer = 17 + +def teardown_function(function): + del function.answer + def test_modlevel(): assert modlevel[0] == 42 + assert test_modlevel.answer == 17 + class TestSimpleClassSetup: clslevel = [] From hpk at codespeak.net Sat Jan 8 17:03:38 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 8 Jan 2005 17:03:38 +0100 (MET) Subject: [py-svn] r8171 - py/dist/py/test/report/text Message-ID: <20050108160338.933D127B71@code1.codespeak.net> Author: hpk Date: Sat Jan 8 17:03:38 2005 New Revision: 8171 Modified: py/dist/py/test/report/text/summary.py Log: handle non-existing source code more gracefully Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Sat Jan 8 17:03:38 2005 @@ -106,8 +106,9 @@ def repr_source(self, tb): # represent source code for a given traceback entry self.out.line() - source = tb.frame.code.fullsource - if not source: + try: + source = tb.frame.code.fullsource + except py.error.ENOENT: self.out.line("failure to get at sourcelines from %r" % tb) #self.out.line("(co_filename = %r)" % (frame.f_code.co_filename)) #self.out.line("(f_lineno = %r)" % (frame.f_lineno)) From hpk at codespeak.net Sat Jan 8 17:56:17 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 8 Jan 2005 17:56:17 +0100 (MET) Subject: [py-svn] r8172 - py/dist/py Message-ID: <20050108165617.4C82927B71@code1.codespeak.net> Author: hpk Date: Sat Jan 8 17:56:17 2005 New Revision: 8172 Modified: py/dist/py/initpkg.py Log: be yet more tolerant Modified: py/dist/py/initpkg.py ============================================================================== --- py/dist/py/initpkg.py (original) +++ py/dist/py/initpkg.py Sat Jan 8 17:56:17 2005 @@ -163,7 +163,7 @@ if hasattr(result, '__bases__'): try: setattr(result, '__name__', name) - except TypeError: # doesn't work on Python 2.2 + except (AttributeError, TypeError): pass # print "setting virtual module on %r" % result return result From hpk at codespeak.net Sun Jan 9 16:49:35 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 9 Jan 2005 16:49:35 +0100 (MET) Subject: [py-svn] r8182 - in py/dist/py: . bin builtin builtin/testing code code/testing documentation documentation/example/pytest execnet execnet/bin execnet/testing execnet/testing/test magic magic/testing misc misc/testing path path/extpy path/extpy/testing path/extpy/testing/test_data path/gateway path/local path/local/popen5/testing path/local/testing path/svn path/svn/testing path/test process process/testing test test/report test/report/testing test/report/text test/testing test/testing/test test/testing/test/data test/tool test/tool/testing Message-ID: <20050109154935.B050527B75@code1.codespeak.net> Author: hpk Date: Sun Jan 9 16:49:34 2005 New Revision: 8182 Modified: py/dist/py/__init__.py py/dist/py/bin/_findpy.py py/dist/py/builtin/enumerate.py py/dist/py/builtin/testing/test_enumerate.py py/dist/py/code/excinfo.py py/dist/py/code/frame.py py/dist/py/code/source.py py/dist/py/code/testing/test_cpython_features.py py/dist/py/code/testing/test_excinfo.py py/dist/py/code/testing/test_frame.py py/dist/py/code/testing/test_source.py py/dist/py/conftest.py py/dist/py/documentation/example/pytest/failure_demo.py py/dist/py/documentation/example/pytest/test_setup_flow_example.py py/dist/py/documentation/rest_test.py py/dist/py/env.py py/dist/py/execnet/bin/quitserver.py py/dist/py/execnet/bin/shell.py py/dist/py/execnet/bin/startserver.py py/dist/py/execnet/channel.py py/dist/py/execnet/gateway.py py/dist/py/execnet/inputoutput.py py/dist/py/execnet/message.py py/dist/py/execnet/register.py py/dist/py/execnet/testing/__init__.py py/dist/py/execnet/testing/sshtesting.py py/dist/py/execnet/testing/test/test_pickle.py py/dist/py/execnet/testing/test_gateway.py py/dist/py/initpkg.py py/dist/py/magic/assertion.py py/dist/py/magic/autopath.py py/dist/py/magic/conftest.py py/dist/py/magic/exprinfo.py py/dist/py/magic/invoke.py py/dist/py/magic/patch.py py/dist/py/magic/testing/__init__.py py/dist/py/magic/testing/test_assertion.py py/dist/py/magic/testing/test_autopath.py py/dist/py/magic/testing/test_exprinfo.py py/dist/py/magic/testing/test_invoke.py py/dist/py/magic/testing/test_patch.py py/dist/py/magic/testing/test_viewtype.py py/dist/py/magic/viewtype.py py/dist/py/misc/cache.py py/dist/py/misc/error.py py/dist/py/misc/std.py py/dist/py/misc/testing/__init__.py py/dist/py/misc/testing/test_api.py py/dist/py/misc/testing/test_cache.py py/dist/py/misc/testing/test_error.py py/dist/py/misc/testing/test_initpkg.py py/dist/py/misc/testing/test_std.py py/dist/py/path/__init__.py py/dist/py/path/common.py py/dist/py/path/extpy/extpy.py py/dist/py/path/extpy/testing/__init__.py py/dist/py/path/extpy/testing/inc_pseudofs.py py/dist/py/path/extpy/testing/inc_test_extpy.py py/dist/py/path/extpy/testing/test_data/no_trailing_newline.py py/dist/py/path/extpy/testing/test_extpy.py py/dist/py/path/gateway/channeltest.py py/dist/py/path/gateway/channeltest2.py py/dist/py/path/gateway/remotepath.py py/dist/py/path/local/api.py py/dist/py/path/local/local.py py/dist/py/path/local/popen5/testing/__init__.py py/dist/py/path/local/popen5/testing/test_subprocess.py py/dist/py/path/local/posix.py py/dist/py/path/local/stdoutcapture.py py/dist/py/path/local/testing/__init__.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 py/dist/py/path/svn/cache.py py/dist/py/path/svn/svncommon.py py/dist/py/path/svn/testing/__init__.py py/dist/py/path/svn/testing/svntestbase.py py/dist/py/path/svn/testing/test_urlcommand.py py/dist/py/path/svn/testing/test_wccommand.py py/dist/py/path/svn/urlcommand.py py/dist/py/path/svn/wccommand.py py/dist/py/path/svn/xsvnbinding.py py/dist/py/path/test/common.py py/dist/py/path/test/fscommon.py py/dist/py/path/test/test_api.py py/dist/py/process/cmdexec.py py/dist/py/process/testing/__init__.py py/dist/py/test/cmdline.py py/dist/py/test/collect.py py/dist/py/test/compat.py py/dist/py/test/config.py py/dist/py/test/defaultconfig.py py/dist/py/test/drive.py py/dist/py/test/item.py py/dist/py/test/raises.py py/dist/py/test/report/memo.py py/dist/py/test/report/testing/__init__.py py/dist/py/test/report/testing/test_memo.py py/dist/py/test/report/text/out.py py/dist/py/test/report/text/reporter.py py/dist/py/test/report/text/summary.py py/dist/py/test/run.py py/dist/py/test/testing/__init__.py py/dist/py/test/testing/test/data/disabled.py py/dist/py/test/testing/test/data/disabledclass.py py/dist/py/test/testing/test/data/syntax_error.py py/dist/py/test/testing/test/demo.py py/dist/py/test/testing/test/test_setup_nested.py py/dist/py/test/testing/test_collect.py py/dist/py/test/testing/test_compat.py py/dist/py/test/testing/test_config.py py/dist/py/test/testing/test_raises.py py/dist/py/test/tool/optparse.py py/dist/py/test/tool/outerrcapture.py py/dist/py/test/tool/testing/__init__.py py/dist/py/test/tool/testing/test_outerrcapture.py Log: remove trailing whitespace. As i was usually the one who added these trailing whitespace it doesn't really change the history (which is nice to keep in mind when doing such changes). Modified: py/dist/py/__init__.py ============================================================================== --- py/dist/py/__init__.py (original) +++ py/dist/py/__init__.py Sun Jan 9 16:49:34 2005 @@ -12,7 +12,7 @@ 'test.collect.Class' : ('./test/collect.py', 'Class'), 'test.collect.Error' : ('./test/collect.py', 'Error'), 'test.collect.Collector' : ('./test/collect.py', 'Collector'), - 'test.TextReporter' : ('./test/report/text/reporter.py', + 'test.TextReporter' : ('./test/report/text/reporter.py', 'TextReporter'), 'test.Option' : ('./test/tool/optparse.py', 'Option'), 'test.MemoReporter' : ('./test/report/memo.py', 'MemoReporter'), @@ -52,5 +52,5 @@ 'execnet.PopenGateway' : ('./execnet/register.py', 'PopenGateway'), 'execnet.SshGateway' : ('./execnet/register.py', 'SshGateway'), - 'error' : ('./misc/error.py', 'error'), + 'error' : ('./misc/error.py', 'error'), }) Modified: py/dist/py/bin/_findpy.py ============================================================================== --- py/dist/py/bin/_findpy.py (original) +++ py/dist/py/bin/_findpy.py Sun Jan 9 16:49:34 2005 @@ -1,27 +1,27 @@ # -# find and import a version of 'py' -# +# find and import a version of 'py' +# import sys import os -from os.path import dirname as opd, exists, join, basename, abspath +from os.path import dirname as opd, exists, join, basename, abspath def searchpy(current): while 1: last = current - initpy = join(current, '__init__.py') - if not exists(initpy): - pydir = join(current, 'py') - # recognize py-package and ensure it is importable - if exists(pydir) and exists(join(pydir, '__init__.py')): + initpy = join(current, '__init__.py') + if not exists(initpy): + pydir = join(current, 'py') + # recognize py-package and ensure it is importable + if exists(pydir) and exists(join(pydir, '__init__.py')): for p in sys.path: if p == current: - return True + return True print "inserting into sys.path:", current - sys.path.insert(0, current) + sys.path.insert(0, current) return True - current = opd(current) - if last == current: - return False + current = opd(current) + if last == current: + return False if not searchpy(abspath(os.curdir)): if not searchpy(opd(abspath(sys.argv[0]))): Modified: py/dist/py/builtin/enumerate.py ============================================================================== --- py/dist/py/builtin/enumerate.py (original) +++ py/dist/py/builtin/enumerate.py Sun Jan 9 16:49:34 2005 @@ -1,9 +1,9 @@ -from __future__ import generators +from __future__ import generators try: enumerate = enumerate -except NameError: - def enumerate(iterable): - i = 0 - for x in iterable: +except NameError: + def enumerate(iterable): + i = 0 + for x in iterable: yield i, x i += 1 Modified: py/dist/py/builtin/testing/test_enumerate.py ============================================================================== --- py/dist/py/builtin/testing/test_enumerate.py (original) +++ py/dist/py/builtin/testing/test_enumerate.py Sun Jan 9 16:49:34 2005 @@ -1,7 +1,7 @@ -import sys +import sys import py -def test_enumerate(): +def test_enumerate(): l = [0,1,2] - for i,x in py.builtin.enumerate(l): - assert i == x + for i,x in py.builtin.enumerate(l): + assert i == x Modified: py/dist/py/code/excinfo.py ============================================================================== --- py/dist/py/code/excinfo.py (original) +++ py/dist/py/code/excinfo.py Sun Jan 9 16:49:34 2005 @@ -1,13 +1,13 @@ -from __future__ import generators +from __future__ import generators import sys import py -class ExceptionInfo(object): - """ wraps sys.exc_info() objects and offers - help for navigating the traceback. +class ExceptionInfo(object): + """ wraps sys.exc_info() objects and offers + help for navigating the traceback. """ TRACEBACK_HIDE = object() - + def __init__(self, tup=None, exprinfo=None): # NB. all attributes are private! Subclasses or other # ExceptionInfo-like classes may have different attributes. @@ -49,53 +49,53 @@ yield TracebackEntry(current) current = current.tb_next - def getentries(self, startcondition=None, endcondition=None): - if startcondition is not None and not callable(startcondition): - raise TypeError("%r is not callable or None" % startcondition) - if endcondition is not None and not callable(endcondition): - raise TypeError("%r is not callable or None" % endcondition) + def getentries(self, startcondition=None, endcondition=None): + if startcondition is not None and not callable(startcondition): + raise TypeError("%r is not callable or None" % startcondition) + if endcondition is not None and not callable(endcondition): + raise TypeError("%r is not callable or None" % endcondition) result = [] gen = iter(self) - for x in gen: - if startcondition is None or startcondition(x): - result.append(x) - break - for x in gen: - result.append(x) - if endcondition is not None and endcondition(x): - break - return result - #entries = list(self) - #gen = py.builtin.enumerate(self) - #if start is not None: - # for i, entry in gen: + for x in gen: + if startcondition is None or startcondition(x): + result.append(x) + break + for x in gen: + result.append(x) + if endcondition is not None and endcondition(x): + break + return result + #entries = list(self) + #gen = py.builtin.enumerate(self) + #if start is not None: + # for i, entry in gen: # p,l = entry.frame.code.path, entry.frame.code.firstlineno - # if start == i or (p,l) == start: - # break + # if start == i or (p,l) == start: + # break #res = [] - #for i, entry in gen: + #for i, entry in gen: # res.append(entry) - # if end is not None: - # p,l = entry.frame.code.path, entry.frame.code.firstlineno - # if i == end or (p,l) == end: - # break - #return res + # if end is not None: + # p,l = entry.frame.code.path, entry.frame.code.firstlineno + # if i == end or (p,l) == end: + # break + #return res -class TracebackEntry(object): +class TracebackEntry(object): def __init__(self, rawentry): self._rawentry = rawentry self.frame = py.code.Frame(rawentry.tb_frame) - self.lineno = rawentry.tb_lineno - 1 - - def statement(self): - source = self.frame.code.fullsource - return source.getstatement(self.lineno) - statement = property(statement, None, None, - "statement of this traceback entry.") + self.lineno = rawentry.tb_lineno - 1 + + def statement(self): + source = self.frame.code.fullsource + return source.getstatement(self.lineno) + statement = property(statement, None, None, + "statement of this traceback entry.") - def path(self): - return self.frame.path + def path(self): + return self.frame.path path = property(path, None, None, "path to the full source code") - def __repr__(self): + def __repr__(self): return "" %(self.frame.code.path, self.lineno + 1) Modified: py/dist/py/code/frame.py ============================================================================== --- py/dist/py/code/frame.py (original) +++ py/dist/py/code/frame.py Sun Jan 9 16:49:34 2005 @@ -1,42 +1,42 @@ import py -class Code(object): - def __init__(self, f_code): - self.raw = f_code - self.firstlineno = f_code.co_firstlineno - 1 +class Code(object): + def __init__(self, f_code): + self.raw = f_code + self.firstlineno = f_code.co_firstlineno - 1 self.name = f_code.co_name - def path(self): - try: - return self.raw.co_filename.__path__ - except AttributeError: + def path(self): + try: + return self.raw.co_filename.__path__ + except AttributeError: return py.path.local(self.raw.co_filename) path = property(path, None, None, "path of this code object") - def fullsource(self): - fn = self.raw.co_filename - try: - return fn.__source__ - except AttributeError: + def fullsource(self): + fn = self.raw.co_filename + try: + return fn.__source__ + except AttributeError: return py.code.Source(self.path.read(mode="rU")) - fullsource = property(fullsource, None, None, - "full source containing this code object") + fullsource = property(fullsource, None, None, + "full source containing this code object") class Frame(object): """Wrapper around a Python frame holding f_locals and f_globals in which expressions can be evaluated.""" - + def __init__(self, frame): self.code = Code(frame.f_code) self.lineno = frame.f_lineno - 1 self.f_globals = frame.f_globals - self.f_locals = frame.f_locals + self.f_locals = frame.f_locals - def statement(self): - return self.code.fullsource.getstatement(self.lineno) - statement = property(statement, None, None, - "statement this frame is at") + def statement(self): + return self.code.fullsource.getstatement(self.lineno) + statement = property(statement, None, None, + "statement this frame is at") def eval(self, code, **vars): self.f_locals.update(vars) @@ -52,4 +52,4 @@ def is_true(self, object): return object - + Modified: py/dist/py/code/source.py ============================================================================== --- py/dist/py/code/source.py (original) +++ py/dist/py/code/source.py Sun Jan 9 16:49:34 2005 @@ -1,262 +1,262 @@ -from __future__ import generators -import sys +from __future__ import generators +import sys import inspect # DON'T IMPORT PY HERE class Source(object): - """ a mutable object holding a source code fragment, - automatically deindenting it. + """ a mutable object holding a source code fragment, + automatically deindenting it. """ - def __init__(self, *parts, **kwargs): + def __init__(self, *parts, **kwargs): self.lines = lines = [] de = kwargs.get('deindent', True) for part in parts: if isinstance(part, Source): - partlines = part.lines + partlines = part.lines elif isinstance(part, str): partlines = part.split('\n') - else: - partlines = getsource(part, deindent=False).lines - if de: - partlines = deindent(partlines) - lines.extend(partlines) + else: + partlines = getsource(part, deindent=False).lines + if de: + partlines = deindent(partlines) + lines.extend(partlines) - def __getitem__(self, key): - if isinstance(key, int): + def __getitem__(self, key): + if isinstance(key, int): return self.lines[key] - else: - return self.__getslice__(key) + else: + return self.__getslice__(key) def __getslice__(self, start, end): newsource = Source() newsource.lines = self.lines[start:end] - return newsource + return newsource - def strip(self): - """ return new source object with trailing - and leading blank lines removed. + def strip(self): + """ return new source object with trailing + and leading blank lines removed. """ for start in range(0, len(self)): - if not self.lines[start].isspace(): - break - for end in range(len(self)-1, -1, -1): - if not self.lines[end].isspace(): - break - source = Source() + if not self.lines[start].isspace(): + break + for end in range(len(self)-1, -1, -1): + if not self.lines[end].isspace(): + break + source = Source() source.lines[:] = self.lines[start:end+1] - return source + return source def putaround(self, before='', after=''): - """ modifies a new source object embedded/indented - between before and after. + """ modifies a new source object embedded/indented + between before and after. """ - before = Source(before) - after = Source(after) - newsource = Source() + before = Source(before) + after = Source(after) + newsource = Source() lines = [' ' + line for line in self.lines] - newsource.lines = before.lines + lines + after.lines - return newsource + newsource.lines = before.lines + lines + after.lines + return newsource def getstatement(self, lineno): - """ return Source statement which contains the - given linenumber (counted from 0). + """ return Source statement which contains the + given linenumber (counted from 0). """ - start, end = self.getstatementrange(lineno) + start, end = self.getstatementrange(lineno) return self[start:end] def getstatementrange(self, lineno): - """ return (start, end) tuple which span the statement - region which contains the given lineno. + """ return (start, end) tuple which span the statement + region which contains the given lineno. """ - # XXX there must be a better than these heuristic ways ... - for end in range(lineno, len(self)): + # XXX there must be a better than these heuristic ways ... + for end in range(lineno, len(self)): trysource = self[lineno:end+1] - if trysource.isparseable(): - start = lineno - break - else: + if trysource.isparseable(): + start = lineno + break + else: end = lineno - for start in range(lineno, -1, -1): + for start in range(lineno, -1, -1): trysource = self[start:end+1] - if trysource.isparseable(): - break - else: - # find the end - for end in range(lineno, len(self)): + if trysource.isparseable(): + break + else: + # find the end + for end in range(lineno, len(self)): trysource = self[:end+1] - if trysource.isparseable(): - break - else: - return None - # find the start - for start in range(end, -1, -1): + if trysource.isparseable(): + break + else: + return None + # find the start + for start in range(end, -1, -1): trysource = self[start:end+1] - if trysource.isparseable(): - break + if trysource.isparseable(): + break assert start <= lineno <= end, "could not locate statement" return start, end + 1 - def getblockend(self, lineno): + def getblockend(self, lineno): # XXX lines = [x + '\n' for x in self.lines[lineno:]] - blocklines = inspect.getblock(lines) - #print blocklines + blocklines = inspect.getblock(lines) + #print blocklines return lineno + len(blocklines) - 1 - def deindent(self, offset=None): - """ return a new source object deindented by offset. - If offset is None then guess an indentation offset from - the first non-blank line. Subsequent lines which have a - lower indentation offset will be copied verbatim as - they are assumed to be part of multilines. + def deindent(self, offset=None): + """ return a new source object deindented by offset. + If offset is None then guess an indentation offset from + the first non-blank line. Subsequent lines which have a + lower indentation offset will be copied verbatim as + they are assumed to be part of multilines. """ - # XXX maybe use the tokenizer to properly handle multiline - # strings etc.pp? + # XXX maybe use the tokenizer to properly handle multiline + # strings etc.pp? newsource = Source() - newsource.lines[:] = deindent(self.lines, offset) - return newsource - - def __len__(self): - return len(self.lines) - - def isparseable(self, deindent=True): - """ return True if source is parseable, heuristically - deindenting it by default. + newsource.lines[:] = deindent(self.lines, offset) + return newsource + + def __len__(self): + return len(self.lines) + + def isparseable(self, deindent=True): + """ return True if source is parseable, heuristically + deindenting it by default. """ - import parser - if deindent: + import parser + if deindent: source = str(self.deindent()) - else: - source = str(self) + else: + source = str(self) try: - parser.suite(source+'\n') + parser.suite(source+'\n') except (parser.ParserError, SyntaxError): return False else: - return True + return True def __str__(self): - return "\n".join(self.lines) + return "\n".join(self.lines) - def compile(self, filename=None, mode='exec', + def compile(self, filename=None, mode='exec', flag=generators.compiler_flag): - """ return compiled code object. if filename is None - invent an artificial filename which displays - the source/line position of the caller frame. + """ return compiled code object. if filename is None + invent an artificial filename which displays + the source/line position of the caller frame. """ - if filename is None: - frame = sys._getframe(1) # the caller - filename = '<%s:%d>' % (frame.f_code.co_filename, - frame.f_lineno) + if filename is None: + frame = sys._getframe(1) # the caller + filename = '<%s:%d>' % (frame.f_code.co_filename, + frame.f_lineno) source = str(self)+'\n' try: co = compile(source, filename, mode, flag) except SyntaxError, ex: - # re-represent syntax errors from parsing python strings + # re-represent syntax errors from parsing python strings newex = SyntaxError('\n'.join([ "".join(self.lines[:ex.lineno]), - " " * ex.offset + '^', + " " * ex.offset + '^', "syntax error probably generated here: %s" % filename])) newex.offset = ex.offset newex.lineno = ex.lineno newex.text = ex.text raise newex - else: - co_filename = MyStr(filename) + else: + co_filename = MyStr(filename) co_filename.__source__ = self - return newcode_withfilename(co, co_filename) + return newcode_withfilename(co, co_filename) -# -# public API shortcut functions -# - -def compile_(source, filename=None, mode='exec', flags= - generators.compiler_flag): - """ compile the given source to a raw code object, - which points back to the source code through - "co_filename.__source__". All code objects - contained in the code object will recursively - also have this special subclass-of-string - filename. +# +# public API shortcut functions +# + +def compile_(source, filename=None, mode='exec', flags= + generators.compiler_flag): + """ compile the given source to a raw code object, + which points back to the source code through + "co_filename.__source__". All code objects + contained in the code object will recursively + also have this special subclass-of-string + filename. """ s = Source(source) - co = s.compile(filename, mode, flags) - return co + co = s.compile(filename, mode, flags) + return co -def getsource(obj, **kwargs): - if hasattr(obj, 'func_code'): +def getsource(obj, **kwargs): + if hasattr(obj, 'func_code'): obj = obj.func_code - elif hasattr(obj, 'f_code'): - obj = obj.f_code + elif hasattr(obj, 'f_code'): + obj = obj.f_code try: - fullsource = obj.co_filename.__source__ - except AttributeError: - import inspect - strsrc = inspect.getsource(obj) - assert isinstance(strsrc, str) - return Source(strsrc, **kwargs) - else: - lineno = obj.co_firstlineno - 1 + fullsource = obj.co_filename.__source__ + except AttributeError: + import inspect + strsrc = inspect.getsource(obj) + assert isinstance(strsrc, str) + return Source(strsrc, **kwargs) + else: + lineno = obj.co_firstlineno - 1 end = fullsource.getblockend(lineno) return fullsource[lineno:end+1] -# -# various helper functions -# -class MyStr(str): - """ custom string which allows to add attributes. """ - +# +# various helper functions +# +class MyStr(str): + """ custom string which allows to add attributes. """ + def deindent(lines, offset=None): - # XXX maybe use the tokenizer to properly handle multiline - # strings etc.pp? - if offset is None: - for line in lines: + # XXX maybe use the tokenizer to properly handle multiline + # strings etc.pp? + if offset is None: + for line in lines: s = line.lstrip() - if s: - offset = len(line)-len(s) - break - else: - offset = 0 + if s: + offset = len(line)-len(s) + break + else: + offset = 0 newlines = [] - for line in lines: + for line in lines: #line = line.expandtabs() s = line.lstrip() - if s and line[:offset].isspace(): + if s and line[:offset].isspace(): line = line[offset:] - newlines.append(line) - return newlines + newlines.append(line) + return newlines -def newcode(fromcode, **kwargs): +def newcode(fromcode, **kwargs): names = [x for x in dir(fromcode) if x[:3] == 'co_'] - for name in names: - if name not in kwargs: - kwargs[name] = getattr(fromcode, name) + for name in names: + if name not in kwargs: + kwargs[name] = getattr(fromcode, name) import new return new.code( - kwargs['co_argcount'], - kwargs['co_nlocals'], - kwargs['co_stacksize'], - kwargs['co_flags'], - kwargs['co_code'], - kwargs['co_consts'], - kwargs['co_names'], - kwargs['co_varnames'], - kwargs['co_filename'], - kwargs['co_name'], - kwargs['co_firstlineno'], - kwargs['co_lnotab'], - kwargs['co_freevars'], - kwargs['co_cellvars'], + kwargs['co_argcount'], + kwargs['co_nlocals'], + kwargs['co_stacksize'], + kwargs['co_flags'], + kwargs['co_code'], + kwargs['co_consts'], + kwargs['co_names'], + kwargs['co_varnames'], + kwargs['co_filename'], + kwargs['co_name'], + kwargs['co_firstlineno'], + kwargs['co_lnotab'], + kwargs['co_freevars'], + kwargs['co_cellvars'], ) -def newcode_withfilename(co, co_filename): +def newcode_withfilename(co, co_filename): newconstlist = [] cotype = type(co) - for c in co.co_consts: - if isinstance(c, cotype): + for c in co.co_consts: + if isinstance(c, cotype): c = newcode_withfilename(c, co_filename) - newconstlist.append(c) - return newcode(co, co_consts = tuple(newconstlist), + newconstlist.append(c) + return newcode(co, co_consts = tuple(newconstlist), co_filename = co_filename) - + Modified: py/dist/py/code/testing/test_cpython_features.py ============================================================================== --- py/dist/py/code/testing/test_cpython_features.py (original) +++ py/dist/py/code/testing/test_cpython_features.py Sun Jan 9 16:49:34 2005 @@ -1,16 +1,16 @@ -import new +import new -def test_new_code_object_carries_filename_through(): - class mystr(str): - pass +def test_new_code_object_carries_filename_through(): + class mystr(str): + pass filename = mystr("dummy") co = compile("hello\n", filename, 'exec') - assert not isinstance(co.co_filename, mystr) - c2 = new.code(co.co_argcount, co.co_nlocals, co.co_stacksize, - co.co_flags, co.co_code, co.co_consts, - co.co_names, co.co_varnames, - filename, - co.co_name, co.co_firstlineno, co.co_lnotab, + assert not isinstance(co.co_filename, mystr) + c2 = new.code(co.co_argcount, co.co_nlocals, co.co_stacksize, + co.co_flags, co.co_code, co.co_consts, + co.co_names, co.co_varnames, + filename, + co.co_name, co.co_firstlineno, co.co_lnotab, co.co_freevars, co.co_cellvars) - assert c2.co_filename is filename + assert c2.co_filename is filename Modified: py/dist/py/code/testing/test_excinfo.py ============================================================================== --- py/dist/py/code/testing/test_excinfo.py (original) +++ py/dist/py/code/testing/test_excinfo.py Sun Jan 9 16:49:34 2005 @@ -1,39 +1,39 @@ -import py -mypath = py.magic.autopath() +import py +mypath = py.magic.autopath() -def test_excinfo_simple(): - try: +def test_excinfo_simple(): + try: raise ValueError - except ValueError: + except ValueError: info = py.code.ExceptionInfo() - assert info.type == ValueError + assert info.type == ValueError -def test_excinfo_getstatement(): +def test_excinfo_getstatement(): def g(): raise ValueError - def f(): + def f(): g() - try: + try: f() - except ValueError: - info = py.code.ExceptionInfo() - l = list(info) - linenumbers = [f.func_code.co_firstlineno-1+3, - f.func_code.co_firstlineno-1+1, + except ValueError: + info = py.code.ExceptionInfo() + l = list(info) + linenumbers = [f.func_code.co_firstlineno-1+3, + f.func_code.co_firstlineno-1+1, g.func_code.co_firstlineno-1+1,] foundlinenumbers = [x.lineno for x in info] print l[0].frame.statement - assert foundlinenumbers == linenumbers - #for x in info: + assert foundlinenumbers == linenumbers + #for x in info: # print "%s:%d %s" %(x.path.relto(root), x.lineno, x.statement) #xxx # testchain for getentries test below -def f(): - raise ValueError -def g(): +def f(): + raise ValueError +def g(): f() -def h(): +def h(): g() def test_excinfo_getentries_nocut(): @@ -42,28 +42,28 @@ except ValueError: pass excinfo = py.code.ExceptionInfo() - entries = excinfo.getentries() - assert len(entries) == 4 # fragile + entries = excinfo.getentries() + assert len(entries) == 4 # fragile names = ['f','g','h'] - for entry in entries: - try: + for entry in entries: + try: names.remove(entry.frame.code.name) - except ValueError: - pass - assert not names + except ValueError: + pass + assert not names -def test_excinfo_getentries_cut(): - excinfo = py.test.raises(ValueError, h) +def test_excinfo_getentries_cut(): + excinfo = py.test.raises(ValueError, h) entries = excinfo.getentries( - lambda x: x.frame.code.name != 'raises', + lambda x: x.frame.code.name != 'raises', lambda x: x.frame.code.name != 'f') names = [x.frame.code.name for x in entries] assert names == ['h','g'] -def test_excinfo_getentries_type_error(): - excinfo = py.test.raises(ValueError, h) +def test_excinfo_getentries_type_error(): + excinfo = py.test.raises(ValueError, h) entries = excinfo.getentries( - lambda x: x.frame.code.name != 'raises', + lambda x: x.frame.code.name != 'raises', lambda x: x.frame.code.name != 'f') names = [x.frame.code.name for x in entries] assert names == ['h','g'] Modified: py/dist/py/code/testing/test_frame.py ============================================================================== --- py/dist/py/code/testing/test_frame.py (original) +++ py/dist/py/code/testing/test_frame.py Sun Jan 9 16:49:34 2005 @@ -1,10 +1,10 @@ import sys -from py.code import Frame +from py.code import Frame -def test_frame_getsourcelineno_myself(): - def func(): - return sys._getframe(0) - f = func() - f = Frame(f) - source, lineno = f.code.fullsource, f.lineno +def test_frame_getsourcelineno_myself(): + def func(): + return sys._getframe(0) + f = func() + f = Frame(f) + source, lineno = f.code.fullsource, f.lineno assert source[lineno].startswith(" return sys._getframe(0)") Modified: py/dist/py/code/testing/test_source.py ============================================================================== --- py/dist/py/code/testing/test_source.py (original) +++ py/dist/py/code/testing/test_source.py Sun Jan 9 16:49:34 2005 @@ -1,31 +1,31 @@ -from py.code import Source -import py +from py.code import Source +import py import sys def test_source_str_function(): x = Source("3") - assert str(x) == "3" + assert str(x) == "3" x = Source(" 3") - assert str(x) == "3" + assert str(x) == "3" x = Source(""" 3 - """) - assert str(x) == "\n3\n " + """) + assert str(x) == "\n3\n " -def test_source_from_function(): +def test_source_from_function(): source = py.code.Source(test_source_str_function) assert str(source).startswith('def test_source_str_function():') -def test_source_from_inner_function(): - def f(): - pass - source = py.code.Source(f, deindent=False) - assert str(source).startswith(' def f():') - source = py.code.Source(f) - assert str(source).startswith('def f():') - +def test_source_from_inner_function(): + def f(): + pass + source = py.code.Source(f, deindent=False) + assert str(source).startswith(' def f():') + source = py.code.Source(f) + assert str(source).startswith('def f():') + def test_source_putaround_simple(): source = Source("raise ValueError") source = source.putaround( @@ -48,126 +48,126 @@ assert ex.value.offset == 3 assert ex.value.text.strip(), 'x x' -def test_isparseable(): +def test_isparseable(): assert Source("hello").isparseable() assert Source("if 1:\n pass").isparseable() assert Source(" \nif 1:\n pass").isparseable() assert not Source(" \nif 1:\npass").isparseable() -class TestSliceAccess: +class TestSliceAccess: source = Source("""\ def f(x): pass def g(x): pass """) - def test_getrange(self): + def test_getrange(self): x = self.source[0:2] - assert x.isparseable() + assert x.isparseable() assert len(x.lines) == 2 - assert str(x) == "def f(x):\n pass" + assert str(x) == "def f(x):\n pass" - def test_getline(self): + def test_getline(self): x = self.source[0] - assert x == "def f(x):" + assert x == "def f(x):" -class TestCodeHacks: - def test_newcode(self): - from py.__impl__.code.source import newcode - def f(): +class TestCodeHacks: + def test_newcode(self): + from py.__impl__.code.source import newcode + def f(): pass co_filename = 'hello' - c = newcode(f.func_code, co_filename=co_filename) - assert c.co_filename is co_filename + c = newcode(f.func_code, co_filename=co_filename) + assert c.co_filename is co_filename - def test_newcode_withfilename(self): + def test_newcode_withfilename(self): from py.__impl__.code.source import newcode_withfilename source = py.code.Source(""" - def f(): - def g(): + def f(): + def g(): pass """) co = compile(str(source)+'\n', 'nada', 'exec') obj = 'hello' - newco = newcode_withfilename(co, obj) - def walkcode(co): - for x in co.co_consts: - if isinstance(x, type(co)): - for y in walkcode(x): - yield y - yield co - - names = [] - for code in walkcode(newco): - assert newco.co_filename == obj - assert newco.co_filename is obj - names.append(code.co_name) - assert 'f' in names - assert 'g' in names + newco = newcode_withfilename(co, obj) + def walkcode(co): + for x in co.co_consts: + if isinstance(x, type(co)): + for y in walkcode(x): + yield y + yield co + + names = [] + for code in walkcode(newco): + assert newco.co_filename == obj + assert newco.co_filename is obj + names.append(code.co_name) + assert 'f' in names + assert 'g' in names -class TestSourceParsingAndCompiling: +class TestSourceParsingAndCompiling: source = Source("""\ def f(x): - assert (x == - 3 + + assert (x == + 3 + 4) """).strip() - def test_compile(self): + def test_compile(self): co = py.code.compile("x=3") - exec co - assert x == 3 + exec co + assert x == 3 - def test_compile_and_getsource_simple(self): + def test_compile_and_getsource_simple(self): co = py.code.compile("x=3") - exec co - source = py.code.Source(co) + exec co + source = py.code.Source(co) assert str(source) == "x=3" def test_getstatement(self): #print str(self.source) - ass = str(self.source[1:]) - for i in range(1, 4): + ass = str(self.source[1:]) + for i in range(1, 4): #print "trying start in line %r" % self.source[i] - s = self.source.getstatement(i) + s = self.source.getstatement(i) #x = s.deindent() - assert str(s) == ass + assert str(s) == ass - def XXXtest_getstatement_within_constructs(self): + def XXXtest_getstatement_within_constructs(self): source = Source("""\ - try: - raise ValueError - finally: + try: + raise ValueError + finally: 42 - """) + """) stmt = source.getstatement(1) assert str(stmt).strip() == 'raise ValueError' xxx - co = source.compile() - try: - exec co - except ValueError: - excinfo = py.code.ExceptionInfo(py.std.sys.exc_info()) - l = list(excinfo) + co = source.compile() + try: + exec co + except ValueError: + excinfo = py.code.ExceptionInfo(py.std.sys.exc_info()) + l = list(excinfo) tb = l[0] inner = l[1] - print "inner frame-statement:", inner.frame.statement + print "inner frame-statement:", inner.frame.statement print "inner frame-lineno:", inner.frame.lineno - print "inner tb-statement:", inner.statement + print "inner tb-statement:", inner.statement print "inner tb-lineno:", inner.lineno print "...", repr(inner.frame.code.fullsource[inner.lineno]) - print "tb-statement:", tb.statement - print "tb-lineno:", tb.lineno + print "tb-statement:", tb.statement + print "tb-lineno:", tb.lineno XXX - def test_compile_and_getsource(self): - co = self.source.compile() - exec co + def test_compile_and_getsource(self): + co = self.source.compile() + exec co f(7) excinfo = py.test.raises(AssertionError, "f(6)") frame = list(excinfo)[-1].frame - stmt = frame.code.fullsource.getstatement(frame.lineno) + stmt = frame.code.fullsource.getstatement(frame.lineno) #print "block", str(block) assert str(stmt).strip().startswith('assert') @@ -175,9 +175,9 @@ class A: def __init__(self, *args): frame = sys._getframe(1) - self.source = py.code.Frame(frame).statement - - x = A('x', 'y') + self.source = py.code.Frame(frame).statement + + x = A('x', 'y') l = [i for i in x.source.lines if i.strip()] assert len(l) == 1 @@ -186,12 +186,12 @@ class A: def __init__(self, *args): frame = sys._getframe(1) - self.source = py.code.Frame(frame).statement - - x = A('x', + self.source = py.code.Frame(frame).statement + + x = A('x', 'y' \ - , - 'z') + , + 'z') l = [i for i in x.source.lines if i.strip()] assert len(l) == 4 @@ -202,13 +202,13 @@ excinfo = py.test.raises(TypeError, """ teardown = None try: - c(1) + c(1) finally: - if teardown: - teardown() + if teardown: + teardown() """) - source = list(excinfo)[-1].statement - assert str(source).strip() == 'c(1)' + source = list(excinfo)[-1].statement + assert str(source).strip() == 'c(1)' def test_getfuncsource_dynamic(): source = """ @@ -217,8 +217,8 @@ def g(): pass """ - co = py.code.compile(source) - exec co + co = py.code.compile(source) + exec co assert str(py.code.Source(f)).strip() == 'def f():\n raise ValueError' assert str(py.code.Source(g)).strip() == 'def g(): pass' Modified: py/dist/py/conftest.py ============================================================================== --- py/dist/py/conftest.py (original) +++ py/dist/py/conftest.py Sun Jan 9 16:49:34 2005 @@ -1,20 +1,20 @@ -#pythonexecutables = ('python2.2', 'python2.3',) -#pythonexecutable = 'python2.2' +#pythonexecutables = ('python2.2', 'python2.3',) +#pythonexecutable = 'python2.2' -# in the future we want to be able to say here: +# in the future we want to be able to say here: #def setup_module(extpy): -# mod = extpy.resolve() +# mod = extpy.resolve() # mod.module = 23 # directory = pypath.root.dirpath() import py rootdir = py.magic.autopath().dirpath().dirpath() - -# default values for options (modified from cmdline) -verbose = 0 -nocapture = False -collectonly = False -exitfirstproblem = False -fulltrace = False + +# default values for options (modified from cmdline) +verbose = 0 +nocapture = False +collectonly = False +exitfirstproblem = False +fulltrace = False showlocals = False -nomagic = False +nomagic = False Modified: py/dist/py/documentation/example/pytest/failure_demo.py ============================================================================== --- py/dist/py/documentation/example/pytest/failure_demo.py (original) +++ py/dist/py/documentation/example/pytest/failure_demo.py Sun Jan 9 16:49:34 2005 @@ -3,7 +3,7 @@ def otherfunc(a,b): assert a==b - + def somefunc(x,y): otherfunc(x,y) @@ -39,12 +39,12 @@ def test_startswith(self): s = "123" g = "456" - assert s.startswith(g) + assert s.startswith(g) def test_startswith_nested(self): - def f(): + def f(): return "123" - def g(): + def g(): return "456" assert f().startswith(g()) @@ -74,7 +74,7 @@ def test_raise(self): raise ValueError("demo error") - + def test_tupleerror(self): a,b = [1] @@ -87,16 +87,16 @@ if namenotexi: pass - def test_generator(self): - yield None + def test_generator(self): + yield None - def func1(self): + def func1(self): assert 41 == 42 - def test_generator2(self): + def test_generator2(self): yield self.func1 -# thanks to Matthew Scott for this test +# thanks to Matthew Scott for this test def test_dynamic_compile_shows_nicely(): src = 'def foo():\n assert 1 == 0\n' name = 'abc-123' @@ -105,7 +105,7 @@ exec code in module.__dict__ py.std.sys.modules[name] = module module.foo() - + def globf(x): return x+1 Modified: py/dist/py/documentation/example/pytest/test_setup_flow_example.py ============================================================================== --- py/dist/py/documentation/example/pytest/test_setup_flow_example.py (original) +++ py/dist/py/documentation/example/pytest/test_setup_flow_example.py Sun Jan 9 16:49:34 2005 @@ -25,18 +25,18 @@ """ For this example the control flow happens as follows:: import test_setup_flow_example setup_module(test_setup_flow_example) - setup_class(TestStateFullThing) + setup_class(TestStateFullThing) instance = TestStateFullThing() - setup_method(instance, instance.test_42) + setup_method(instance, instance.test_42) instance.test_42() - setup_method(instance, instance.test_23) + setup_method(instance, instance.test_23) instance.test_23() - teardown_class(TestStateFullThing) + teardown_class(TestStateFullThing) teardown_module(test_setup_flow_example) -Note that ``setup_class(TestStateFullThing)`` is called and not +Note that ``setup_class(TestStateFullThing)`` is called and not ``TestStateFullThing.setup_class()`` which would require you to insert ``setup_class = classmethod(setup_class)`` to make -your setup function callable. +your setup function callable. """ Modified: py/dist/py/documentation/rest_test.py ============================================================================== --- py/dist/py/documentation/rest_test.py (original) +++ py/dist/py/documentation/rest_test.py Sun Jan 9 16:49:34 2005 @@ -1,19 +1,19 @@ -from __future__ import generators +from __future__ import generators -import py +import py -pydir = py.magic.autopath(vars(py)).dirpath() -rest = pydir.join('bin', 'py.rest').getpymodule() +pydir = py.magic.autopath(vars(py)).dirpath() +rest = pydir.join('bin', 'py.rest').getpymodule() docdir = py.path.svnwc(pydir.join('documentation')) -def restcheck(path): - try: - import docutils - except ImportError: - py.test.skip("docutils not importable") - rest.process(path) - #assert not out +def restcheck(path): + try: + import docutils + except ImportError: + py.test.skip("docutils not importable") + rest.process(path) + #assert not out -def test_rest_files(): - for x in docdir.listdir('*.txt'): - yield restcheck, x +def test_rest_files(): + for x in docdir.listdir('*.txt'): + yield restcheck, x Modified: py/dist/py/env.py ============================================================================== --- py/dist/py/env.py (original) +++ py/dist/py/env.py Sun Jan 9 16:49:34 2005 @@ -1,8 +1,8 @@ -#!/usr/bin/python +#!/usr/bin/python import sys, os -progpath = sys.argv[0] +progpath = sys.argv[0] packagedir = os.path.abspath(os.path.dirname(progpath)) packagename = os.path.basename(packagedir) bindir = os.path.join(packagedir, 'bin') @@ -20,4 +20,4 @@ if sys.platform != 'win32': print prepend_unixpath('PATH', bindir) print prepend_unixpath('PATH', tooldir) - print prepend_unixpath('PYTHONPATH', rootdir) + print prepend_unixpath('PYTHONPATH', rootdir) Modified: py/dist/py/execnet/bin/quitserver.py ============================================================================== --- py/dist/py/execnet/bin/quitserver.py (original) +++ py/dist/py/execnet/bin/quitserver.py Sun Jan 9 16:49:34 2005 @@ -1,6 +1,6 @@ """ - send a "quit" signal to a remote server + send a "quit" signal to a remote server """ Modified: py/dist/py/execnet/bin/shell.py ============================================================================== --- py/dist/py/execnet/bin/shell.py (original) +++ py/dist/py/execnet/bin/shell.py Sun Jan 9 16:49:34 2005 @@ -1,14 +1,14 @@ """ -a remote python shell +a remote python shell -for injection into startserver.py +for injection into startserver.py """ import sys, os, socket, select try: - clientsock + clientsock except NameError: - print "client side starting" + print "client side starting" import sys host, port = sys.argv[1].split(':') port = int(port) @@ -59,8 +59,8 @@ line = filein.readline() if len(line)==0: raise EOFError,"nothing" #print >>sys.stderr,"got line: " + line - if line.strip(): - oldout, olderr = sys.stdout, sys.stderr + if line.strip(): + oldout, olderr = sys.stdout, sys.stderr sys.stdout, sys.stderr = clientfile, clientfile try: try: Modified: py/dist/py/execnet/bin/startserver.py ============================================================================== --- py/dist/py/execnet/bin/startserver.py (original) +++ py/dist/py/execnet/bin/startserver.py Sun Jan 9 16:49:34 2005 @@ -1,23 +1,23 @@ #! /usr/bin/env python """ - start socket based minimal readline exec server + start socket based minimal readline exec server """ # this part of the program only executes on the server side # progname = 'socket_readline_exec_server-1.2' -debug = 0 +debug = 0 import sys, socket, os -if debug: # and not os.isatty(sys.stdin.fileno()): - f = open('/tmp/execnet-socket-pyout.log', 'a', 0) - old = sys.stdout, sys.stderr - sys.stdout = sys.stderr = f +if debug: # and not os.isatty(sys.stdin.fileno()): + f = open('/tmp/execnet-socket-pyout.log', 'a', 0) + old = sys.stdout, sys.stderr + sys.stdout = sys.stderr = f -def execloop(serversock): - while 1: +def execloop(serversock): + while 1: try: print progname, 'Entering Accept loop', serversock.getsockname() clientsock,address = serversock.accept() @@ -27,17 +27,17 @@ source = clientfile.readline() clientfile.close() g = {'clientsock' : clientsock, 'address' : address} - source = eval(source) + source = eval(source) if not source: - break + break co = compile(source+'\n', source, 'exec') - print progname, 'compiled source, executing' + print progname, 'compiled source, executing' try: exec co in g - finally: - print progname, 'finished executing code' + finally: + print progname, 'finished executing code' except (SystemExit, KeyboardInterrupt): - break + break #except: # import traceback # traceback.print_exc() @@ -56,7 +56,7 @@ execloop(serversock) finally: print "leaving socketserver execloop" - serversock.shutdown(2) + serversock.shutdown(2) if __name__ == '__main__': import sys @@ -64,6 +64,6 @@ hostport = sys.argv[1] else: hostport = ':8888' - serversock = bind_and_listen(hostport) + serversock = bind_and_listen(hostport) startserver(serversock) Modified: py/dist/py/execnet/channel.py ============================================================================== --- py/dist/py/execnet/channel.py (original) +++ py/dist/py/execnet/channel.py Sun Jan 9 16:49:34 2005 @@ -1,4 +1,4 @@ -import threading +import threading import Queue if 'Message' not in globals(): from py.__impl__.execnet.message import Message @@ -8,7 +8,7 @@ def __init__(self, gateway, id): assert isinstance(id, int) self.gateway = gateway - self.id = id + self.id = id self._items = Queue.Queue() self._closeevent = threading.Event() #self._depchannel = [] @@ -18,99 +18,99 @@ return "" % (self.id, flag) def isclosed(self): - return self._closeevent.isSet() + return self._closeevent.isSet() def open(self, mode='w'): assert mode == 'w' - return ChannelFile(self) + return ChannelFile(self) def close(self, error=None): - """ close down this channel on both sides. """ - if self.id in self.gateway.channelfactory: - put = self.gateway._outgoing.put - if error is not None: - put(Message.CHANNEL_CLOSE_ERROR(self.id, str(error))) + """ close down this channel on both sides. """ + if self.id in self.gateway.channelfactory: + put = self.gateway._outgoing.put + if error is not None: + put(Message.CHANNEL_CLOSE_ERROR(self.id, str(error))) else: put(Message.CHANNEL_CLOSE(self.id)) self._close() - def _close(self, finalitem=EOFError()): + def _close(self, finalitem=EOFError()): if self.id in self.gateway.channelfactory: del self.gateway.channelfactory[self.id] - self._finalitem = finalitem - #for x in self._depchannel: - # x._close() - self._items.put(finalitem) + self._finalitem = finalitem + #for x in self._depchannel: + # x._close() + self._items.put(finalitem) self._closeevent.set() def newchannel(self): - """ return a new channel. """ + """ return a new channel. """ chan = self.gateway.channelfactory.new() return chan def _receivechannel(self, newid): - """ receive a remotely created new (sub)channel. """ - newchannel = Channel(self.gateway, newid) - self.gateway.channelfactory[newid] = newchannel - #self._depchannel.append(newchannel) - self._items.put(newchannel) + """ receive a remotely created new (sub)channel. """ + newchannel = Channel(self.gateway, newid) + self.gateway.channelfactory[newid] = newchannel + #self._depchannel.append(newchannel) + self._items.put(newchannel) - def waitclose(self, timeout): + def waitclose(self, timeout): """ wait until this channel is closed. Note that a closed - channel may still hold items that can be received or - send. Also note that exceptions from the other side will be - reraised as gateway.RemoteError exceptions containing - a textual representation of the remote traceback. + channel may still hold items that can be received or + send. Also note that exceptions from the other side will be + reraised as gateway.RemoteError exceptions containing + a textual representation of the remote traceback. """ - self._closeevent.wait(timeout=timeout) + self._closeevent.wait(timeout=timeout) if not self._closeevent.isSet(): raise IOError, "Timeout" if isinstance(self._finalitem, self.gateway.RemoteError): - raise self._finalitem - - def send(self, item): - """sends the given item to the other side of the channel, - possibly blocking if the sender queue is full. - Note that an item needs to be marshallable. + raise self._finalitem + + def send(self, item): + """sends the given item to the other side of the channel, + possibly blocking if the sender queue is full. + Note that an item needs to be marshallable. """ if isinstance(item, Channel): - data = Message.CHANNEL_NEW(self.id, item.id) - else: - data = Message.CHANNEL_DATA(self.id, item) + data = Message.CHANNEL_NEW(self.id, item.id) + else: + data = Message.CHANNEL_DATA(self.id, item) self.gateway._outgoing.put(data) def receive(self): - """receives an item that was sent from the other side, - possibly blocking if there is none. - Note that exceptions from the other side will be - reraised as gateway.RemoteError exceptions containing - a textual representation of the remote traceback. + """receives an item that was sent from the other side, + possibly blocking if there is none. + Note that exceptions from the other side will be + reraised as gateway.RemoteError exceptions containing + a textual representation of the remote traceback. """ - x = self._items.get() - if isinstance(x, EOFError): - raise x + x = self._items.get() + if isinstance(x, EOFError): + raise x return x -# -# helpers +# +# helpers # class ChannelFactory(object): - def __init__(self, gateway, startcount=1): + def __init__(self, gateway, startcount=1): self._dict = dict() self._lock = threading.RLock() self.gateway = gateway self.count = startcount - def new(self, id=None): + def new(self, id=None): """ create a new Channel with 'id' (or create new id if None). """ self._lock.acquire() try: if id is None: - id = self.count - self.count += 2 - channel = Channel(self.gateway, id) - self._dict[id] = channel + id = self.count + self.count += 2 + channel = Channel(self.gateway, id) + self._dict[id] = channel return channel finally: self._lock.release() @@ -122,13 +122,13 @@ finally: self._lock.release() - def values(self): + def values(self): self._lock.acquire() try: - return self._dict.values() + return self._dict.values() finally: self._lock.release() - + def __getitem__(self, key): self._lock.acquire() try: @@ -152,11 +152,11 @@ class ChannelFile: def __init__(self, channel): self.channel = channel - + def write(self, out): if self.channel.isclosed(): return - self.channel.send(out) + self.channel.send(out) def flush(self): pass @@ -165,15 +165,15 @@ self.channel.close() def __repr__(self): - state = self.channel.isclosed() and 'closed' or 'open' - return '' %(self.channel.id, state) + state = self.channel.isclosed() and 'closed' or 'open' + return '' %(self.channel.id, state) def receive2file(channel, f): - while 1: + while 1: try: - out = channel.receive() - except EOFError: - break - f.write(out) + out = channel.receive() + except EOFError: + break + f.write(out) f.flush() Modified: py/dist/py/execnet/gateway.py ============================================================================== --- py/dist/py/execnet/gateway.py (original) +++ py/dist/py/execnet/gateway.py Sun Jan 9 16:49:34 2005 @@ -1,64 +1,64 @@ import sys import os import threading -import Queue +import Queue import traceback import atexit # XXX the following line should not be here g = globals() if 'Message' not in g: - from py.code import Source + from py.code import Source from py.__impl__.execnet.channel import ChannelFactory, Channel - from py.__impl__.execnet.message import Message + from py.__impl__.execnet.message import Message assert Message and ChannelFactory, "Import/Configuration Error" import os -debug = 0 # open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') +debug = 0 # open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') -sysex = (KeyboardInterrupt, SystemExit) +sysex = (KeyboardInterrupt, SystemExit) class RemoteError(EOFError): """ Contains an Exceptions from the other side. """ - def __init__(self, formatted): - self.formatted = formatted - EOFError.__init__(self) + def __init__(self, formatted): + self.formatted = formatted + EOFError.__init__(self) def __str__(self): - return self.formatted + return self.formatted def __repr__(self): - return "%s: %s" %(self.__class__.__name__, self.formatted) + return "%s: %s" %(self.__class__.__name__, self.formatted) class Gateway(object): num_worker_threads = 2 RemoteError = RemoteError - def __init__(self, io, startcount=2): + def __init__(self, io, startcount=2): self.io = io self._execqueue = Queue.Queue() self._outgoing = Queue.Queue() - self.channelfactory = ChannelFactory(self, startcount) + self.channelfactory = ChannelFactory(self, startcount) self._exitlock = threading.Lock() self.iothreads = [ threading.Thread(target=self.thread_receiver, name='receiver'), threading.Thread(target=self.thread_sender, name='sender'), ] - self.workerthreads = w = [] + self.workerthreads = w = [] for x in range(self.num_worker_threads): - w.append(threading.Thread(target=self.thread_executor, + w.append(threading.Thread(target=self.thread_executor, name='executor %d' % x)) - for x in self.iothreads + w: + for x in self.iothreads + w: x.start() if not _gateways: - atexit.register(cleanup_atexit) - _gateways.append(self) + atexit.register(cleanup_atexit) + _gateways.append(self) def _stopexec(self): - if self.workerthreads: - for x in self.workerthreads: - self._execqueue.put(None) + if self.workerthreads: + for x in self.workerthreads: + self._execqueue.put(None) for x in self.workerthreads: if x.isAlive(): self.trace("joining %r" % x) @@ -66,21 +66,21 @@ self.workerthreads[:] = [] self.trace("workerthreads are empty now") - def exit(self): + def exit(self): self._exitlock.acquire() try: #for channel in self.channelfactory.values(): # channel.close() if self.workerthreads: self._stopexec() - self._outgoing.put(Message.EXIT_GATEWAY()) + self._outgoing.put(Message.EXIT_GATEWAY()) return True finally: self._exitlock.release() def join(self): current = threading.currentThread() - for x in self.iothreads: + for x in self.iothreads: if x != current and x.isAlive(): self.trace("joining %s" % x) x.join() @@ -91,75 +91,75 @@ l = "\n".join(args).split(os.linesep) id = getid(self) for x in l: - print >>debug, x + print >>debug, x debug.flush() - except sysex: + except sysex: raise except: traceback.print_exc() def traceex(self, excinfo): - l = traceback.format_exception(*excinfo) + l = traceback.format_exception(*excinfo) errortext = "".join(l) self.trace(errortext) def thread_receiver(self): - """ thread to read and handle Messages half-sync-half-async. """ + """ thread to read and handle Messages half-sync-half-async. """ try: - while 1: + while 1: try: - msg = Message.readfrom(self.io) - self.trace("received <- %r" % msg) - msg.received(self) - except sysex: - raise + msg = Message.readfrom(self.io) + self.trace("received <- %r" % msg) + msg.received(self) + except sysex: + raise except: - self.traceex(sys.exc_info()) + self.traceex(sys.exc_info()) break finally: self.trace('leaving %r' % threading.currentThread()) def thread_sender(self): - """ thread to send Messages over the wire. """ + """ thread to send Messages over the wire. """ try: - while 1: + while 1: msg = self._outgoing.get() try: - msg.writeto(self.io) - except: + msg.writeto(self.io) + except: excinfo = sys.exc_info() - self.traceex(excinfo) - msg.post_sent(self, excinfo) + self.traceex(excinfo) + msg.post_sent(self, excinfo) raise else: - self.trace('sent -> %r' % msg) + self.trace('sent -> %r' % msg) msg.post_sent(self) - finally: + finally: self.trace('leaving %r' % threading.currentThread()) def thread_executor(self): - """ worker thread to execute source objects from the execution queue. """ + """ worker thread to execute source objects from the execution queue. """ try: - while 1: + while 1: task = self._execqueue.get() - if task is None: + if task is None: break - channel, source = task + channel, source = task try: - loc = { 'channel' : channel } - self.trace("execution starts:", repr(source)[:50]) - try: + loc = { 'channel' : channel } + self.trace("execution starts:", repr(source)[:50]) + try: co = compile(source+'\n', '', 'exec') - exec co in loc - finally: - self.trace("execution finished:", repr(source)[:50]) + exec co in loc + finally: + self.trace("execution finished:", repr(source)[:50]) except (KeyboardInterrupt, SystemExit): raise except: excinfo = sys.exc_info() - l = traceback.format_exception(*excinfo) + l = traceback.format_exception(*excinfo) errortext = "".join(l) - channel.close(errortext) - self.trace(errortext) + channel.close(errortext) + self.trace(errortext) else: channel.close() finally: @@ -167,21 +167,21 @@ # _____________________________________________________________________ # - # High Level Interface + # High Level Interface # _____________________________________________________________________ - + def remote_exec(self, source): - """ return channel object for communicating with the asynchronously - executing 'source' code which will have a corresponding 'channel' - object in its executing namespace. - """ + """ return channel object for communicating with the asynchronously + executing 'source' code which will have a corresponding 'channel' + object in its executing namespace. + """ source = str(Source(source)) channel = self.channelfactory.new() self._outgoing.put(Message.CHANNEL_OPEN(channel.id, source)) return channel def getid(gw, cache={}): - name = gw.__class__.__name__ + name = gw.__class__.__name__ try: return cache.setdefault(name, {})[id(gw)] except KeyError: @@ -190,8 +190,8 @@ _gateways = [] def cleanup_atexit(): - if debug: + if debug: print >>debug, "="*20 + "cleaning up" + "=" * 20 debug.flush() - for x in _gateways: + for x in _gateways: x.exit() Modified: py/dist/py/execnet/inputoutput.py ============================================================================== --- py/dist/py/execnet/inputoutput.py (original) +++ py/dist/py/execnet/inputoutput.py Sun Jan 9 16:49:34 2005 @@ -1,13 +1,13 @@ """ InputOutput Classes used for connecting gateways - across process or computer barriers. + across process or computer barriers. """ import socket, os, sys class SocketIO: server_stmt = """ -io = SocketIO(clientsock) +io = SocketIO(clientsock) import sys try: sys.stdout = sys.stderr = open('/tmp/execnet-socket-debug.log', 'a', 0) @@ -17,8 +17,8 @@ """ error = (socket.error, EOFError) - def __init__(self, sock): - self.sock = sock + def __init__(self, sock): + self.sock = sock try: sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) sock.setsockopt(socket.SOL_IP, socket.IP_TOS, 0x10) # IPTOS_LOWDELAY @@ -38,11 +38,11 @@ return buf def write(self, data): - """write out all bytes to the socket. """ + """write out all bytes to the socket. """ self.sock.sendall(data) def close_read(self): - if self.readable: + if self.readable: self.sock.shutdown(0) self.readable = None def close_write(self): @@ -62,12 +62,12 @@ """ error = (IOError, OSError, EOFError) - def __init__(self, infile, outfile): - if sys.platform == 'win32': - import msvcrt - msvcrt.setmode(infile.fileno(), os.O_BINARY) - msvcrt.setmode(outfile.fileno(), os.O_BINARY) - self.outfile, self.infile = infile, outfile + def __init__(self, infile, outfile): + if sys.platform == 'win32': + import msvcrt + msvcrt.setmode(infile.fileno(), os.O_BINARY) + msvcrt.setmode(outfile.fileno(), os.O_BINARY) + self.outfile, self.infile = infile, outfile self.readable = self.writeable = True def read(self, numbytes): @@ -81,7 +81,7 @@ return s def write(self, data): - """write out all bytes to the pipe. """ + """write out all bytes to the pipe. """ #import sys #print >> sys.stderr, "writing: %r" % data self.outfile.write(data) @@ -89,9 +89,9 @@ def close_read(self): if self.readable: - os.close(self.infile.fileno()) + os.close(self.infile.fileno()) self.readable = None def close_write(self): if self.writeable: - os.close(self.outfile.fileno()) + os.close(self.outfile.fileno()) self.writeable = None Modified: py/dist/py/execnet/message.py ============================================================================== --- py/dist/py/execnet/message.py (original) +++ py/dist/py/execnet/message.py Sun Jan 9 16:49:34 2005 @@ -1,43 +1,43 @@ import struct -#import marshal +#import marshal # ___________________________________________________________________________ # -# Messages +# Messages # ___________________________________________________________________________ -# the size of a number on the wire +# the size of a number on the wire numsize = struct.calcsize("!i") class Message: """ encapsulates Messages and their wire protocol. """ _types = {} - def __init__(self, channelid=0, data=''): - self.channelid = channelid - self.data = data + def __init__(self, channelid=0, data=''): + self.channelid = channelid + self.data = data def writeto(self, io): # big XXX and all this # data = marshal.dumps(self.data) # doesn't work for exchanging data across Python version :-((( data = repr(self.data) # argh - + header = struct.pack("!iii", self.msgtype, self.channelid, len(data)) io.write(header) - io.write(data) + io.write(data) - def readfrom(cls, io): - header = io.read(numsize*3) + def readfrom(cls, io): + header = io.read(numsize*3) msgtype, senderid, stringlen = struct.unpack("!iii", header) - if stringlen: + if stringlen: string = io.read(stringlen) # same big XXX as in writeto() # string = marshal.loads(string) string = eval(string, {}) else: - string = '' + string = '' msg = cls._types[msgtype](senderid, string) - return msg - readfrom = classmethod(readfrom) + return msg + readfrom = classmethod(readfrom) def post_sent(self, gateway, excinfo=None): pass @@ -45,29 +45,29 @@ def __repr__(self): r = repr(self.data) if len(r) > 50: - return "" %(self.__class__.__name__, + return "" %(self.__class__.__name__, self.channelid, len(r)) - else: - return "" %(self.__class__.__name__, + else: + return "" %(self.__class__.__name__, self.channelid, self.data) def _setupmessages(): # # EXIT_GATEWAY and STOP_RECEIVING are messages to cleanly - # bring down the IO and gateway connection + # bring down the IO and gateway connection # # First an EXIT_GATEWAY message is send which results - # on the other side's receive_handle to send send - # a STOP_RECEIVING message + # on the other side's receive_handle to send send + # a STOP_RECEIVING message # class EXIT_GATEWAY(Message): def received(self, gateway): gateway._stopexec() - gateway._outgoing.put(self.STOP_RECEIVING()) - for x in gateway.channelfactory.values(): + gateway._outgoing.put(self.STOP_RECEIVING()) + for x in gateway.channelfactory.values(): x._close() - raise SystemExit + raise SystemExit def post_sent(self, gateway, excinfo=None): gateway.io.close_write() raise SystemExit @@ -77,33 +77,33 @@ # as the sender side will have closed the io # already. With sockets closing it would raise # a Transport Not Connected exception - for x in gateway.channelfactory.values(): + for x in gateway.channelfactory.values(): x._close() - raise SystemExit + raise SystemExit def post_sent(self, gateway, excinfo=None): gateway.io.close_write() raise SystemExit - + class CHANNEL_OPEN(Message): def received(self, gateway): - channel = gateway.channelfactory.new(self.channelid) - gateway._execqueue.put((channel, self.data)) + channel = gateway.channelfactory.new(self.channelid) + gateway._execqueue.put((channel, self.data)) class CHANNEL_NEW(Message): def received(self, gateway): - newid = self.data - channel = gateway.channelfactory[self.channelid] + newid = self.data + channel = gateway.channelfactory[self.channelid] channel._receivechannel(newid) class CHANNEL_DATA(Message): def received(self, gateway): channel = gateway.channelfactory[self.channelid] - channel._items.put(self.data) + channel._items.put(self.data) class CHANNEL_CLOSE(Message): def received(self, gateway): channel = gateway.channelfactory[self.channelid] - channel._close() + channel._close() class CHANNEL_CLOSE_ERROR(Message): def received(self, gateway): channel = gateway.channelfactory[self.channelid] @@ -111,10 +111,10 @@ classes = [x for x in locals().values() if hasattr(x, '__bases__')] classes.sort(lambda x,y : cmp(x.__name__, y.__name__)) i = 0 - for cls in classes: - Message._types[i] = cls + for cls in classes: + Message._types[i] = cls cls.msgtype = i - setattr(Message, cls.__name__, cls) + setattr(Message, cls.__name__, cls) i+=1 _setupmessages() Modified: py/dist/py/execnet/register.py ============================================================================== --- py/dist/py/execnet/register.py (original) +++ py/dist/py/execnet/register.py Sun Jan 9 16:49:34 2005 @@ -8,26 +8,26 @@ class InstallableGateway(gateway.Gateway): """ initialize gateways on both sides of a inputoutput object. """ - def __init__(self, io): - self.remote_bootstrap_gateway(io) + def __init__(self, io): + self.remote_bootstrap_gateway(io) gateway.Gateway.__init__(self, io=io, startcount=1) - def remote_bootstrap_gateway(self, io, extra=''): - """ return Gateway with a asynchronously remotely - initialized counterpart Gateway (which may or may not succeed). - Note that the other sides gateways starts enumerating + def remote_bootstrap_gateway(self, io, extra=''): + """ return Gateway with a asynchronously remotely + initialized counterpart Gateway (which may or may not succeed). + Note that the other sides gateways starts enumerating its channels with even numbers while the sender - gateway starts with odd numbers. This allows to - uniquely identify channels across both sides. + gateway starts with odd numbers. This allows to + uniquely identify channels across both sides. """ - bootstrap = [ - extra, - inspect.getsource(inputoutput), - inspect.getsource(message), - inspect.getsource(channel), - inspect.getsource(gateway), - io.server_stmt, - "Gateway(io=io, startcount=2).join()", + bootstrap = [ + extra, + inspect.getsource(inputoutput), + inspect.getsource(message), + inspect.getsource(channel), + inspect.getsource(gateway), + io.server_stmt, + "Gateway(io=io, startcount=2).join()", ] source = "\n".join(bootstrap) self.trace("sending gateway bootstrap code") @@ -36,53 +36,53 @@ class PopenCmdGateway(InstallableGateway): def __init__(self, cmd): infile, outfile = os.popen2(cmd) - io = inputoutput.Popen2IO(infile, outfile) + io = inputoutput.Popen2IO(infile, outfile) super(PopenCmdGateway, self).__init__(io=io) - self._pidchannel = self.remote_exec(""" - import os - channel.send(os.getpid()) - """) + self._pidchannel = self.remote_exec(""" + import os + channel.send(os.getpid()) + """) def exit(self): if not super(PopenCmdGateway, self).exit(): return try: pid = self._pidchannel.receive() - self._pidchannel.waitclose(timeout=0.5) - except IOError: + self._pidchannel.waitclose(timeout=0.5) + except IOError: self.trace("could not receive child PID") else: - self.trace("waiting for pid %s" % pid) + self.trace("waiting for pid %s" % pid) try: - os.waitpid(pid, 0) - except OSError: - self.trace("child process %s already dead?" %pid) + os.waitpid(pid, 0) + except OSError: + self.trace("child process %s already dead?" %pid) class PopenGateway(PopenCmdGateway): - # use sysfind/sysexec/subprocess instead of os.popen? + # use sysfind/sysexec/subprocess instead of os.popen? def __init__(self, python=sys.executable): cmd = '%s -u -c "exec input()"' % python super(PopenGateway, self).__init__(cmd) - def remote_bootstrap_gateway(self, io, extra=''): - # XXX the following hack helps us to import the same version - # of the py lib, but only works for PopenGateways - # --> we need proper remote imports working + def remote_bootstrap_gateway(self, io, extra=''): + # XXX the following hack helps us to import the same version + # of the py lib, but only works for PopenGateways + # --> we need proper remote imports working # across any kind of gateway! - plist = os.environ['PYTHONPATH'].split(':') - s = "import sys ; sys.path[:0] = %r" % (plist,) - s = "\n".join([extra, s]) - super(PopenGateway, self).remote_bootstrap_gateway(io, s) + plist = os.environ['PYTHONPATH'].split(':') + s = "import sys ; sys.path[:0] = %r" % (plist,) + s = "\n".join([extra, s]) + super(PopenGateway, self).remote_bootstrap_gateway(io, s) class SocketGateway(InstallableGateway): - def __init__(self, host, port): + def __init__(self, host, port): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.host = host = str(host) - self.port = port = int(port) + self.host = host = str(host) + self.port = port = int(port) sock.connect((host, port)) - io = inputoutput.SocketIO(sock) - InstallableGateway.__init__(self, io=io) + io = inputoutput.SocketIO(sock) + InstallableGateway.__init__(self, io=io) class SshGateway(PopenCmdGateway): def __init__(self, host, port=None, username=None, remotepython='python'): @@ -117,7 +117,7 @@ callbacks = self.callbacks = {} answerid = id(callback) self.callbacks[answerid] = callback - + self.exec_remote(''' import sys, StringIO try: Modified: py/dist/py/execnet/testing/__init__.py ============================================================================== --- py/dist/py/execnet/testing/__init__.py (original) +++ py/dist/py/execnet/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# Modified: py/dist/py/execnet/testing/sshtesting.py ============================================================================== --- py/dist/py/execnet/testing/sshtesting.py (original) +++ py/dist/py/execnet/testing/sshtesting.py Sun Jan 9 16:49:34 2005 @@ -4,9 +4,9 @@ import py -#REMOTE_HOST = 'codespeak.net' -#REMOTE_HOSTNAME = 'thoth.codespeak.net' -REMOTE_HOST = 'localhost' # you need to have a local ssh-daemon running! +#REMOTE_HOST = 'codespeak.net' +#REMOTE_HOSTNAME = 'thoth.codespeak.net' +REMOTE_HOST = 'localhost' # you need to have a local ssh-daemon running! REMOTE_HOSTNAME = py.std.socket.gethostname() # the remote's socket.gethostname() def test_sshgateway(): Modified: py/dist/py/execnet/testing/test/test_pickle.py ============================================================================== --- py/dist/py/execnet/testing/test/test_pickle.py (original) +++ py/dist/py/execnet/testing/test/test_pickle.py Sun Jan 9 16:49:34 2005 @@ -18,11 +18,11 @@ pickler1.dump(d) f1.seek(0) d_other = unpickler2.load() - - # translate unpickler2 memo to pickler2 - pickler2.memo = dict([(id(obj), (int(x), obj)) + + # translate unpickler2 memo to pickler2 + pickler2.memo = dict([(id(obj), (int(x), obj)) for x, obj in unpickler2.memo.items()]) - + pickler2.dump(d_other) f2.seek(0) @@ -30,13 +30,13 @@ d_back = unpickler1.load() - assert d is d_back + assert d is d_back def test_cpickle(): import cPickle pickletest(cPickle) def test_pickle(): - import pickle + import pickle pickletest(pickle) Modified: py/dist/py/execnet/testing/test_gateway.py ============================================================================== --- py/dist/py/execnet/testing/test_gateway.py (original) +++ py/dist/py/execnet/testing/test_gateway.py Sun Jan 9 16:49:34 2005 @@ -1,7 +1,7 @@ import os, sys -import py -from py.__impl__.execnet import gateway -mypath = py.magic.autopath() +import py +from py.__impl__.execnet import gateway +mypath = py.magic.autopath() from StringIO import StringIO @@ -9,11 +9,11 @@ def test_wire_protocol(self): for cls in gateway.Message._types.values(): one = StringIO() - cls(42, '23').writeto(one) + cls(42, '23').writeto(one) two = StringIO(one.getvalue()) msg = gateway.Message.readfrom(two) - assert isinstance(msg, cls) - assert msg.channelid == 42 + assert isinstance(msg, cls) + assert msg.channelid == 42 assert msg.data == '23' assert isinstance(repr(msg), str) # == "" %(msg.__class__.__name__, ) @@ -30,39 +30,39 @@ def test_factory_getitem(self): chan1 = self.fac.new() - assert self.fac[chan1.id] == chan1 + assert self.fac[chan1.id] == chan1 chan2 = self.fac.new() assert self.fac[chan2.id] == chan2 - + def test_factory_delitem(self): chan1 = self.fac.new() - assert self.fac[chan1.id] == chan1 + assert self.fac[chan1.id] == chan1 del self.fac[chan1.id] py.test.raises(KeyError, self.fac.__getitem__, chan1.id) def test_factory_setitem(self): channel = gateway.Channel(None, 12) self.fac[channel.id] = channel - assert self.fac[channel.id] == channel + assert self.fac[channel.id] == channel def test_channel_timeouterror(self): - channel = self.fac.new() + channel = self.fac.new() py.test.raises(IOError, channel.waitclose, timeout=0.01) -class PopenGatewayTestSetup: +class PopenGatewayTestSetup: def setup_class(cls): - cls.gw = py.execnet.PopenGateway() + cls.gw = py.execnet.PopenGateway() def teardown_class(cls): - cls.gw.exit() + cls.gw.exit() -class BasicRemoteExecution: +class BasicRemoteExecution: def test_correct_setup(self): - assert self.gw.workerthreads and self.gw.iothreads + assert self.gw.workerthreads and self.gw.iothreads - def test_remote_exec_waitclose(self): - channel = self.gw.remote_exec('pass') - channel.waitclose(timeout=3.0) + def test_remote_exec_waitclose(self): + channel = self.gw.remote_exec('pass') + channel.waitclose(timeout=3.0) def test_remote_exec_channel_anonymous(self): channel = self.gw.remote_exec(''' @@ -75,33 +75,33 @@ def test_channel_close_and_then_receive_error(self): channel = self.gw.remote_exec('raise ValueError') - py.test.raises(gateway.RemoteError, channel.receive) + py.test.raises(gateway.RemoteError, channel.receive) def test_channel_close_and_then_receive_error_multiple(self): channel = self.gw.remote_exec('channel.send(42) ; raise ValueError') x = channel.receive() - assert x == 42 - py.test.raises(gateway.RemoteError, channel.receive) + assert x == 42 + py.test.raises(gateway.RemoteError, channel.receive) def test_channel_close(self): channel = self.gw.channelfactory.new() - channel._close() + channel._close() channel.waitclose(0.1) def test_channel_close_error(self): channel = self.gw.channelfactory.new() - channel._close(gateway.RemoteError("error")) - py.test.raises(gateway.RemoteError, channel.waitclose, 0.01) + channel._close(gateway.RemoteError("error")) + py.test.raises(gateway.RemoteError, channel.waitclose, 0.01) def test_channel_passing_over_channel(self): channel = self.gw.remote_exec(''' c = channel.newchannel() - channel.send(c) + channel.send(c) c.send(42) ''') c = channel.receive() x = c.receive() - assert x == 42 + assert x == 42 # check that the both sides previous channels are really gone channel.waitclose(0.3) @@ -112,18 +112,18 @@ ''' % (channel.id)) newchan.waitclose(0.3) -class TestBasicPopenGateway(PopenGatewayTestSetup, BasicRemoteExecution): +class TestBasicPopenGateway(PopenGatewayTestSetup, BasicRemoteExecution): def test_many_popen(self): num = 4 l = [] for i in range(num): l.append(py.execnet.PopenGateway()) channels = [] - for gw in l: + for gw in l: channel = gw.remote_exec("""channel.send(42)""") channels.append(channel) try: - while channels: + while channels: channel = channels.pop() try: ret = channel.receive() @@ -131,63 +131,63 @@ finally: channel.gateway.exit() finally: - for x in channels: + for x in channels: x.gateway.exit() class SocketGatewaySetup: def setup_class(cls): portrange = (7770, 7800) - cls.proxygw = py.execnet.PopenGateway() - socketserverbootstrap = py.code.Source( - mypath.dirpath().dirpath('bin', 'startserver.py').read(), + cls.proxygw = py.execnet.PopenGateway() + socketserverbootstrap = py.code.Source( + mypath.dirpath().dirpath('bin', 'startserver.py').read(), """ - import socket - portrange = channel.receive() - for i in portrange: + import socket + portrange = channel.receive() + for i in portrange: try: sock = bind_and_listen(("localhost", i)) - except socket.error: + except socket.error: print "got error" import traceback traceback.print_exc() continue else: - channel.send(i) + channel.send(i) startserver(sock) break else: - channel.send(None) + channel.send(None) """) - # open a gateway to a fresh child process + # open a gateway to a fresh child process cls.proxygw = py.execnet.PopenGateway() # execute asynchronously the above socketserverbootstrap on the other - channel = cls.proxygw.remote_exec(socketserverbootstrap) + channel = cls.proxygw.remote_exec(socketserverbootstrap) # send parameters for the for-loop - channel.send((7770, 7800)) + channel.send((7770, 7800)) # # the other side should start the for loop now, we # wait for the result # - cls.listenport = channel.receive() - if cls.listenport is None: + cls.listenport = channel.receive() + if cls.listenport is None: raise IOError, "could not setup remote SocketServer" - cls.gw = py.execnet.SocketGateway('localhost', cls.listenport) - print "initialized socket gateway on port", cls.listenport + cls.gw = py.execnet.SocketGateway('localhost', cls.listenport) + print "initialized socket gateway on port", cls.listenport def teardown_class(cls): - print "trying to tear down remote socket gateway" - cls.gw.exit() - if cls.gw.port: - print "trying to tear down remote socket loop" + print "trying to tear down remote socket gateway" + cls.gw.exit() + if cls.gw.port: + print "trying to tear down remote socket loop" import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', cls.listenport)) - sock.sendall('"raise KeyboardInterrupt"') - sock.shutdown(2) - print "trying to tear proxy gateway" - cls.proxygw.exit() + sock.sendall('"raise KeyboardInterrupt"') + sock.shutdown(2) + print "trying to tear proxy gateway" + cls.proxygw.exit() -class TestSocketGateway(SocketGatewaySetup, BasicRemoteExecution): +class TestSocketGateway(SocketGatewaySetup, BasicRemoteExecution): pass Modified: py/dist/py/initpkg.py ============================================================================== --- py/dist/py/initpkg.py (original) +++ py/dist/py/initpkg.py Sun Jan 9 16:49:34 2005 @@ -1,78 +1,78 @@ """ -package initialization. +package initialization. You use the functionality of this package by putting - from py.initpkg import initpkg - initpkg(__name__, exportdefs={ + from py.initpkg import initpkg + initpkg(__name__, exportdefs={ 'name1.name2' : ('./path/to/file.py', 'name') ... }) -into your package's __init__.py file. This will +into your package's __init__.py file. This will lead your package to only expose the names of all -your implementation files that you explicitely -specify. In the above example 'name1' will -become a Module instance where 'name2' is -bound in its namespace to the 'name' object -in the relative './path/to/file.py' python module. -Note that you can also use a '.c' file in which +your implementation files that you explicitely +specify. In the above example 'name1' will +become a Module instance where 'name2' is +bound in its namespace to the 'name' object +in the relative './path/to/file.py' python module. +Note that you can also use a '.c' file in which case it will be compiled via distutils-facilities -on the fly. +on the fly. """ -from __future__ import generators +from __future__ import generators import sys assert sys.version_info >= (2,2,0), "py lib requires python 2.2 or higher" ModuleType = type(sys.modules[__name__]) # --------------------------------------------------- -# Package Object +# Package Object # --------------------------------------------------- class Package(object): def __init__(self, name, exportdefs): pkgmodule = sys.modules[name] - assert pkgmodule.__name__ == name + assert pkgmodule.__name__ == name self.exportdefs = exportdefs - self.module = pkgmodule + self.module = pkgmodule assert not hasattr(pkgmodule, '__package__'), \ "unsupported reinitialization of %r" % pkgmodule pkgmodule.__package__ = self - # make available pkgname.__impl__ + # make available pkgname.__impl__ implname = name + '.' + '__impl__' - self.implmodule = ModuleType(implname) - self.implmodule.__name__ = implname + self.implmodule = ModuleType(implname) + self.implmodule.__name__ = implname self.implmodule.__file__ = pkgmodule.__file__ - self.implmodule.__path__ = pkgmodule.__path__ + self.implmodule.__path__ = pkgmodule.__path__ pkgmodule.__impl__ = self.implmodule - setmodule(implname, self.implmodule) + setmodule(implname, self.implmodule) # inhibit further direct filesystem imports through the package module del pkgmodule.__path__ - + def _resolve(self, extpyish): """ resolve a combined filesystem/python extpy-ish path. """ fspath, modpath = extpyish - if not fspath.endswith('.py'): + if not fspath.endswith('.py'): import py - e = py.path.local(self.implmodule.__file__) - e = e.dirpath(fspath, abs=True) - e = py.path.extpy(e, modpath) - return e.resolve() + e = py.path.local(self.implmodule.__file__) + e = e.dirpath(fspath, abs=True) + e = py.path.extpy(e, modpath) + return e.resolve() assert fspath.startswith('./'), \ - "%r is not an implementation path (XXX)" % extpyish - implmodule = self._loadimpl(fspath[:-3]) - current = implmodule - for x in modpath.split('.'): - current = getattr(current, x) + "%r is not an implementation path (XXX)" % extpyish + implmodule = self._loadimpl(fspath[:-3]) + current = implmodule + for x in modpath.split('.'): + current = getattr(current, x) return current def _loadimpl(self, relfile): """ load implementation for the given relfile. """ parts = [x.strip() for x in relfile.split('/') if x and x!= '.'] - modpath = ".".join([self.implmodule.__name__] + parts) + modpath = ".".join([self.implmodule.__name__] + parts) #print "trying import", modpath return __import__(modpath, None, None, ['name']) @@ -80,68 +80,68 @@ return self.exportdefs.items() def getpath(self): - from py.path import local + from py.path import local base = local(self.implmodule.__file__).dirpath() assert base.check() return base - def _iterfiles(self): - from py.path import checker - base = self.getpath() - for x in base.visit(checker(file=1, notext='.pyc'), + def _iterfiles(self): + from py.path import checker + base = self.getpath() + for x in base.visit(checker(file=1, notext='.pyc'), rec=checker(dotfile=0)): - yield x + yield x def shahexdigest(self, cache=[]): """ return sha hexdigest for files contained in package. """ - if cache: + if cache: return cache[0] - from sha import sha - sum = sha() - for x in self._iterfiles(): - sum.update(x.read()) + from sha import sha + sum = sha() + for x in self._iterfiles(): + sum.update(x.read()) cache.append(sum.hexdigest()) return cache[0] - def getzipdata(self): - """ return string representing a zipfile containing the package. """ - import zipfile + def getzipdata(self): + """ return string representing a zipfile containing the package. """ + import zipfile import py - try: + try: from cStringIO import StringIO - except ImportError: + except ImportError: from StringIO import StringIO base = py.__package__.getpath().dirpath() outf = StringIO() f = zipfile.ZipFile(outf, 'w', compression=zipfile.ZIP_DEFLATED) try: - for x in self._iterfiles(): + for x in self._iterfiles(): f.write(str(x), x.relto(base)) - finally: + finally: f.close() - return outf.getvalue() + return outf.getvalue() - def getrev(self): + def getrev(self): import py - p = py.path.svnwc(self.module.__file__).dirpath() - try: - return p.info().rev - except (KeyboardInterrupt, MemoryError, SystemExit): - raise - except: - return 'unknown' + p = py.path.svnwc(self.module.__file__).dirpath() + try: + return p.info().rev + except (KeyboardInterrupt, MemoryError, SystemExit): + raise + except: + return 'unknown' def setmodule(modpath, module): #print "sys.modules[%r] = %r" % (modpath, module) - sys.modules[modpath] = module + sys.modules[modpath] = module # --------------------------------------------------- -# Virtual Module Object +# Virtual Module Object # --------------------------------------------------- -class Module(ModuleType): - def __init__(self, pkg, name): - self.__package__ = pkg +class Module(ModuleType): + def __init__(self, pkg, name): + self.__package__ = pkg self.__name__ = name self.__map__ = {} @@ -149,23 +149,23 @@ try: extpy = self.__map__[name] except KeyError: - raise AttributeError(name) - #print "getattr(%r, %r)" %(self, name) + raise AttributeError(name) + #print "getattr(%r, %r)" %(self, name) result = self.__package__._resolve(extpy) - setattr(self, name, result) + setattr(self, name, result) del self.__map__[name] - # XXX modify some attrs to make a class appear at virtual module level - if hasattr(result, '__module__'): + # XXX modify some attrs to make a class appear at virtual module level + if hasattr(result, '__module__'): try: - setattr(result, '__module__', self.__name__) - except (AttributeError, TypeError): - pass + setattr(result, '__module__', self.__name__) + except (AttributeError, TypeError): + pass if hasattr(result, '__bases__'): try: setattr(result, '__name__', name) - except (AttributeError, TypeError): + except (AttributeError, TypeError): pass - # print "setting virtual module on %r" % result + # print "setting virtual module on %r" % result return result def __repr__(self): @@ -183,32 +183,32 @@ del getdict # --------------------------------------------------- -# Bootstrap Virtual Module Hierarchy +# Bootstrap Virtual Module Hierarchy # --------------------------------------------------- def initpkg(pkgname, exportdefs): #print "initializing package", pkgname - # bootstrap Package object + # bootstrap Package object pkg = Package(pkgname, exportdefs) seen = { pkgname : pkg.module } for pypath, extpy in pkg.exportitems(): pyparts = pypath.split('.') modparts = pyparts[:-1] - current = pkgname + current = pkgname - # ensure modules + # ensure modules for name in modparts: previous = current - current += '.' + name + current += '.' + name if current not in seen: - seen[current] = mod = Module(pkg, current) - setattr(seen[previous], name, mod) - setmodule(current, mod) + seen[current] = mod = Module(pkg, current) + setattr(seen[previous], name, mod) + setmodule(current, mod) mod = seen[current] if not hasattr(mod, '__map__'): assert mod is pkg.module, \ "only root modules are allowed to be non-lazy. " setattr(mod, pyparts[-1], pkg._resolve(extpy)) else: - mod.__map__[pyparts[-1]] = extpy + mod.__map__[pyparts[-1]] = extpy Modified: py/dist/py/magic/assertion.py ============================================================================== --- py/dist/py/magic/assertion.py (original) +++ py/dist/py/magic/assertion.py Sun Jan 9 16:49:34 2005 @@ -1,5 +1,5 @@ import __builtin__, sys -import py +import py from py.__impl__.magic import exprinfo BuiltinAssertionError = __builtin__.AssertionError @@ -11,7 +11,7 @@ try: source = py.code.Frame(f).statement source = str(source).strip() - except py.error.ENOENT: + except py.error.ENOENT: source = None # this can also occur during reinterpretation, when the # co_filename is set to "". @@ -25,4 +25,4 @@ def invoke(): py.magic.patch(__builtin__, 'AssertionError', AssertionError) def revoke(): - py.magic.revert(__builtin__, 'AssertionError') + py.magic.revert(__builtin__, 'AssertionError') Modified: py/dist/py/magic/autopath.py ============================================================================== --- py/dist/py/magic/autopath.py (original) +++ py/dist/py/magic/autopath.py Sun Jan 9 16:49:34 2005 @@ -3,39 +3,39 @@ from py.__impl__.path.common import PathStr def autopath(globs=None, basefile='__init__.py'): - """ return the (local) path of the "current" file pointed to by globals - or - if it is none - alternatively the callers frame globals. + """ return the (local) path of the "current" file pointed to by globals + or - if it is none - alternatively the callers frame globals. - the path will always point to a .py file or to None. - the path will have the following payload: - pkgdir is the last parent directory path containing 'basefile' - starting backwards from the current file. + the path will always point to a .py file or to None. + the path will have the following payload: + pkgdir is the last parent directory path containing 'basefile' + starting backwards from the current file. """ if globs is None: globs = sys._getframe(1).f_globals try: - __file__ = globs['__file__'] + __file__ = globs['__file__'] except KeyError: - if not sys.argv[0]: + if not sys.argv[0]: raise ValueError, "cannot compute autopath in interactive mode" - __file__ = os.path.abspath(sys.argv[0]) + __file__ = os.path.abspath(sys.argv[0]) custom__file__ = isinstance(__file__, PathStr) if custom__file__: ret = __file__.__path__ else: - ret = local(__file__) + ret = local(__file__) if ret.ext in ('.pyc', '.pyo'): ret = ret.new(ext='.py') current = pkgdir = ret.dirpath() - while 1: + while 1: if basefile in current: - pkgdir = current + pkgdir = current current = current.dirpath() if pkgdir != current: continue elif not custom__file__ and str(current) not in sys.path: sys.path.insert(0, str(current)) - break - ret.pkgdir = pkgdir - return ret + break + ret.pkgdir = pkgdir + return ret Modified: py/dist/py/magic/conftest.py ============================================================================== --- py/dist/py/magic/conftest.py (original) +++ py/dist/py/magic/conftest.py Sun Jan 9 16:49:34 2005 @@ -1,7 +1,7 @@ import py -class Directory(py.test.collect.Directory): - def rec(self, path): - if path.basename != 'testing': - return False - return super(Directory, self).rec(path) +class Directory(py.test.collect.Directory): + def rec(self, path): + if path.basename != 'testing': + return False + return super(Directory, self).rec(path) Modified: py/dist/py/magic/exprinfo.py ============================================================================== --- py/dist/py/magic/exprinfo.py (original) +++ py/dist/py/magic/exprinfo.py Sun Jan 9 16:49:34 2005 @@ -1,8 +1,8 @@ from compiler import parse, ast, pycodegen -import py +import py import __builtin__, sys -passthroughex = (KeyboardInterrupt, SystemExit, MemoryError) +passthroughex = (KeyboardInterrupt, SystemExit, MemoryError) class Failure: def __init__(self, node): @@ -26,8 +26,8 @@ self.__obj__.filename = '' co = pycodegen.ExpressionCodeGenerator(expr).getCode() result = frame.eval(co) - except passthroughex: - raise + except passthroughex: + raise except: raise Failure(self) self.result = result @@ -40,8 +40,8 @@ expr.filename = '' co = pycodegen.ModuleCodeGenerator(expr).getCode() frame.exec_(co) - except passthroughex: - raise + except passthroughex: + raise except: raise Failure(self) @@ -164,10 +164,10 @@ ast.Not : 'not __exprinfo_expr', ast.Invert : '(~__exprinfo_expr)', }.items(): - + class UnaryArith(Interpretable): __view__ = astclass - + def eval(self, frame, astpattern=astpattern, co=compile(astpattern, '?', 'eval')): expr = Interpretable(self.expr) @@ -192,7 +192,7 @@ ast.Mod : '(__exprinfo_left % __exprinfo_right)', ast.Power : '(__exprinfo_left ** __exprinfo_right)', }.items(): - + class BinaryArith(Interpretable): __view__ = astclass @@ -212,7 +212,7 @@ raise except: raise Failure(self) - + keepalive.append(BinaryArith) @@ -280,7 +280,7 @@ co = compile('__exprinfo_expr.%s' % self.attrname, '?', 'eval') try: self.result = frame.eval(co, __exprinfo_expr=expr.result) - except passthroughex: + except passthroughex: raise except: raise Failure(self) @@ -293,7 +293,7 @@ from_instance = frame.is_true( frame.eval(co, __exprinfo_expr=expr.result)) except passthroughex: - raise + raise except: from_instance = True if from_instance: @@ -316,11 +316,11 @@ test.explanation = test.explanation[15:-2] # print the result as 'assert ' self.result = test.result - self.explanation = 'assert ' + test.explanation + self.explanation = 'assert ' + test.explanation if not frame.is_true(test.result): try: raise BuiltinAssertionError - except passthroughex: + except passthroughex: raise except: raise Failure(self) @@ -340,7 +340,7 @@ co = pycodegen.ModuleCodeGenerator(mod).getCode() try: frame.exec_(co, __exprinfo_expr=expr.result) - except passthroughex: + except passthroughex: raise except: raise Failure(self) @@ -381,7 +381,7 @@ node = Interpretable(expr.node) try: node.eval(frame) - except passthroughex: + except passthroughex: raise except Failure, e: report_failure(e) @@ -391,19 +391,19 @@ ########################################################### -# API / Entry points +# API / Entry points # ######################################################### def interpret(source, frame, should_fail=False): module = Interpretable(parse(source, 'exec').node) - #print "got module", module - if isinstance(frame, py.std.types.FrameType): + #print "got module", module + if isinstance(frame, py.std.types.FrameType): frame = py.code.Frame(frame) try: module.run(frame) except Failure, e: return getfailure(e) - except passthroughex: + except passthroughex: raise except: import traceback @@ -413,13 +413,13 @@ else: return None -def getmsg(excinfo): - if isinstance(excinfo, tuple): - excinfo = py.code.ExceptionInfo(excinfo) +def getmsg(excinfo): + if isinstance(excinfo, tuple): + excinfo = py.code.ExceptionInfo(excinfo) #frame, line = gettbline(tb) #frame = py.code.Frame(frame) #return interpret(line, frame) - + tb = list(excinfo)[-1] source = str(tb.statement).strip() x = interpret(source, tb.frame, should_fail=True) Modified: py/dist/py/magic/invoke.py ============================================================================== --- py/dist/py/magic/invoke.py (original) +++ py/dist/py/magic/invoke.py Sun Jan 9 16:49:34 2005 @@ -1,19 +1,19 @@ -def invoke(assertion=False): +def invoke(assertion=False): """ invoke magic, currently you can specify: assertion patches the builtin AssertionError to try to give more meaningful AssertionErrors, which by means of deploying a mini-interpreter constructs - a useful error message. + a useful error message. """ - if assertion: - from py.__impl__.magic import assertion + if assertion: + from py.__impl__.magic import assertion assertion.invoke() def revoke(assertion=False): """ revoke previously invoked magic (see invoke()).""" if assertion: - from py.__impl__.magic import assertion + from py.__impl__.magic import assertion assertion.revoke() Modified: py/dist/py/magic/patch.py ============================================================================== --- py/dist/py/magic/patch.py (original) +++ py/dist/py/magic/patch.py Sun Jan 9 16:49:34 2005 @@ -1,26 +1,26 @@ patched = {} -def patch(namespace, name, value): - """ rebind the 'name' on the 'namespace' to the 'value', - possibly and remember the original value. Multiple +def patch(namespace, name, value): + """ rebind the 'name' on the 'namespace' to the 'value', + possibly and remember the original value. Multiple invocations to the same namespace/name pair will - remember a list of old values. + remember a list of old values. """ - nref = (namespace, name) + nref = (namespace, name) orig = getattr(namespace, name) - patched.setdefault(nref, []).append(orig) + patched.setdefault(nref, []).append(orig) setattr(namespace, name, value) return orig - + def revert(namespace, name): - """ revert to the orginal value the last patch modified. - Raise ValueError if no such original value exists. + """ revert to the orginal value the last patch modified. + Raise ValueError if no such original value exists. """ - nref = (namespace, name) + nref = (namespace, name) if nref not in patched or not patched[nref]: raise ValueError, "No original value stored for %s.%s" % nref current = getattr(namespace, name) orig = patched[nref].pop() - setattr(namespace, name, orig) + setattr(namespace, name, orig) return current Modified: py/dist/py/magic/testing/__init__.py ============================================================================== --- py/dist/py/magic/testing/__init__.py (original) +++ py/dist/py/magic/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# Modified: py/dist/py/magic/testing/test_assertion.py ============================================================================== --- py/dist/py/magic/testing/test_assertion.py (original) +++ py/dist/py/magic/testing/test_assertion.py Sun Jan 9 16:49:34 2005 @@ -1,10 +1,10 @@ import py def setup_module(mod): - py.magic.invoke(assertion=1) + py.magic.invoke(assertion=1) def teardown_module(mod): - py.magic.revoke(assertion=1) + py.magic.revoke(assertion=1) def f(): return 2 @@ -16,10 +16,10 @@ s = str(e) assert s.startswith('assert 2 == 3\n') -def test_assert_within_finally(): - class A: +def test_assert_within_finally(): + class A: def f(): - pass + pass excinfo = py.test.raises(TypeError, """ try: A().f() Modified: py/dist/py/magic/testing/test_autopath.py ============================================================================== --- py/dist/py/magic/testing/test_autopath.py (original) +++ py/dist/py/magic/testing/test_autopath.py Sun Jan 9 16:49:34 2005 @@ -1,64 +1,64 @@ -import py +import py import sys -class TestAutoPath: - getauto = "from py.magic import autopath ; autopath = autopath()" +class TestAutoPath: + getauto = "from py.magic import autopath ; autopath = autopath()" def __init__(self): - self.root = py.test.config.tmpdir.ensure('autoconfigure', dir=1) + self.root = py.test.config.tmpdir.ensure('autoconfigure', dir=1) self.initdir = self.root.ensure('pkgdir', dir=1) - self.initdir.ensure('__init__.py') - self.initdir2 = self.initdir.ensure('initdir2', dir=1) - self.initdir2.ensure('__init__.py') + self.initdir.ensure('__init__.py') + self.initdir2 = self.initdir.ensure('initdir2', dir=1) + self.initdir2.ensure('__init__.py') def test_import_autoconfigure__file__with_init(self): testpath = self.initdir2 / 'autoconfiguretest.py' d = {'__file__' : str(testpath)} oldsyspath = sys.path[:] try: - exec self.getauto in d + exec self.getauto in d conf = d['autopath'] assert conf.dirpath() == self.initdir2 - assert conf.pkgdir == self.initdir - assert str(self.root) in sys.path - exec self.getauto in d + assert conf.pkgdir == self.initdir + assert str(self.root) in sys.path + exec self.getauto in d assert conf is not d['autopath'] finally: - sys.path[:] = oldsyspath + sys.path[:] = oldsyspath def test_import_autoconfigure__file__with_py_exts(self): - for ext in '.pyc', '.pyo': + for ext in '.pyc', '.pyo': testpath = self.initdir2 / ('autoconfiguretest' + ext) d = {'__file__' : str(testpath)} oldsyspath = sys.path[:] try: - exec self.getauto in d + exec self.getauto in d conf = d['autopath'] - assert conf == self.initdir2.join('autoconfiguretest.py') - assert conf.pkgdir == self.initdir - assert str(self.root) in sys.path - exec self.getauto in d + assert conf == self.initdir2.join('autoconfiguretest.py') + assert conf.pkgdir == self.initdir + assert str(self.root) in sys.path + exec self.getauto in d assert conf is not d['autopath'] finally: - sys.path[:] = oldsyspath + sys.path[:] = oldsyspath def test_import_autoconfigure___file__without_init(self): testpath = self.root / 'autoconfiguretest.py' d = {'__file__' : str(testpath)} oldsyspath = sys.path[:] try: - exec self.getauto in d + exec self.getauto in d conf = d['autopath'] assert conf.dirpath() == self.root assert conf.pkgdir == self.root syspath = sys.path[:] - assert str(self.root) in syspath - exec self.getauto in d + assert str(self.root) in syspath + exec self.getauto in d assert conf is not d['autopath'] finally: - sys.path[:] = oldsyspath + sys.path[:] = oldsyspath def test_import_autoconfigure__nofile(self): - p = self.initdir2 / 'autoconfiguretest.py' + p = self.initdir2 / 'autoconfiguretest.py' oldsysarg = sys.argv sys.argv = [str(p)] oldsyspath = sys.path[:] @@ -69,10 +69,10 @@ assert conf.dirpath() == self.initdir2 assert conf.pkgdir == self.initdir syspath = sys.path[:] - assert str(self.root) in syspath + assert str(self.root) in syspath finally: - sys.path[:] = oldsyspath - sys.argv = sys.argv + sys.path[:] = oldsyspath + sys.argv = sys.argv def test_import_autoconfigure__nofile_interactive(self): @@ -83,7 +83,7 @@ py.test.raises(ValueError,''' d = {} exec self.getauto in d - ''') + ''') finally: - sys.path[:] = oldsyspath - sys.argv = sys.argv + sys.path[:] = oldsyspath + sys.argv = sys.argv Modified: py/dist/py/magic/testing/test_exprinfo.py ============================================================================== --- py/dist/py/magic/testing/test_exprinfo.py (original) +++ py/dist/py/magic/testing/test_exprinfo.py Sun Jan 9 16:49:34 2005 @@ -43,18 +43,18 @@ msg = getmsg(excinfo) assert msg == 'assert 1 == 2' -def test_assert_func_argument_type_error(): - def f (): +def test_assert_func_argument_type_error(): + def f (): pass def g(): - f(1) + f(1) excinfo = getexcinfo(TypeError, g) msg = getmsg(excinfo) assert msg.find("takes no argument") != -1 - class A: + class A: def f(): - pass + pass def g(): A().f() excinfo = getexcinfo(TypeError, g) @@ -80,24 +80,24 @@ def test_keyboard_interrupt(): # XXX this test is slightly strange because it is not # clear that "interpret" should execute "raise" statements - # ... but it apparently currently does and it's nice to - # exercise the code because the exprinfo-machinery is - # not much executed when all tests pass ... - - class DummyCode: + # ... but it apparently currently does and it's nice to + # exercise the code because the exprinfo-machinery is + # not much executed when all tests pass ... + + class DummyCode: co_filename = 'dummy' co_firstlineno = 0 co_name = 'dummy' - class DummyFrame: + class DummyFrame: f_globals = f_locals = {} - f_code = DummyCode + f_code = DummyCode f_lineno = 0 - + for exstr in "SystemExit", "KeyboardInterrupt", "MemoryError": - ex = eval(exstr) + ex = eval(exstr) try: interpret("raise %s" % exstr, py.code.Frame(DummyFrame)) - except ex: + except ex: pass else: raise AssertionError, "ex %s didn't pass through" %(exstr, ) Modified: py/dist/py/magic/testing/test_invoke.py ============================================================================== --- py/dist/py/magic/testing/test_invoke.py (original) +++ py/dist/py/magic/testing/test_invoke.py Sun Jan 9 16:49:34 2005 @@ -1,10 +1,10 @@ -import __builtin__ as bltin -import py +import __builtin__ as bltin +import py import inspect def check_assertion(): excinfo = py.test.raises(AssertionError, "assert 1 == 2") - assert excinfo.exception_text == "assert 1 == 2" + assert excinfo.exception_text == "assert 1 == 2" def test_invoke_assertion(): py.magic.invoke(assertion=True) @@ -12,4 +12,4 @@ check_assertion() finally: py.magic.revoke(assertion=True) - + Modified: py/dist/py/magic/testing/test_patch.py ============================================================================== --- py/dist/py/magic/testing/test_patch.py (original) +++ py/dist/py/magic/testing/test_patch.py Sun Jan 9 16:49:34 2005 @@ -1,5 +1,5 @@ -from py.test import raises -from py.magic import patch, revert +from py.test import raises +from py.magic import patch, revert def test_patch_revert(): class a: @@ -7,12 +7,12 @@ raises(AttributeError, "patch(a, 'i', 42)") a.i = 42 - patch(a, 'i', 23) + patch(a, 'i', 23) assert a.i == 23 - revert(a, 'i') + revert(a, 'i') assert a.i == 42 -def test_double_patch(): +def test_double_patch(): class a: i = 42 assert patch(a, 'i', 2) == 42 @@ -28,4 +28,4 @@ i = 2 pass raises(ValueError, "revert(a, 'i')") - + Modified: py/dist/py/magic/testing/test_viewtype.py ============================================================================== --- py/dist/py/magic/testing/test_viewtype.py (original) +++ py/dist/py/magic/testing/test_viewtype.py Sun Jan 9 16:49:34 2005 @@ -23,7 +23,7 @@ assert Picklable(123).pickle() == '123' assert Picklable([1,[2,3],4]).pickle() == '1;2;3;4' - assert Picklable({1:2}).pickle() == '1!2' + assert Picklable({1:2}).pickle() == '1!2' def test_custom_class_hierarchy(): Modified: py/dist/py/magic/viewtype.py ============================================================================== --- py/dist/py/magic/viewtype.py (original) +++ py/dist/py/magic/viewtype.py Sun Jan 9 16:49:34 2005 @@ -10,7 +10,7 @@ class View(object): """View base class. - + If C is a subclass of View, then C(x) creates a proxy object around the object x. The actual class of the proxy is not C in general, but a *subclass* of C determined by the rules below. To avoid confusion @@ -35,7 +35,7 @@ of the object x, instead of the class of x, by overriding __viewkey__. See last example at the end of this module. """ - + _viewcache = {} __view__ = () Modified: py/dist/py/misc/cache.py ============================================================================== --- py/dist/py/misc/cache.py (original) +++ py/dist/py/misc/cache.py Sun Jan 9 16:49:34 2005 @@ -1,154 +1,154 @@ -""" -This module contains multithread-safe cache implementations. +""" +This module contains multithread-safe cache implementations. -Caches mainly have a +Caches mainly have a __getitem__ and getorbuild() method -where the latter either just return a cached value or -first builds the value. +where the latter either just return a cached value or +first builds the value. -These are the current cache implementations: +These are the current cache implementations: - BuildcostAccessCache tracks building-time and accesses. Evicts - by product of num-accesses * build-time. + BuildcostAccessCache tracks building-time and accesses. Evicts + by product of num-accesses * build-time. """ -import py -gettime = py.std.time.time +import py +gettime = py.std.time.time -class WeightedCountingEntry(object): - def __init__(self, value, oneweight): - self.num = 1 - self._value = value - self.oneweight = oneweight - - def weight(): - def fget(self): - return self.num * self.oneweight - return property(fget, None, None, "cumulative weight") - weight = weight() - - def value(): - def fget(self): - # you need to protect against mt-access at caller side! - self.num += 1 - return self._value - return property(fget, None, None) +class WeightedCountingEntry(object): + def __init__(self, value, oneweight): + self.num = 1 + self._value = value + self.oneweight = oneweight + + def weight(): + def fget(self): + return self.num * self.oneweight + return property(fget, None, None, "cumulative weight") + weight = weight() + + def value(): + def fget(self): + # you need to protect against mt-access at caller side! + self.num += 1 + return self._value + return property(fget, None, None) value = value() - -class BasicCache(object): - def __init__(self, maxentries=128): - self.maxentries = maxentries + +class BasicCache(object): + def __init__(self, maxentries=128): + self.maxentries = maxentries self.prunenum = maxentries - int(maxentries/8) self._lock = py.std.threading.RLock() self._dict = {} - def getentry(self, key): - lock = self._lock + def getentry(self, key): + lock = self._lock lock.acquire() - try: - return self._dict.get(key, None) - finally: - lock.release() + try: + return self._dict.get(key, None) + finally: + lock.release() - def putentry(self, key, entry): + def putentry(self, key, entry): self._lock.acquire() - try: - self._prunelowestweight() - self._dict[key] = entry - finally: - self._lock.release() + try: + self._prunelowestweight() + self._dict[key] = entry + finally: + self._lock.release() - def delentry(self, key, raising=False): + def delentry(self, key, raising=False): self._lock.acquire() - try: - try: - del self._dict[key] - except KeyError: - if raising: - raise - finally: - self._lock.release() + try: + try: + del self._dict[key] + except KeyError: + if raising: + raise + finally: + self._lock.release() - def getorbuild(self, key, builder, *args, **kwargs): + def getorbuild(self, key, builder, *args, **kwargs): entry = self.getentry(key) - if entry is None: - entry = self.build(key, builder, *args, **kwargs) - return entry.value - - def _prunelowestweight(self): - """ prune out entries with lowest weight. """ - # note: must be called with acquired self._lock! - numentries = len(self._dict) - if numentries >= self.maxentries: - # evict according to entry's weight + if entry is None: + entry = self.build(key, builder, *args, **kwargs) + return entry.value + + def _prunelowestweight(self): + """ prune out entries with lowest weight. """ + # note: must be called with acquired self._lock! + numentries = len(self._dict) + if numentries >= self.maxentries: + # evict according to entry's weight items = [(entry.weight, key) for key, entry in self._dict.iteritems()] - items.sort() - index = numentries - self.prunenum - if index > 0: - for weight, key in items[:index]: - del self._dict[key] - -class BuildcostAccessCache(BasicCache): - """ A BuildTime/Access-counting cache implementation. + items.sort() + index = numentries - self.prunenum + if index > 0: + for weight, key in items[:index]: + del self._dict[key] + +class BuildcostAccessCache(BasicCache): + """ A BuildTime/Access-counting cache implementation. the weight of a value is computed as the product of - - num-accesses-of-a-value * time-to-build-the-value - The values with the least such weights are evicted - if the cache maxentries threshold is superceded. - For implementation flexibility more than one object - might be evicted at a time. - """ - # time function to use for measuring build-times - _time = gettime - - def __init__(self, maxentries=64): - super(BuildcostAccessCache, self).__init__(maxentries) - - def build(self, key, builder, *args, **kwargs): - start = self._time() - val = builder(*args, **kwargs) - end = self._time() - entry = WeightedCountingEntry(val, end-start) - self.putentry(key, entry) - return entry - -class AgingCache(BasicCache): - """ This cache prunes out cache entries that are too old. + num-accesses-of-a-value * time-to-build-the-value + + The values with the least such weights are evicted + if the cache maxentries threshold is superceded. + For implementation flexibility more than one object + might be evicted at a time. + """ + # time function to use for measuring build-times + _time = gettime + + def __init__(self, maxentries=64): + super(BuildcostAccessCache, self).__init__(maxentries) + + def build(self, key, builder, *args, **kwargs): + start = self._time() + val = builder(*args, **kwargs) + end = self._time() + entry = WeightedCountingEntry(val, end-start) + self.putentry(key, entry) + return entry + +class AgingCache(BasicCache): + """ This cache prunes out cache entries that are too old. """ - def __init__(self, maxentries=128, maxseconds=10.0): - super(AgingCache, self).__init__(maxentries) - self.maxseconds = maxseconds + def __init__(self, maxentries=128, maxseconds=10.0): + super(AgingCache, self).__init__(maxentries) + self.maxseconds = maxseconds - def getentry(self, key): - self._lock.acquire() + def getentry(self, key): + self._lock.acquire() try: - try: + try: entry = self._dict[key] - except KeyError: - entry = None - else: - if entry.isexpired(): - del self._dict[key] - entry = None - return entry - finally: - self._lock.release() - - def build(self, key, builder, *args, **kwargs): - ctime = gettime() - val = builder(*args, **kwargs) - entry = AgingEntry(val, ctime + self.maxseconds) - self.putentry(key, entry) - return entry - -class AgingEntry(object): - def __init__(self, value, expirationtime): - self.value = value - self.expirationtime = expirationtime - - def isexpired(self): - t = py.std.time.time() - return t >= self.expirationtime + except KeyError: + entry = None + else: + if entry.isexpired(): + del self._dict[key] + entry = None + return entry + finally: + self._lock.release() + + def build(self, key, builder, *args, **kwargs): + ctime = gettime() + val = builder(*args, **kwargs) + entry = AgingEntry(val, ctime + self.maxseconds) + self.putentry(key, entry) + return entry + +class AgingEntry(object): + def __init__(self, value, expirationtime): + self.value = value + self.expirationtime = expirationtime + + def isexpired(self): + t = py.std.time.time() + return t >= self.expirationtime Modified: py/dist/py/misc/error.py ============================================================================== --- py/dist/py/misc/error.py (original) +++ py/dist/py/misc/error.py Sun Jan 9 16:49:34 2005 @@ -1,56 +1,56 @@ import py -class Error(EnvironmentError): +class Error(EnvironmentError): __module__ = 'py.error' - def __repr__(self): - return "%s.%s %r: %s " %(self.__class__.__module__, - self.__class__.__name__, - self.__class__.__doc__, - " ".join(map(str, self.args)), - #repr(self.args) + def __repr__(self): + return "%s.%s %r: %s " %(self.__class__.__module__, + self.__class__.__name__, + self.__class__.__doc__, + " ".join(map(str, self.args)), + #repr(self.args) ) - def __str__(self): - return "[%s]: %s" %(self.__class__.__doc__, - " ".join(map(str, self.args)), + def __str__(self): + return "[%s]: %s" %(self.__class__.__doc__, + " ".join(map(str, self.args)), ) -ModuleType = type(py) +ModuleType = type(py) -class py_error(ModuleType): - """ py.error contains higher level Exception classes - for each possible POSIX errno (as defined per - the 'errno' module. All such Exceptions derive - from py.error.Error, which itself is a subclass - of EnvironmentError. - """ - Error = Error +class py_error(ModuleType): + """ py.error contains higher level Exception classes + for each possible POSIX errno (as defined per + the 'errno' module. All such Exceptions derive + from py.error.Error, which itself is a subclass + of EnvironmentError. + """ + Error = Error - def _geterrnoclass(eno, _errno2class = {}): - try: + def _geterrnoclass(eno, _errno2class = {}): + try: return _errno2class[eno] - except KeyError: + except KeyError: clsname = py.std.errno.errorcode[eno] - cls = py.std.new.classobj(clsname, (Error,), - {'__module__':'py.error', + cls = py.std.new.classobj(clsname, (Error,), + {'__module__':'py.error', '__doc__': py.std.os.strerror(eno)}) _errno2class[eno] = cls - return cls - _geterrnoclass = staticmethod(_geterrnoclass) + return cls + _geterrnoclass = staticmethod(_geterrnoclass) - def __getattr__(self, name): - eno = getattr(py.std.errno, name) + def __getattr__(self, name): + eno = getattr(py.std.errno, name) cls = self._geterrnoclass(eno) - setattr(self, name, cls) - return cls + setattr(self, name, cls) + return cls def getdict(self, done=[]): try: return done[0] - except IndexError: - for name in py.std.errno.errorcode.values(): + except IndexError: + for name in py.std.errno.errorcode.values(): hasattr(self, name) # force attribute to be loaded, ignore errors dictdescr = ModuleType.__dict__['__dict__'] done.append(dictdescr.__get__(self)) @@ -59,4 +59,4 @@ __dict__ = property(getdict) del getdict -error = py_error('py.error', py_error.__doc__) +error = py_error('py.error', py_error.__doc__) Modified: py/dist/py/misc/std.py ============================================================================== --- py/dist/py/misc/std.py (original) +++ py/dist/py/misc/std.py Sun Jan 9 16:49:34 2005 @@ -3,13 +3,13 @@ class Std(object): def __init__(self): - self.__dict__ = sys.modules + self.__dict__ = sys.modules def __getattr__(self, name): try: m = __import__(name) - except ImportError: - raise AttributeError("py.std: could not import %s" % name) - return m + except ImportError: + raise AttributeError("py.std: could not import %s" % name) + return m -std = Std() +std = Std() Modified: py/dist/py/misc/testing/__init__.py ============================================================================== --- py/dist/py/misc/testing/__init__.py (original) +++ py/dist/py/misc/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# Modified: py/dist/py/misc/testing/test_api.py ============================================================================== --- py/dist/py/misc/testing/test_api.py (original) +++ py/dist/py/misc/testing/test_api.py Sun Jan 9 16:49:34 2005 @@ -6,7 +6,7 @@ class TestAPI_V0_namespace_consistence: def test_path_entrypoints(self): - assert inspect.ismodule(py.path) + assert inspect.ismodule(py.path) assert_class('py.path', 'local') assert_class('py.path', 'svnwc') assert_class('py.path', 'svnurl') @@ -21,23 +21,23 @@ assert_function('py.magic', 'revoke') def test_process_entrypoints(self): - assert_function('py.process', 'cmdexec') + assert_function('py.process', 'cmdexec') def XXXtest_utest_entrypoints(self): - # XXX TOBECOMPLETED - assert_function('py.test', 'main') - #assert_module('std.utest', 'collect') + # XXX TOBECOMPLETED + assert_function('py.test', 'main') + #assert_module('std.utest', 'collect') def assert_class(modpath, name): mod = __import__(modpath, None, None, [name]) - obj = getattr(mod, name) + obj = getattr(mod, name) fullpath = modpath + '.' + name - assert obj.__module__ == modpath + assert obj.__module__ == modpath if sys.version_info >= (2,3): assert obj.__name__ == name def assert_function(modpath, name): mod = __import__(modpath, None, None, [name]) - obj = getattr(mod, name) - assert hasattr(obj, 'func_doc') + obj = getattr(mod, name) + assert hasattr(obj, 'func_doc') #assert obj.func_name == name Modified: py/dist/py/misc/testing/test_cache.py ============================================================================== --- py/dist/py/misc/testing/test_cache.py (original) +++ py/dist/py/misc/testing/test_cache.py Sun Jan 9 16:49:34 2005 @@ -1,55 +1,55 @@ -import py -from py.__impl__.misc.cache import BuildcostAccessCache, AgingCache +import py +from py.__impl__.misc.cache import BuildcostAccessCache, AgingCache -class BasicCacheAPITest: +class BasicCacheAPITest: cache = None - def test_getorbuild(self): - val = self.cache.getorbuild(-42, lambda: 42) - assert val == 42 - val = self.cache.getorbuild(-42, lambda: 23) - assert val == 42 - - def test_cache_get_key_error(self): - assert self.cache.getentry(-23) == None - - def test_delentry_non_raising(self): - val = self.cache.getorbuild(100, lambda: 100) - self.cache.delentry(100) - assert self.cache.getentry(100) is None - - def test_delentry_raising(self): - val = self.cache.getorbuild(100, lambda: 100) - self.cache.delentry(100) + def test_getorbuild(self): + val = self.cache.getorbuild(-42, lambda: 42) + assert val == 42 + val = self.cache.getorbuild(-42, lambda: 23) + assert val == 42 + + def test_cache_get_key_error(self): + assert self.cache.getentry(-23) == None + + def test_delentry_non_raising(self): + val = self.cache.getorbuild(100, lambda: 100) + self.cache.delentry(100) + assert self.cache.getentry(100) is None + + def test_delentry_raising(self): + val = self.cache.getorbuild(100, lambda: 100) + self.cache.delentry(100) py.test.raises(KeyError, "self.cache.delentry(100, raising=True)") -class TestBuildcostAccess(BasicCacheAPITest): - cache = BuildcostAccessCache(maxentries=128) +class TestBuildcostAccess(BasicCacheAPITest): + cache = BuildcostAccessCache(maxentries=128) - def test_cache_works_somewhat_simple(self): - cache = BuildcostAccessCache() - for x in range(cache.maxentries): - y = cache.getorbuild(x, lambda: x) - assert x == y - for x in range(cache.maxentries): - assert cache.getorbuild(x, None) == x - for x in range(cache.maxentries/2): - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(x, None) == x - val = cache.getorbuild(cache.maxentries * 2, lambda: 42) - assert val == 42 - # check that recently used ones are still there + def test_cache_works_somewhat_simple(self): + cache = BuildcostAccessCache() + for x in range(cache.maxentries): + y = cache.getorbuild(x, lambda: x) + assert x == y + for x in range(cache.maxentries): + assert cache.getorbuild(x, None) == x + for x in range(cache.maxentries/2): + assert cache.getorbuild(x, None) == x + assert cache.getorbuild(x, None) == x + assert cache.getorbuild(x, None) == x + val = cache.getorbuild(cache.maxentries * 2, lambda: 42) + assert val == 42 + # check that recently used ones are still there # and are not build again - for x in range(cache.maxentries/2): - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(cache.maxentries*2, None) == 42 - - -class TestAging(BasicCacheAPITest): - maxsecs = 0.02 - cache = AgingCache(maxentries=128, maxseconds=maxsecs) + for x in range(cache.maxentries/2): + assert cache.getorbuild(x, None) == x + assert cache.getorbuild(cache.maxentries*2, None) == 42 - def test_cache_eviction(self): + +class TestAging(BasicCacheAPITest): + maxsecs = 0.02 + cache = AgingCache(maxentries=128, maxseconds=maxsecs) + + def test_cache_eviction(self): self.cache.getorbuild(17, lambda: 17) - py.std.time.sleep(self.maxsecs*1.1) - assert self.cache.getentry(17) is None + py.std.time.sleep(self.maxsecs*1.1) + assert self.cache.getentry(17) is None Modified: py/dist/py/misc/testing/test_error.py ============================================================================== --- py/dist/py/misc/testing/test_error.py (original) +++ py/dist/py/misc/testing/test_error.py Sun Jan 9 16:49:34 2005 @@ -1,10 +1,10 @@ import py -import errno +import errno -def test_error_classes(): - for name in errno.errorcode.values(): - x = getattr(py.error, name) - assert issubclass(x, py.error.Error) - assert issubclass(x, EnvironmentError) +def test_error_classes(): + for name in errno.errorcode.values(): + x = getattr(py.error, name) + assert issubclass(x, py.error.Error) + assert issubclass(x, EnvironmentError) Modified: py/dist/py/misc/testing/test_initpkg.py ============================================================================== --- py/dist/py/misc/testing/test_initpkg.py (original) +++ py/dist/py/misc/testing/test_initpkg.py Sun Jan 9 16:49:34 2005 @@ -1,25 +1,25 @@ import py import types -def checksubpackage(name): +def checksubpackage(name): obj = getattr(py, name) - if hasattr(obj, '__map__'): # isinstance(obj, Module): - keys = dir(obj) - assert len(keys) > 0 + if hasattr(obj, '__map__'): # isinstance(obj, Module): + keys = dir(obj) + assert len(keys) > 0 assert getattr(obj, '__map__') == {} def test_dir(): - from py.__impl__.initpkg import Module + from py.__impl__.initpkg import Module for name in dir(py): - if name == 'magic': # greenlets don't work everywhere, we don't care here - continue + if name == 'magic': # greenlets don't work everywhere, we don't care here + continue if not name.startswith('_'): - yield checksubpackage, name + yield checksubpackage, name def test_virtual_module_identity(): from py import path as path1 from py import path as path2 - assert path1 is path2 + assert path1 is path2 from py.path import local as local1 from py.path import local as local2 assert local1 is local2 @@ -27,59 +27,59 @@ def test_importing_all_implementations(): base = py.path.local(py.__file__).dirpath() nodirs = ( - base.join('test', 'testing', 'test'), - base.join('path', 'extpy', 'testing', 'test_data'), - base.join('path', 'gateway',), - base.join('documentation',), - base.join('test', 'testing', 'import_test'), - base.join('magic', 'greenlet'), - base.join('bin'), - base.join('execnet', 'bin'), + base.join('test', 'testing', 'test'), + base.join('path', 'extpy', 'testing', 'test_data'), + base.join('path', 'gateway',), + base.join('documentation',), + base.join('test', 'testing', 'import_test'), + base.join('magic', 'greenlet'), + base.join('bin'), + base.join('execnet', 'bin'), ) for p in base.visit('*.py', py.path.checker(dotfile=0)): - relpath = p.new(ext='').relto(base) - if base.sep in relpath: # not std/*.py itself - for x in nodirs: - if p.relto(x): - break - else: - relpath = relpath.replace(base.sep, '.') - modpath = 'py.__impl__.%s' % relpath - assert __import__(modpath) + relpath = p.new(ext='').relto(base) + if base.sep in relpath: # not std/*.py itself + for x in nodirs: + if p.relto(x): + break + else: + relpath = relpath.replace(base.sep, '.') + modpath = 'py.__impl__.%s' % relpath + assert __import__(modpath) -def test_shahexdigest(): - hex = py.__package__.shahexdigest() +def test_shahexdigest(): + hex = py.__package__.shahexdigest() assert len(hex) == 40 def test_getzipdata(): s = py.__package__.getzipdata() -def test_getrev(): - d = py.__package__.getrev() - try: - svnversion = py.path.local.sysfind('svnversion') - except py.error.ENOENT: - py.test.skip("cannot test svnversion, 'svnversion' binary not found") +def test_getrev(): + d = py.__package__.getrev() + try: + svnversion = py.path.local.sysfind('svnversion') + except py.error.ENOENT: + py.test.skip("cannot test svnversion, 'svnversion' binary not found") v = svnversion.sysexec(py.path.local(py.__file__).dirpath()) - assert v.startswith(str(d)) + assert v.startswith(str(d)) -# the following test should abasically work in the future +# the following test should abasically work in the future def XXXtest_virtual_on_the_fly(): py.initpkg('my', { - 'x.abspath' : 'os.path.abspath', + 'x.abspath' : 'os.path.abspath', 'x.local' : 'py.path.local', - 'y' : 'smtplib', - 'z.cmdexec' : 'py.process.cmdexec', + 'y' : 'smtplib', + 'z.cmdexec' : 'py.process.cmdexec', }) from my.x import abspath - from my.x import local - import smtplib + from my.x import local + import smtplib from my import y - assert y is smtplib + assert y is smtplib from my.z import cmdexec from py.process import cmdexec as cmdexec2 assert cmdexec is cmdexec2 ##def test_help(): -# help(std.path) +# help(std.path) # #assert False Modified: py/dist/py/misc/testing/test_std.py ============================================================================== --- py/dist/py/misc/testing/test_std.py (original) +++ py/dist/py/misc/testing/test_std.py Sun Jan 9 16:49:34 2005 @@ -3,11 +3,11 @@ def test_os(): import os - assert py.std.os is os + assert py.std.os is os def test_import_error_converts_to_attributeerror(): py.test.raises(AttributeError, "py.std.xyzalskdj") def test_std_gets_it(): for x in py.std.sys.modules: - assert x in py.std.__dict__ + assert x in py.std.__dict__ Modified: py/dist/py/path/__init__.py ============================================================================== --- py/dist/py/path/__init__.py (original) +++ py/dist/py/path/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# +# Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Sun Jan 9 16:49:34 2005 @@ -4,13 +4,13 @@ """ from __future__ import generators import sys -import py +import py def checktype(pathinstance, kw): - names = ('local', 'svnwc', 'svnurl', 'py', 'fspy') + names = ('local', 'svnwc', 'svnurl', 'py', 'fspy') for name,value in kw.items(): if name in names: - cls = getattr(py.path, name) + cls = getattr(py.path, name) if bool(isinstance(pathinstance, cls)) ^ bool(value): return False del kw[name] @@ -21,9 +21,9 @@ self.kwargs = kwargs def __call__(self, p): return p.check(**self.kwargs) - + class Checkers: - _depend_on_existence = 'exists', + _depend_on_existence = 'exists', def __init__(self, path): self.path = path @@ -48,16 +48,16 @@ def _evaluate(self, kw): for name, value in kw.items(): - invert = False + invert = False meth = None try: meth = getattr(self, name) except AttributeError: if name[:3] == 'not': invert = True - try: - meth = getattr(self, name[3:]) - except AttributeError: + try: + meth = getattr(self, name[3:]) + except AttributeError: pass if meth is None: raise TypeError, "no %r checker available for %r" % (name, self.path) @@ -68,12 +68,12 @@ else: if bool(value) ^ bool(meth()) ^ invert: return False - except (py.error.ENOENT, py.error.ENOTDIR): - for name in self._depend_on_existence: + except (py.error.ENOENT, py.error.ENOTDIR): + for name in self._depend_on_existence: if name in kw: if kw.get(name): return False - name = 'not' + name + name = 'not' + name if name in kw: if not kw.get(name): return False @@ -100,17 +100,17 @@ if isinstance(other, str): return self.join(other).check() else: - if other.dirpath() != self: + if other.dirpath() != self: return False p = self.join(other.basename) return p.check() def basename(self): return self.get('basename')[0] - basename = property(basename, None, None, 'basename part of path') + basename = property(basename, None, None, 'basename part of path') - def parts(self, reverse=False): - """ return a root-first list of all ancestor directories + def parts(self, reverse=False): + """ return a root-first list of all ancestor directories plus the path itself. """ current = self @@ -119,20 +119,20 @@ last = current current = current.dirpath() if last == current: - break - l.insert(0, current) + break + l.insert(0, current) if reverse: l.reverse() return l def common(self, other): """ return the common part shared with the other path - or None if there is no common part. + or None if there is no common part. """ last = None for x, y in zip(self.parts(), other.parts()): if x != y: - return last + return last last = x return last @@ -151,7 +151,7 @@ def __repr__(self): return repr(str(self)) - def visit(self, fil=None, rec=None, ignore=None): + def visit(self, fil=None, rec=None, ignore=None): if isinstance(fil, str): fil = fnmatch(fil) if isinstance(rec, str): @@ -160,12 +160,12 @@ try: dirlist = self.listdir() except ignore: - return + return else: dirlist = self.listdir() checkdir = py.path.checker(dir=1) reclist = [] - for p in dirlist: + for p in dirlist: if fil is None or fil(p): yield p if checkdir(p) and (rec is None or rec(p)): @@ -176,18 +176,18 @@ yield i def _callex(self, func, *args): - """ call a function and raise errno-exception if applicable. """ + """ call a function and raise errno-exception if applicable. """ try: return func(*args) except (py.error.Error, KeyboardInterrupt, SystemExit): - raise + raise except EnvironmentError, e: - if not hasattr(e, 'errno'): - raise - cls, value, tb = sys.exc_info() - cls = py.error._geterrnoclass(e.errno) + if not hasattr(e, 'errno'): + raise + cls, value, tb = sys.exc_info() + cls = py.error._geterrnoclass(e.errno) value = cls("%s%r" % (func.__name__, args)) - raise cls, value, tb + raise cls, value, tb class fnmatch: def __init__(self, pattern): @@ -201,17 +201,17 @@ [!seq] matches any char not in seq if the pattern contains a path-separator then the full path - is used for pattern matching and a '*' is prepended to the - pattern. + is used for pattern matching and a '*' is prepended to the + pattern. if the pattern doesn't contain a path-separator the pattern - is only matched against the basename. + is only matched against the basename. """ pattern = self.pattern if pattern.find(path.sep) == -1: - name = path.basename + name = path.basename else: - name = str(path) # path.strpath # XXX svn? + name = str(path) # path.strpath # XXX svn? pattern = '*' + path.sep + pattern from fnmatch import fnmatch return fnmatch(name, pattern) @@ -232,9 +232,9 @@ def ext(self, arg): if not arg.startswith('.'): arg = '.' + arg - return self.path.ext == arg + return self.path.ext == arg -class FSPathBase(PathBase): +class FSPathBase(PathBase): """ shared implementation for filesystem path objects.""" Checkers = FSCheckers @@ -243,27 +243,27 @@ def dirpath(self, *args, **kwargs): """ return the directory Path of the current Path joined - with any given path arguments. + with any given path arguments. """ - return self.new(basename='').join(*args, **kwargs) + return self.new(basename='').join(*args, **kwargs) def ext(self): return self.get('ext')[0] - ext = property(ext, None, None, 'extension part of path') + ext = property(ext, None, None, 'extension part of path') def purebasename(self): return self.get('purebasename')[0] purebasename = property(purebasename, None, None, 'basename without extension') def read(self, mode='rb'): - """ read and return a bytestring from reading the path. """ - if py.std.sys.version_info < (2,3): - for x in 'u', 'U': - if x in mode: - mode = mode.replace(x, '') - f = self.open(mode) + """ read and return a bytestring from reading the path. """ + if py.std.sys.version_info < (2,3): + for x in 'u', 'U': + if x in mode: + mode = mode.replace(x, '') + f = self.open(mode) try: - return f.read() + return f.read() finally: f.close() @@ -292,11 +292,11 @@ def move(self, target): if target.relto(self): - raise py.error.EINVAL(target, "cannot move path into a subdirectory of itself") + raise py.error.EINVAL(target, "cannot move path into a subdirectory of itself") try: self.rename(target) except py.error.EXDEV: # invalid cross-device link - self.copy(target) + self.copy(target) self.remove() def getpymodule(self): @@ -309,7 +309,7 @@ co = self.getpycodeobj() mod = py.std.new.module(modname) mod.__file__ = PathStr(self) - if self.basename == '__init__.py': + if self.basename == '__init__.py': mod.__path__ = [str(self.dirpath())] sys.modules[modname] = mod exec co in mod.__dict__ @@ -318,7 +318,7 @@ def getpycodeobj(self): s = self.read('rU') # XXX str(self) should show up somewhere in the code's filename - return py.code.compile(s) + return py.code.compile(s) class PathStr(str): def __init__(self, path): Modified: py/dist/py/path/extpy/extpy.py ============================================================================== --- py/dist/py/path/extpy/extpy.py (original) +++ py/dist/py/path/extpy/extpy.py Sun Jan 9 16:49:34 2005 @@ -1,40 +1,40 @@ """ -A path to python objects located in filesystems. +A path to python objects located in filesystems. Note: this is still experimental and may be removed for the first stable release! """ from __future__ import generators import py -from py.__impl__.path import common +from py.__impl__.path import common import sys import inspect -moduletype = type(py) +moduletype = type(py) class Extpy(common.PathBase): - """ path object for addressing python objects. """ + """ path object for addressing python objects. """ sep = '.' - def __new__(cls, root, modpath=''): + def __new__(cls, root, modpath=''): if isinstance(root, str): - root = py.path.local(root) + root = py.path.local(root) #root = py.path.local(root) - #raise TypeError("first root argument is not resolvable") + #raise TypeError("first root argument is not resolvable") if not isinstance(modpath, str): - raise TypeError("second 'modpath' argument must be a dotted name.") + raise TypeError("second 'modpath' argument must be a dotted name.") #assert not isinstance(root, Extpy) self = object.__new__(cls) self.modpath = modpath - self.root = root + self.root = root return self def __hash__(self): - return hash((self.root, self.modpath)) + return hash((self.root, self.modpath)) def __repr__(self): - return 'extpy(%r, %r)' % (self.root, self.modpath) + return 'extpy(%r, %r)' % (self.root, self.modpath) def __str__(self): - return str(self.root.new(ext=self.modpath)) + return str(self.root.new(ext=self.modpath)) def join(self, *args): for arg in args: @@ -42,28 +42,28 @@ raise TypeError, "non-strings not allowed in %r" % args modpath = [x.strip('.') for x in ((self.modpath,)+args) if x] modpath = self.sep.join(modpath) - return self.__class__(self.root, modpath) + return self.__class__(self.root, modpath) def dirpath(self, *args): modpath = self.modpath.split(self.sep) [:-1] modpath = self.sep.join(modpath+list(args)) - return self.__class__(self.root, modpath) - + return self.__class__(self.root, modpath) + def new(self, **kw): """ create a modified version of this path. the following keyword arguments modify various path parts: - modpath substitute module path + modpath substitute module path """ - cls = self.__class__ + cls = self.__class__ if 'modpath' in kw: - return cls(self.root, kw['modpath']) + return cls(self.root, kw['modpath']) if 'basename' in kw: i = self.modpath.rfind('.') - if i != -1: + if i != -1: return cls(self.root, self.modpath[i+1:] + kw['basename']) else: return cls(self.root, kw['basename']) - return cls(self.root, self.modpath) + return cls(self.root, self.modpath) def get(self, spec): l = [] @@ -71,29 +71,29 @@ for name in spec.split(','): if name == 'basename': l.append(modparts[-1]) - return l + return l def resolve(self): """return the python object, obtained from traversing from - the root along the modpath. + the root along the modpath. """ - rest = filter(None, self.modpath.split('.')) + rest = filter(None, self.modpath.split('.')) target = self.getpymodule() - for name in rest: + for name in rest: try: target = getattr(target, name) except AttributeError: - raise py.error.ENOENT(target, name) - return target + raise py.error.ENOENT(target, name) + return target def getpymodule(self): - if hasattr(self.root, 'resolve'): - return self.root.resolve() + if hasattr(self.root, 'resolve'): + return self.root.resolve() else: return self.root.getpymodule() def relto(self, otherpath): - if self.root == otherpath.root: + if self.root == otherpath.root: if self.modpath.startswith(otherpath.modpath): s = self.modpath[len(otherpath.modpath):] return s.lstrip(self.sep) @@ -116,7 +116,7 @@ obj = self.resolve() l = [] #print "listdir on", self - if not hasattr(obj, '__dict__'): + if not hasattr(obj, '__dict__'): raise py.error.ENOTDIR(self, "does not have a __dict__ attribute") for name in dir(obj): sub = self.join(name) @@ -129,30 +129,30 @@ def getfilelineno(self, scrapinit=0): x = obj = self.resolve() - if inspect.ismodule(obj): + if inspect.ismodule(obj): return obj.__file__, 0 if inspect.ismethod(obj): - obj = obj.im_func + obj = obj.im_func if inspect.isfunction(obj): - obj = obj.func_code + obj = obj.func_code if inspect.iscode(obj): return py.path.local(obj.co_filename), obj.co_firstlineno - 1 else: - source, lineno = inspect.findsource(obj) + source, lineno = inspect.findsource(obj) return x.getfile(), lineno - 1 def visit(self, fil=None, rec=None, ignore=None, seen=None): def myrec(p, seen={id(self): True}): if id(p) in seen: return False - seen[id(p)] = True + seen[id(p)] = True if self.samefile(p): - return True - + return True + for x in super(Extpy, self).visit(fil=fil, rec=rec, ignore=ignore): yield x return - + if seen is None: seen = {id(self): True} @@ -165,20 +165,20 @@ try: l = self.listdir() except ignore: - return + return else: l = self.listdir() reclist = [] - for p in l: + for p in l: if fil is None or fil(p): yield p if id(p) not in seen: try: obj = p.resolve() - if inspect.isclass(obj) or inspect.ismodule(obj): + if inspect.isclass(obj) or inspect.ismodule(obj): reclist.append(p) finally: - seen[id(p)] = p + seen[id(p)] = p for p in reclist: for i in p.visit(fil, rec, seen): yield i @@ -186,20 +186,20 @@ def samefile(self, other): otherobj = other.resolve() try: - x = inspect.getfile(otherobj) - except TypeError: - return False + x = inspect.getfile(otherobj) + except TypeError: + return False if x.endswith('.pyc'): x = x[:-1] if str(self.root) == x: return True - def read(self): + def read(self): """ return a bytestring from looking at our underlying object. """ return str(self.resolve()) class Checkers(common.Checkers): - _depend_on_existence = (common.Checkers._depend_on_existence + + _depend_on_existence = (common.Checkers._depend_on_existence + ('func', 'class_', 'exists', 'dir')) def _obj(self): @@ -208,7 +208,7 @@ def exists(self): obj = self._obj() - return True + return True def func(self): ob = self._obj() @@ -216,20 +216,20 @@ def class_(self): ob = self._obj() - return inspect.isclass(ob) - + return inspect.isclass(ob) + def isinstance(self, args): return isinstance(self._obj(), args) def dir(self): obj = self._obj() - return inspect.isclass(obj) or inspect.ismodule(obj) + return inspect.isclass(obj) or inspect.ismodule(obj) def file(self): - return not self.dir() + return not self.dir() def genfunc(self): try: - return self._obj().func_code.co_flags & 32 + return self._obj().func_code.co_flags & 32 except AttributeError: - return False + return False Modified: py/dist/py/path/extpy/testing/__init__.py ============================================================================== --- py/dist/py/path/extpy/testing/__init__.py (original) +++ py/dist/py/path/extpy/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# Modified: py/dist/py/path/extpy/testing/inc_pseudofs.py ============================================================================== --- py/dist/py/path/extpy/testing/inc_pseudofs.py (original) +++ py/dist/py/path/extpy/testing/inc_pseudofs.py Sun Jan 9 16:49:34 2005 @@ -6,7 +6,7 @@ otherfile = 'otherfile' class otherdir: - init = 42 + init = 42 class execfile: - x = 42 + x = 42 Modified: py/dist/py/path/extpy/testing/inc_test_extpy.py ============================================================================== --- py/dist/py/path/extpy/testing/inc_test_extpy.py (original) +++ py/dist/py/path/extpy/testing/inc_test_extpy.py Sun Jan 9 16:49:34 2005 @@ -1,4 +1,4 @@ -from __future__ import generators +from __future__ import generators class A: x1 = 42 @@ -9,10 +9,10 @@ yield 2 class B: - x2 = 23 - + x2 = 23 + class Nested: class Class: def borgfunc(self): pass - + Modified: py/dist/py/path/extpy/testing/test_data/no_trailing_newline.py ============================================================================== --- py/dist/py/path/extpy/testing/test_data/no_trailing_newline.py (original) +++ py/dist/py/path/extpy/testing/test_data/no_trailing_newline.py Sun Jan 9 16:49:34 2005 @@ -4,4 +4,4 @@ ############################################################################# # 2004 M.E.Farmer Jr. -# Python license \ No newline at end of file +# Python license Modified: py/dist/py/path/extpy/testing/test_extpy.py ============================================================================== --- py/dist/py/path/extpy/testing/test_extpy.py (original) +++ py/dist/py/path/extpy/testing/test_extpy.py Sun Jan 9 16:49:34 2005 @@ -1,9 +1,9 @@ import os -import py +import py -from py.__impl__.path.test import common +from py.__impl__.path.test import common -mypath = py.magic.autopath().dirpath('inc_test_extpy.py') +mypath = py.magic.autopath().dirpath('inc_test_extpy.py') class TestExtPyCommonTests(common.CommonPathTests): def setup_class(cls): @@ -11,12 +11,12 @@ py.magic.autopath().dirpath('inc_pseudofs.py')) def test_file(self): - assert self.root.join('samplefile').check(file=1) - assert self.root.join('otherdir').check(file=0) - -class TestExtPy: + assert self.root.join('samplefile').check(file=1) + assert self.root.join('otherdir').check(file=0) + +class TestExtPy: def setup_class(cls): - cls.root = py.path.extpy(mypath) + cls.root = py.path.extpy(mypath) def test_join(self): p = self.root.join('A') @@ -27,7 +27,7 @@ def test_listdir_module(self): l = self.root.listdir() basenames = [x.basename for x in l] - dlist = dir(self.root.resolve()) + dlist = dir(self.root.resolve()) for name in dlist: assert name in basenames for name in basenames: @@ -36,7 +36,7 @@ def test_listdir_class(self): l = self.root.join('A').listdir() basenames = [x.basename for x in l] - dlist = dir(self.root.resolve().A) + dlist = dir(self.root.resolve().A) for name in dlist: assert name in basenames for name in basenames: @@ -45,33 +45,33 @@ def listobj(self): l = self.root.listobj(basestarts='path') assert len(l) == 1 - assert l[0] == path + assert l[0] == path def test_visit(self): l = list(self.root.visit(py.path.checker(basename='borgfunc'))) assert len(l) == 1 obj = l[0] - assert str(obj).endswith('Nested.Class.borgfunc') - assert obj.resolve() == self.root.resolve().Nested.Class.borgfunc + assert str(obj).endswith('Nested.Class.borgfunc') + assert obj.resolve() == self.root.resolve().Nested.Class.borgfunc def test_visit_fnmatch(self): - l = list(self.root.visit('borg*')) + l = list(self.root.visit('borg*')) assert len(l) == 1 obj = l[0] - assert str(obj).endswith('Nested.Class.borgfunc') - assert obj.resolve() == self.root.resolve().Nested.Class.borgfunc + assert str(obj).endswith('Nested.Class.borgfunc') + assert obj.resolve() == self.root.resolve().Nested.Class.borgfunc #def test_join_from_empty(self): - # p = path.py('') + # p = path.py('') # n = p.join('tokenize') # assert str(n) == 'tokenize' # - # p = path.py('', ns=os) + # p = path.py('', ns=os) # n = p.join('getlogin') # assert str(n) == 'getlogin' #def test_unspecifiedpypath_lists_modules(self): - # p = path.py('') + # p = path.py('') # l = p.listdir() # for i in l: # assert '.' not in str(i) @@ -84,20 +84,20 @@ # self.fail("%s is not in sys.modules") #def test_main_works(self): - # m = path.py('__main__') + # m = path.py('__main__') # import __main__ # assert m.resolve() is __main__ def test_relto(self): - m1 = self.root.new(modpath='a.b.c.d') + m1 = self.root.new(modpath='a.b.c.d') m2 = self.root.new(modpath='a.b') - m3 = self.root.new(modpath='') + m3 = self.root.new(modpath='') res = m1.relto(m2) assert str(res) == 'c.d' - assert m2.relto(m3) == 'a.b' + assert m2.relto(m3) == 'a.b' def test_basename(self): - m1 = self.root.new(modpath='a.b.hello') + m1 = self.root.new(modpath='a.b.hello') assert m1.basename == 'hello' assert m1.check(basename='hello') assert not m1.check(basename='nono') @@ -106,17 +106,17 @@ def test_dirpath(self): m1 = self.root.new(modpath='a.b.hello') - m2 = self.root.new(modpath='a.b') - m3 = self.root.new(modpath='a') - m4 = self.root.new(modpath='') - assert m1.dirpath() == m2 - assert m2.dirpath() == m3 - assert m3.dirpath() == m4 + m2 = self.root.new(modpath='a.b') + m3 = self.root.new(modpath='a') + m4 = self.root.new(modpath='') + assert m1.dirpath() == m2 + assert m2.dirpath() == m3 + assert m3.dirpath() == m4 def test_function(self): - p = self.root.join('A.func') + p = self.root.join('A.func') assert p.check(func=1) - p = self.root.join('A.x1') + p = self.root.join('A.x1') assert p.check(func=0) def test_generatorfunction(self): @@ -128,33 +128,33 @@ assert p.check(genfunc=0) def test_class(self): - p = self.root.join('A') + p = self.root.join('A') assert p.check(class_=1) def test_hashing_equality(self): x = self.root - y = self.root.new() - assert x == y - assert hash(x) == hash(y) + y = self.root.new() + assert x == y + assert hash(x) == hash(y) def test_parts2(self): - x = self.root.new(modpath='os.path.abspath') - l = x.parts() - assert len(l) == 4 + x = self.root.new(modpath='os.path.abspath') + l = x.parts() + assert len(l) == 4 assert self.root.join('') == l[0] assert self.root.join('os') == l[1] assert self.root.join('os.path') == l[2] assert self.root.join('os.path.abspath') == l[3] -#class TestExtPyWithModule: +#class TestExtPyWithModule: # def test_module(self): # import os -# x = py.path.extpy(os, 'path.abspath') +# x = py.path.extpy(os, 'path.abspath') # assert x.check() -# assert x.resolve() is os.path.abspath +# assert x.resolve() is os.path.abspath # #def setup_class(cls): - # cls.root = py.path.extpy(mypath) - + # cls.root = py.path.extpy(mypath) + class TestEval: disabled = True def test_funccall(self): @@ -170,17 +170,17 @@ p = path.py('os.path.qwe("a", ') s = test.raises(ValueError, "p.resolve()") -class TestErrors: +class TestErrors: def test_ENOENT(self): - p = py.path.extpy(mypath, 'somesuch') + p = py.path.extpy(mypath, 'somesuch') py.test.raises(py.error.ENOENT, p.resolve) def test_ENOENT_really(self): - p = py.path.extpy(mypath.new(basename='notexist'), 'somesuch') + p = py.path.extpy(mypath.new(basename='notexist'), 'somesuch') py.test.raises(py.error.ENOENT, p.resolve) #def test_ImportError(): - # p = path.py('__std.utest.test.data.failingimport.someattr') + # p = path.py('__std.utest.test.data.failingimport.someattr') # utest.raises(ImportError, p.resolve) class ExampleClass: Modified: py/dist/py/path/gateway/channeltest.py ============================================================================== --- py/dist/py/path/gateway/channeltest.py (original) +++ py/dist/py/path/gateway/channeltest.py Sun Jan 9 16:49:34 2005 @@ -25,7 +25,7 @@ def command_GET(self, id, spec): path = self.C2P[id] - self.channel.send(path.get(spec)) + self.channel.send(path.get(spec)) def command_READ(self, id): path = self.C2P[id] Modified: py/dist/py/path/gateway/channeltest2.py ============================================================================== --- py/dist/py/path/gateway/channeltest2.py (original) +++ py/dist/py/path/gateway/channeltest2.py Sun Jan 9 16:49:34 2005 @@ -12,7 +12,7 @@ #gw = py.execnet.SshGateway('codespeak.net') -gw = py.execnet.PopenGateway() +gw = py.execnet.PopenGateway() c = gw.remote_exec(SRC) subchannel = gw.channelfactory.new() c.send(subchannel) Modified: py/dist/py/path/gateway/remotepath.py ============================================================================== --- py/dist/py/path/gateway/remotepath.py (original) +++ py/dist/py/path/gateway/remotepath.py Sun Jan 9 16:49:34 2005 @@ -36,10 +36,10 @@ def get(self, spec): parts = spec.split(',') ask = [x for x in parts if x not in self._specs] - if ask: + if ask: self._channel.send(('GET', self._id, ",".join(ask))) - for part, value in zip(ask, self._channel.receive()): - self._specs[part] = value + for part, value in zip(ask, self._channel.receive()): + self._specs[part] = value return [self._specs[x] for x in parts] def read(self): Modified: py/dist/py/path/local/api.py ============================================================================== --- py/dist/py/path/local/api.py (original) +++ py/dist/py/path/local/api.py Sun Jan 9 16:49:34 2005 @@ -1,7 +1,7 @@ """ Tool functions regarding local filesystem paths """ -from py import path +from py import path def get_temproot(): """ return the system's temporary directory (where tempfiles are usually created in)""" @@ -10,16 +10,16 @@ return p.dirpath() finally: p.remove() - + def mkdtemp(): """ return a Path object pointing to a fresh new temporary directory - (which we created ourself). + (which we created ourself). """ import tempfile tries = 10 for i in range(tries): dname = tempfile.mktemp() - dpath = path.local(tempfile.mktemp()) + dpath = path.local(tempfile.mktemp()) try: dpath.mkdir() except path.FileExists: @@ -29,16 +29,16 @@ def make_numbered_dir(rootdir=None, base = 'session-', keep=3): """ return unique directory with a number greater than the current - maximum one. The number is assumed to start directly after base. + maximum one. The number is assumed to start directly after base. if keep is true directories with a number less than (maxnum-keep) - will be removed. + will be removed. """ if rootdir is None: rootdir = get_temproot() def parse_num(path): """ parse the number out of a path (if it matches the base) """ - bn = path.basename + bn = path.basename if bn.startswith(base): try: return int(bn[len(base):]) @@ -52,11 +52,11 @@ if num is not None: maxnum = max(maxnum, num) - # make the new directory + # make the new directory udir = rootdir.mkdir(base + str(maxnum+1)) # prune old directories - if keep: + if keep: for path in rootdir.listdir(): num = parse_num(path) if num is not None and num <= (maxnum - keep): @@ -67,7 +67,7 @@ if startmodule is None: fn = path.local() else: - mod = path.py(startmodule) + mod = path.py(startmodule) fn = mod.getfile() current = fn.dirpath() while current != fn: Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Sun Jan 9 16:49:34 2005 @@ -1,23 +1,23 @@ """ -specialized local path implementation. +specialized local path implementation. -This Path implementation offers some methods like chmod(), owner() -and so on that may only make sense on unix. +This Path implementation offers some methods like chmod(), owner() +and so on that may only make sense on unix. """ -from __future__ import generators +from __future__ import generators import sys, os, stat -import py -from py.__impl__.path import common +import py +from py.__impl__.path import common if sys.platform == 'win32': - from py.__impl__.path.local.win import WinMixin as PlatformMixin + from py.__impl__.path.local.win import WinMixin as PlatformMixin else: - from py.__impl__.path.local.posix import PosixMixin as PlatformMixin + from py.__impl__.path.local.posix import PosixMixin as PlatformMixin class LocalPath(common.FSPathBase, PlatformMixin): - """ Local path implementation offering access/modification - methods similar to os.path. + """ Local path implementation offering access/modification + methods similar to os.path. """ sep = os.sep class Checkers(common.FSCheckers): @@ -27,10 +27,10 @@ except AttributeError: try: self._statcache = self.path.stat() - except py.error.ELOOP: - self._statcache = self.path.lstat() + except py.error.ELOOP: + self._statcache = self.path.lstat() return self._statcache - + def dir(self): return stat.S_ISDIR(self._stat().st_mode) @@ -45,15 +45,15 @@ return stat.S_ISLNK(st.st_mode) def __new__(cls, path=None): - """ Initialize and return a local Path instance. + """ Initialize and return a local Path instance. Path can be relative to the current directory. If it is None then the current working directory is taken. Note that Path instances always carry an absolute path. - Note also that passing in a local path object will simply return - the exact same path object. Use new() to get a new copy. + Note also that passing in a local path object will simply return + the exact same path object. Use new() to get a new copy. """ - if isinstance(path, cls): + if isinstance(path, cls): if path.__class__ == cls: return path path = path.strpath @@ -77,9 +77,9 @@ """ create a modified version of this path. the following keyword arguments modify various path parts: - a:/some/path/to/a/file.ext + a:/some/path/to/a/file.ext || drive - |-------------| dirname + |-------------| dirname |------| basename |--| purebasename |--| ext @@ -91,18 +91,18 @@ if 'purebasename' in kw or 'ext' in kw: raise ValueError("invalid specification %r" % kw) else: - pb = kw.setdefault('purebasename', purebasename) + pb = kw.setdefault('purebasename', purebasename) try: ext = kw['ext'] - except KeyError: + except KeyError: pass else: if ext and not ext.startswith('.'): ext = '.' + ext kw['basename'] = pb + ext - kw.setdefault('drive', drive) - kw.setdefault('dirname', dirname) + kw.setdefault('drive', drive) + kw.setdefault('dirname', dirname) kw.setdefault('sep', self.sep) obj.strpath = os.path.normpath( "%(drive)s%(dirname)s%(sep)s%(basename)s" % kw) @@ -110,18 +110,18 @@ def get(self, spec): """ return a sequence of specified path parts. 'spec' is - a comma separated string containing path part names. - according to the following convention: - a:/some/path/to/a/file.ext + a comma separated string containing path part names. + according to the following convention: + a:/some/path/to/a/file.ext || drive - |-------------| dirname + |-------------| dirname |------| basename |--| purebasename |--| ext """ res = [] parts = self.strpath.split(self.sep) - + args = filter(None, spec.split(',') ) append = res.append for name in args: @@ -145,17 +145,17 @@ append(ext) else: raise ValueError, "invalid part specification %r" % name - return res + return res def join(self, *args, **kwargs): """ return a new path by appending all 'args' as path - components. if abs=1 is used restart from root if any + components. if abs=1 is used restart from root if any of the args is an absolute path. """ if not args: return self strargs = [self.strpath] - strargs.extend(map(str, args)) + strargs.extend(map(str, args)) if kwargs.get('abs', 0): for i in range(len(strargs)-1, 0, -1): if os.path.isabs(strargs[i]): @@ -170,7 +170,7 @@ def open(self, mode='r'): """ return an opened file with the given mode. """ - return self._callex(open, self.strpath, mode) + return self._callex(open, self.strpath, mode) def listdir(self, fil=None, sort=None): """ list directory contents, possibly filter by the given fil func @@ -179,7 +179,7 @@ if isinstance(fil, str): fil = common.fnmatch(fil) res = [] - for name in self._callex(os.listdir, self.strpath): + for name in self._callex(os.listdir, self.strpath): childurl = self.join(name) if fil is None or fil(childurl): res.append(childurl) @@ -217,7 +217,7 @@ self._callex(os.remove, self.strpath) def copy(self, target, archive=False): - assert not archive, "XXX archive-mode not supported" + assert not archive, "XXX archive-mode not supported" if self.check(file=1): if target.check(dir=1): target = target.join(self.basename) @@ -227,18 +227,18 @@ target.ensure(dir=1) def rec(p): return p.check(link=0) - for x in self.visit(rec=rec): - relpath = x.relto(self) + for x in self.visit(rec=rec): + relpath = x.relto(self) newx = target.join(relpath) if x.check(link=1): newx.mksymlinkto(x.readlink()) elif x.check(file=1): copychunked(x, newx) elif x.check(dir=1): - newx.ensure(dir=1) + newx.ensure(dir=1) def rename(self, target): - return self._callex(os.rename, str(self), str(target)) + return self._callex(os.rename, str(self), str(target)) def dumpobj(self, obj): """ pickle object into path location""" @@ -252,7 +252,7 @@ """ create & return the directory joined with args. """ p = self.join(*args) self._callex(os.mkdir, str(p)) - return p + return p def write(self, content): """ write string content into path. """ @@ -274,9 +274,9 @@ return self def ensure(self, *args, **kwargs): - """ ensure that an args-joined path exists (by default as + """ ensure that an args-joined path exists (by default as a file). if you specify a keyword argument 'dir=True' - then the path is forced to be a directory path. + then the path is forced to be a directory path. """ p = self.join(*args) if kwargs.get('dir', 0): @@ -288,16 +288,16 @@ def stat(self): """ Return an os.stat() tuple. """ - return self._callex(os.stat, self.strpath) + return self._callex(os.stat, self.strpath) def lstat(self): """ Return an os.lstat() tuple. """ - return self._callex(os.lstat, self.strpath) + return self._callex(os.lstat, self.strpath) # xlocal implementation def setmtime(self, mtime=None): """ set modification time for the given path. if 'mtime' is None - (the default) then the file's mtime is set to current time. + (the default) then the file's mtime is set to current time. Note that the resolution for 'mtime' is platform dependent. """ @@ -305,7 +305,7 @@ return self._callex(os.utime, self.strpath, mtime) try: return self._callex(os.utime, self.strpath, (-1, mtime)) - except py.error.EINVAL: + except py.error.EINVAL: return self._callex(os.utime, self.strpath, (self.atime(), mtime)) def chdir(self): @@ -336,7 +336,7 @@ return mod def getpycodeobj(self): - dotpy = self.check(ext='.py') + dotpy = self.check(ext='.py') if dotpy: my_magic = py.std.imp.get_magic() my_timestamp = int(self.mtime()) @@ -345,7 +345,7 @@ else: pycfile = self + 'o' try: - f = pycfile.open('rb') + f = pycfile.open('rb') try: header = f.read(8) if len(header) == 8: @@ -354,62 +354,62 @@ return py.std.marshal.load(f) finally: f.close() - except py.error.Error: + except py.error.Error: pass s = self.read(mode='rU') + '\n' codeobj = compile(s, str(self), 'exec', generators.compiler_flag) if dotpy: try: - f = pycfile.open('wb') + f = pycfile.open('wb') f.write(py.std.struct.pack('<4si', 'TEMP', -1)) # fixed below py.std.marshal.dump(codeobj, f) f.flush() f.seek(0) f.write(py.std.struct.pack('<4si', my_magic, my_timestamp)) f.close() - except py.error.Error: + except py.error.Error: pass return codeobj def sysexec(self, *argv): - """ return stdout-put from executing a system child process, - where the self path points to the binary (XXX or script) - to be executed. Note that this process is directly - invoked and not through a system shell. + """ return stdout-put from executing a system child process, + where the self path points to the binary (XXX or script) + to be executed. Note that this process is directly + invoked and not through a system shell. """ from py.__impl__.path.local.popen5.subprocess import Popen, PIPE - argv = map(str, argv) + argv = map(str, argv) proc = Popen([str(self)] + list(argv), stdout=PIPE, stderr=PIPE) stdout, stderr = proc.communicate() ret = proc.wait() if ret != 0: - raise py.process.cmdexec.Error(ret, ret, str(self), - stdout, - stderr,) + raise py.process.cmdexec.Error(ret, ret, str(self), + stdout, + stderr,) return stdout - - def sysfind(self, name, checker=None): - """ return a path object found by looking at the systems + + def sysfind(self, name, checker=None): + """ return a path object found by looking at the systems underlying PATH specification. If the checker is not None - it will be invoked to filter matching paths. If a binary - cannot be found, py.error.ENOENT is raised. - Note: This is probably not working on plain win32 systems - but may work on cygwin. - """ + it will be invoked to filter matching paths. If a binary + cannot be found, py.error.ENOENT is raised. + Note: This is probably not working on plain win32 systems + but may work on cygwin. + """ for x in py.std.os.environ['PATH'].split(':'): p = py.path.local(x).join(name) - if p.check(file=1): - if checker: - if not checker(p): - continue - return p - raise py.error.ENOENT(name) + if p.check(file=1): + if checker: + if not checker(p): + continue + return p + raise py.error.ENOENT(name) sysfind = classmethod(sysfind) #""" #special class constructors for local filesystem paths #""" def get_temproot(cls): - """ return the system's temporary directory + """ return the system's temporary directory (where tempfiles are usually created in) """ p = cls.mkdtemp() @@ -417,41 +417,41 @@ return p.dirpath() finally: p.remove() - get_temproot = classmethod(get_temproot) - + get_temproot = classmethod(get_temproot) + def mkdtemp(cls): """ return a Path object pointing to a fresh new temporary directory - (which we created ourself). + (which we created ourself). """ import tempfile tries = 10 for i in range(tries): dname = tempfile.mktemp() - dpath = cls(tempfile.mktemp()) + dpath = cls(tempfile.mktemp()) try: dpath.mkdir() except path.FileExists: continue return dpath raise py.error.ENOENT(dpath, "could not create tempdir, %d tries" % tries) - mkdtemp = classmethod(mkdtemp) + mkdtemp = classmethod(mkdtemp) def make_numbered_dir(cls, rootdir=None, base = 'session-', keep=3): """ return unique directory with a number greater than the current - maximum one. The number is assumed to start directly after base. + maximum one. The number is assumed to start directly after base. if keep is true directories with a number less than (maxnum-keep) - will be removed. + will be removed. """ if rootdir is None: rootdir = cls.get_temproot() def parse_num(path): """ parse the number out of a path (if it matches the base) """ - bn = path.basename + bn = path.basename if bn.startswith(base): try: return int(bn[len(base):]) - except ValueError: + except ValueError: pass # compute the maximum number currently in use with the base @@ -461,11 +461,11 @@ if num is not None: maxnum = max(maxnum, num) - # make the new directory + # make the new directory udir = rootdir.mkdir(base + str(maxnum+1)) # prune old directories - if keep: + if keep: for path in rootdir.listdir(): num = parse_num(path) if num is not None and num <= (maxnum - keep): @@ -481,7 +481,7 @@ # if startmodule is None: # fn = path.local() # else: - # mod = path.py(startmodule) + # mod = path.py(startmodule) # fn = mod.getfile() # current = fn.dirpath() # while current != fn: @@ -491,7 +491,7 @@ # current = current.dirpath() #parentdirmatch = classmethod(parentdirmatch) -def copychunked(src, dest): +def copychunked(src, dest): chunksize = 524288 # half a meg of bytes fsrc = src.open('rb') try: @@ -523,17 +523,17 @@ dirpath = cfile.dirpath() lastdir = dirpath.chdir() try: - modname = cfile.purebasename + modname = cfile.purebasename lib = py.path.local(modname+'.so') # argl! we need better "build"-locations alltogether! - if lib.check(): + if lib.check(): lib.remove() c = stdoutcapture.Capture(mixed_out_err = True) try: try: setup( name = "pylibmodules", - ext_modules=[ + ext_modules=[ Extension(modname, [str(cfile)]) ], script_name = 'setup.py', @@ -542,16 +542,16 @@ ) finally: foutput, foutput = c.done() - except KeyboardInterrupt: + except KeyboardInterrupt: raise - except SystemExit: + except SystemExit: raise RuntimeError("cannot compile %s:\n%s" % (cfile, foutput.read(),)) # XXX do we need to do some check on fout/ferr? # XXX not a nice way to import a module - if debug: + if debug: print "inserting path to sys.path", dirpath sys.path.insert(0, '.') - if debug: + if debug: print "import %(modname)s as testmodule" % locals() exec py.code.compile("import %(modname)s as testmodule" % locals()) sys.path.pop(0) Modified: py/dist/py/path/local/popen5/testing/__init__.py ============================================================================== --- py/dist/py/path/local/popen5/testing/__init__.py (original) +++ py/dist/py/path/local/popen5/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# Modified: py/dist/py/path/local/popen5/testing/test_subprocess.py ============================================================================== --- py/dist/py/path/local/popen5/testing/test_subprocess.py (original) +++ py/dist/py/path/local/popen5/testing/test_subprocess.py Sun Jan 9 16:49:34 2005 @@ -21,7 +21,7 @@ def remove_stderr_debug_decorations(stderr): return py.std.re.sub(r"\[\d+ refs\]\r?\n?$", "", stderr) -class TestPopen5(py.test.compat.TestCase): +class TestPopen5(py.test.compat.TestCase): disabled = True def mkstemp(self): """wrapper for mkstemp, calling mktemp if mkstemp is not available""" Modified: py/dist/py/path/local/posix.py ============================================================================== --- py/dist/py/path/local/posix.py (original) +++ py/dist/py/path/local/posix.py Sun Jan 9 16:49:34 2005 @@ -1,5 +1,5 @@ """ -module to access local filesystem pathes +module to access local filesystem pathes (mostly filename manipulations but also file operations) """ import os, sys, stat @@ -7,20 +7,20 @@ import py #__________________________________________________________ # -# Local Path Posix Mixin +# Local Path Posix Mixin #__________________________________________________________ class PosixMixin: - # an instance needs to be a local path instance + # an instance needs to be a local path instance def owner(self): """ return owner name of file. """ - uid = self.stat().st_uid - entry = self._callex(py.std.pwd.getpwuid, uid) + uid = self.stat().st_uid + entry = self._callex(py.std.pwd.getpwuid, uid) return entry[0] def group(self): """ return group name of file. """ - gid = self.stat().st_gid + gid = self.stat().st_gid entry = self._callex(py.std.grp.getgrgid, gid) return entry[0] @@ -30,46 +30,46 @@ def chmod(self, mode, rec=0): """ change permissions to the given mode. If mode is an - integer it directly encodes the os-specific modes. + integer it directly encodes the os-specific modes. (xxx if mode is a string then it specifies access rights - in '/bin/chmod' style, e.g. a+r). - if rec is True perform recursively. + in '/bin/chmod' style, e.g. a+r). + if rec is True perform recursively. """ if not isinstance(mode, int): - raise TypeError("mode %r must be an integer" % (mode,)) + raise TypeError("mode %r must be an integer" % (mode,)) if rec: for x in self.visit(): - self._callex(os.chmod, str(x), mode) - self._callex(os.chmod, str(self), mode) + self._callex(os.chmod, str(x), mode) + self._callex(os.chmod, str(self), mode) def chown(self, user, group, rec=0): - """ change ownership to the given user and group. + """ change ownership to the given user and group. user and group may be specified by a number or - by a name. if rec is True change ownership - recursively. + by a name. if rec is True change ownership + recursively. """ uid = getuserid(user) gid = getgroupid(group) if rec: for x in self.visit(rec=py.path.checker(link=0)): - self._callex(os.chown, str(x), uid, gid) - self._callex(os.chown, str(self), uid, gid) + self._callex(os.chown, str(x), uid, gid) + self._callex(os.chown, str(self), uid, gid) def readlink(self): - """ return value of a symbolic link. """ - return self._callex(os.readlink, self.strpath) + """ return value of a symbolic link. """ + return self._callex(os.readlink, self.strpath) - def mklinkto(self, oldname): - """ posix style hard link to another name. """ + def mklinkto(self, oldname): + """ posix style hard link to another name. """ self._callex(os.link, str(oldname), str(self)) def mksymlinkto(self, value, absolute=1): - """ create a symbolic link with the given value (pointing to another name). """ + """ create a symbolic link with the given value (pointing to another name). """ if absolute: self._callex(os.symlink, str(value), self.strpath) else: base = self.common(value) - # with posix local paths '/' is always a common base + # with posix local paths '/' is always a common base relsource = self.__class__(value).relto(base) reldest = self.relto(base) n = reldest.count(self.sep) Modified: py/dist/py/path/local/stdoutcapture.py ============================================================================== --- py/dist/py/path/local/stdoutcapture.py (original) +++ py/dist/py/path/local/stdoutcapture.py Sun Jan 9 16:49:34 2005 @@ -6,7 +6,7 @@ class Capture: - + def __init__(self, mixed_out_err = False): "Start capture of the Unix-level stdout and stderr." if (not hasattr(os, 'tmpfile') or Modified: py/dist/py/path/local/testing/__init__.py ============================================================================== --- py/dist/py/path/local/testing/__init__.py (original) +++ py/dist/py/path/local/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# 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 Jan 9 16:49:34 2005 @@ -1,6 +1,6 @@ import py from py.path import local, checker -from py.__impl__.path.test.fscommon import CommonFSTests, setuptestfs +from py.__impl__.path.test.fscommon import CommonFSTests, setuptestfs class LocalSetup: def setup_class(cls): @@ -13,7 +13,7 @@ def teardown_method(self, method): self.tmpdir.remove(rec=1) - + class TestLocalPath(LocalSetup, CommonFSTests): def test_initialize_curdir(self): assert str(local()) == py.std.os.getcwd() @@ -33,7 +33,7 @@ assert path1 == path2 assert path2 == path1 path3 = self.root.join('samplefile') - assert path3 != path2 + assert path3 != path2 assert path2 != path3 def test_dump(self): @@ -98,7 +98,7 @@ def test_chdir(self): tmpdir = self.tmpdir.realpath() - old = local() + old = local() try: res = tmpdir.chdir() assert str(res) == str(old) @@ -107,69 +107,69 @@ old.chdir() def test_ensure_filepath_withdir(self): - tmpdir = self.tmpdir + tmpdir = self.tmpdir newfile = tmpdir.join('test1','test2') newfile.ensure() assert newfile.check(file=1) def test_ensure_filepath_withoutdir(self): - tmpdir = self.tmpdir + tmpdir = self.tmpdir newfile = tmpdir.join('test1') t = newfile.ensure() assert t == newfile assert newfile.check(file=1) def test_ensure_dirpath(self): - tmpdir = self.tmpdir + tmpdir = self.tmpdir newfile = tmpdir.join('test1','test2') t = newfile.ensure(dir=1) assert t == newfile assert newfile.check(dir=1) class TestExecution(LocalSetup): - disabled = py.std.sys.platform == 'win32' + disabled = py.std.sys.platform == 'win32' def test_sysfind(self): x = py.path.local.sysfind('test') - assert x.check(file=1) + assert x.check(file=1) py.test.raises(py.error.ENOENT, """ py.path.local.sysfind('jaksdkasldqwe') - """) + """) def test_sysfind_multiple(self): - dir = py.test.config.tmpdir.ensure('sysfind', dir=1) + dir = py.test.config.tmpdir.ensure('sysfind', dir=1) env = py.std.os.environ - oldpath = env['PATH'] - try: - env['PATH'] += ":%s:%s" % (dir.ensure('a'), - dir.join('b')) - dir.ensure('b', 'a') + oldpath = env['PATH'] + try: + env['PATH'] += ":%s:%s" % (dir.ensure('a'), + dir.join('b')) + dir.ensure('b', 'a') checker = lambda x: x.dirpath().basename == 'b' x = py.path.local.sysfind('a', checker=checker) assert x.basename == 'a' - assert x.dirpath().basename == 'b' - checker = lambda x: None - py.test.raises(py.error.ENOENT, """ + assert x.dirpath().basename == 'b' + checker = lambda x: None + py.test.raises(py.error.ENOENT, """ py.path.local.sysfind('a', checker=checker) - """) + """) finally: - env['PATH'] = oldpath - #dir.remove() + env['PATH'] = oldpath + #dir.remove() def test_sysexec(self): x = py.path.local.sysfind('ls') - out = x.sysexec() + out = x.sysexec() for x in py.path.local(): - assert out.find(x.basename) != -1 + assert out.find(x.basename) != -1 def test_sysexec_failing(self): - x = py.path.local.sysfind('false') + x = py.path.local.sysfind('false') py.test.raises(py.process.cmdexec.Error, """ x.sysexec('aksjdkasjd') """) def test_make_numbered_dir(self): - root = self.tmpdir + root = self.tmpdir root.ensure('base.not_an_int', dir=1) for i in range(10): numdir = local.make_numbered_dir(root, 'base.', keep=2) 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 Jan 9 16:49:34 2005 @@ -1,15 +1,15 @@ import py import sys from py.__impl__.path.test.fscommon import setuptestfs -checker = py.path.checker -local = py.path.local +checker = py.path.checker +local = py.path.local class TestPOSIXLocalPath: #root = local(TestLocalPath.root) disabled = sys.platform == 'win32' def setup_class(cls): - cls.root = py.test.config.tmpdir / 'TestPosixLocalPath' + cls.root = py.test.config.tmpdir / 'TestPosixLocalPath' cls.root.ensure(dir=1) setuptestfs(cls.root) @@ -59,9 +59,9 @@ finally: tmpdir.remove(rec=1) - def test_relto_with_root(self): + def test_relto_with_root(self): y = self.root.join('x').relto(py.path.local('/')) - assert y[0] == str(self.root)[1] + assert y[0] == str(self.root)[1] def test_visit_recursive_symlink(self): tmpdir = local.mkdtemp() @@ -88,10 +88,10 @@ tmpdir = local.mkdtemp().realpath() try: linkpath = tmpdir.join('test') - linkpath.mksymlinkto(linkpath) # point to itself + linkpath.mksymlinkto(linkpath) # point to itself assert linkpath.check(link=1) linkpath.remove() - assert not linkpath.check() + assert not linkpath.check() finally: tmpdir.remove(rec=1) @@ -103,7 +103,7 @@ filepath.write("") linkpath.mksymlinkto(filepath) realpath = linkpath.realpath() - assert realpath.basename == 'file' + assert realpath.basename == 'file' finally: tmpdir.remove(rec=1) @@ -118,7 +118,7 @@ def XXXtest_atime(self): # XXX disabled. this test is just not platform independent enough # because acesstime resolution is very different through - # filesystems even on one platform. + # filesystems even on one platform. import time path = self.root.join('samplefile') atime = path.atime() @@ -145,12 +145,12 @@ def test_chmod_simple_int(self): print "self.root is", self.root mode = self.root.mode() - self.root.chmod(mode/2) + self.root.chmod(mode/2) try: assert self.root.mode() != mode finally: self.root.chmod(mode) - assert self.root.mode() == mode + assert self.root.mode() == mode def test_chmod_rec_int(self): # XXX fragile test @@ -162,17 +162,17 @@ self.root.chmod(0772, rec=1) try: for x in self.root.visit(rec=recfilter): - assert x.mode() & 0777 == 0772 + assert x.mode() & 0777 == 0772 finally: for x,y in oldmodes.items(): - x.chmod(y) + x.chmod(y) def test_chown_identity(self): owner = self.root.owner() group = self.root.group() - self.root.chown(owner, group) + self.root.chown(owner, group) def test_chown_identity_rec_mayfail(self): owner = self.root.owner() group = self.root.group() - self.root.chown(owner, group) + self.root.chown(owner, group) Modified: py/dist/py/path/local/win.py ============================================================================== --- py/dist/py/path/local/win.py (original) +++ py/dist/py/path/local/win.py Sun Jan 9 16:49:34 2005 @@ -1,7 +1,7 @@ """ -module for win-specific local path stuff +module for win-specific local path stuff -(implementor needed :-) +(implementor needed :-) """ class WinMixin: Modified: py/dist/py/path/svn/cache.py ============================================================================== --- py/dist/py/path/svn/cache.py (original) +++ py/dist/py/path/svn/cache.py Sun Jan 9 16:49:34 2005 @@ -29,7 +29,7 @@ class RepoCache: """ The Repocache manages discovered repository paths and their revisions. If inside a timeout the cache - will even return the revision of the root. + will even return the revision of the root. """ timeout = 20 # seconds after which we forget that we know the last revision @@ -44,7 +44,7 @@ return if timestamp is None: timestamp = time.time() - + for entry in self.repos: if url == entry.url: entry.timestamp = timestamp Modified: py/dist/py/path/svn/svncommon.py ============================================================================== --- py/dist/py/path/svn/svncommon.py (original) +++ py/dist/py/path/svn/svncommon.py Sun Jan 9 16:49:34 2005 @@ -1,5 +1,5 @@ """ -module with a base subversion path object. +module with a base subversion path object. """ import os, sys, time, re import py @@ -18,17 +18,17 @@ def __str__(self): """ return a string representation (including rev-number) """ - return self.strpath + return self.strpath def __hash__(self): return hash(self.strpath) def new(self, **kw): """ create a modified version of this path. A 'rev' argument - indicates a new revision. + indicates a new revision. the following keyword arguments modify various path parts: - http://host.com/repo/path/file.ext + http://host.com/repo/path/file.ext |-----------------------| dirname |------| basename |--| purebasename @@ -42,15 +42,15 @@ if 'purebasename' in kw or 'ext' in kw: raise ValueError("invalid specification %r" % kw) else: - pb = kw.setdefault('purebasename', purebasename) - ext = kw.setdefault('ext', ext) + pb = kw.setdefault('purebasename', purebasename) + ext = kw.setdefault('ext', ext) if ext and not ext.startswith('.'): ext = '.' + ext kw['basename'] = pb + ext - kw.setdefault('dirname', dirname) + kw.setdefault('dirname', dirname) kw.setdefault('sep', self.sep) - if kw['basename']: + if kw['basename']: obj.strpath = "%(dirname)s%(sep)s%(basename)s" % kw else: obj.strpath = "%(dirname)s" % kw @@ -59,11 +59,11 @@ def get(self, spec): """ get specified parts of the path. 'arg' is a string with comma separated path parts. The parts are returned - in exactly the order of the specification. - - you may specify the following parts: + in exactly the order of the specification. + + you may specify the following parts: - http://host.com/repo/path/file.ext + http://host.com/repo/path/file.ext |-----------------------| dirname |------| basename |--| purebasename @@ -90,23 +90,23 @@ res.append(ext) else: raise NameError, "Don't know part %r" % name - return res + return res def __eq__(self, other): """ return true if path and rev attributes each match """ - return (str(self) == str(other) and + return (str(self) == str(other) and (self.rev == other.rev or self.rev == other.rev)) def __ne__(self, other): return not self == other def join(self, *args): - """ return a new Path (with the same revision) which is composed + """ return a new Path (with the same revision) which is composed of the self Path followed by 'args' path components. """ if not args: return self - + args = tuple([arg.strip(self.sep) for arg in args]) parts = (self.strpath, ) + args newpath = self.__class__(self.sep.join(parts), self.rev) @@ -124,19 +124,19 @@ # XXX unify argument naming with LocalPath.listdir def listdir(self, fil=None, sort=None): - """ return a sequence of Paths. + """ return a sequence of Paths. listdir will return either a tuple or a list of paths - depending on implementation choices. + depending on implementation choices. """ if isinstance(fil, str): fil = common.fnmatch(fil) - nameinfo_seq = self._listdir_nameinfo() - if len(nameinfo_seq) == 1: - name, info = nameinfo_seq[0] - if name == self.basename and info.kind == 'file': - if not self.check(dir=1): - raise py.error.ENOTDIR(self) + nameinfo_seq = self._listdir_nameinfo() + if len(nameinfo_seq) == 1: + name, info = nameinfo_seq[0] + if name == self.basename and info.kind == 'file': + if not self.check(dir=1): + raise py.error.ENOTDIR(self) paths = self._make_path_tuple(nameinfo_seq) if fil or sort: @@ -151,12 +151,12 @@ def info(self): """ return an Info structure with svn-provided information. """ parent = self.dirpath() - nameinfo_seq = parent._listdir_nameinfo() + nameinfo_seq = parent._listdir_nameinfo() bn = self.basename for name, info in nameinfo_seq: - if name == bn: - return info - raise py.error.ENOENT(self) + if name == bn: + return info + raise py.error.ENOENT(self) def size(self): """ Return the size of the file content of the Path. """ @@ -167,9 +167,9 @@ return self.info().mtime def relto(self, rel): - """ Return a string which is the relative part of the Path to 'rel'. + """ Return a string which is the relative part of the Path to 'rel'. - If the Path is not relative to the given base, return an empty string. + If the Path is not relative to the given base, return an empty string. """ relpath = rel.strpath if self.strpath.startswith(relpath): @@ -199,7 +199,7 @@ #def _getlatestrevision(self): # """ return latest repo-revision for this path. """ - # url = self.strpath + # url = self.strpath # path = self.__class__(url, None) # # # we need a long walk to find the root-repo and revision @@ -210,7 +210,7 @@ # path = path.dirpath() # except (IOError, process.cmdexec.Error): # break - # if rev is None: + # if rev is None: # raise IOError, "could not determine newest repo revision for %s" % self # return rev @@ -224,7 +224,7 @@ def _listdirworks(self): try: self.path.listdir() - except py.error.ENOENT: + except py.error.ENOENT: return False else: return True @@ -232,13 +232,13 @@ def file(self): try: return self.path.info().kind == 'file' - except py.error.ENOENT: - return False + except py.error.ENOENT: + return False def exists(self): try: return self.path.info() - except py.error.ENOENT: + except py.error.ENOENT: return self._listdirworks() def parse_apr_time(timestr): Modified: py/dist/py/path/svn/testing/__init__.py ============================================================================== --- py/dist/py/path/svn/testing/__init__.py (original) +++ py/dist/py/path/svn/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# Modified: py/dist/py/path/svn/testing/svntestbase.py ============================================================================== --- py/dist/py/path/svn/testing/svntestbase.py (original) +++ py/dist/py/path/svn/testing/svntestbase.py Sun Jan 9 16:49:34 2005 @@ -1,7 +1,7 @@ import py from py import path, test, process -from py.__impl__.path.test.fscommon import CommonFSTests, setuptestfs -from py.__impl__.path.svn import cache +from py.__impl__.path.test.fscommon import CommonFSTests, setuptestfs +from py.__impl__.path.svn import cache mypath = py.magic.autopath() repodump = mypath.dirpath('testrepo.dump') @@ -18,25 +18,25 @@ try: py.process.cmdexec('svnadmin create %s' % repo) py.process.cmdexec('svnadmin load -q %r <%r' % (str(repo), str(repodump))) - except py.process.cmdexec.Error: + except py.process.cmdexec.Error: repo.remove() raise py.test.skip('could not create temporary svn test repository') print "created svn repository", repo wcdir.ensure(dir=1) - wc = py.path.svnwc(wcdir) - wc.checkout(url='file://%s' % repo) + wc = py.path.svnwc(wcdir) + wc.checkout(url='file://%s' % repo) print "checked out new repo into", wc else: - print "using repository at", repo + print "using repository at", repo wc = py.path.svnwc(wcdir) return ("file://%s" % repo, wc) class CommonSvnTests(CommonFSTests): def setup_method(self, meth): - bn = meth.func_name - for x in 'test_remove', 'test_move': - if bn.startswith(x): + bn = meth.func_name + for x in 'test_remove', 'test_move': + if bn.startswith(x): py.test.skip( "tests for modifying svn needs better test state management") @@ -85,7 +85,7 @@ # raises(py.error.ENOENT, url.listdir) #def test_newrev(self): - # url = self.root.new(rev=None) + # url = self.root.new(rev=None) # assert url.rev == None # assert url.strpath == self.root.strpath # url = self.root.new(rev=10) @@ -97,12 +97,12 @@ # res = url.info() # assert res.size > len("samplefile") and res.created_rev == 1155 - # the following tests are easier if we have a path class + # the following tests are easier if we have a path class def test_repocache_simple(self): repocache = cache.RepoCache() - repocache.put(self.root.strpath, 42) + repocache.put(self.root.strpath, 42) url, rev = repocache.get(self.root.join('test').strpath) - assert rev == 42 + assert rev == 42 assert url == self.root.strpath def test_repocache_notimeout(self): @@ -122,7 +122,7 @@ def _test_getreporev(self): """ this test runs so slow it's usually disabled """ - old = cache.repositories.repos + old = cache.repositories.repos try: _repocache.clear() root = self.root.new(rev=-1) Modified: py/dist/py/path/svn/testing/test_urlcommand.py ============================================================================== --- py/dist/py/path/svn/testing/test_urlcommand.py (original) +++ py/dist/py/path/svn/testing/test_urlcommand.py Sun Jan 9 16:49:34 2005 @@ -1,9 +1,9 @@ import py -from svntestbase import CommonCommandAndBindingTests, getrepowc +from svntestbase import CommonCommandAndBindingTests, getrepowc class TestSvnCommandPath(CommonCommandAndBindingTests): def __init__(self): - repo, wc = getrepowc() + repo, wc = getrepowc() self.root = py.path.svnurl(repo) def xtest_copy_file(self): Modified: py/dist/py/path/svn/testing/test_wccommand.py ============================================================================== --- py/dist/py/path/svn/testing/test_wccommand.py (original) +++ py/dist/py/path/svn/testing/test_wccommand.py Sun Jan 9 16:49:34 2005 @@ -1,7 +1,7 @@ import py from svntestbase import CommonSvnTests, getrepowc -class TestWCSvnCommandPath(CommonSvnTests): +class TestWCSvnCommandPath(CommonSvnTests): def __init__(self): repo, self.root = getrepowc() @@ -83,7 +83,7 @@ def test_diff(self): p = self.root / 'anotherfile' out = p.diff(rev=2) - assert out.find('hello') != -1 + assert out.find('hello') != -1 def test_join_abs(self): s = str(self.root.localpath) @@ -94,7 +94,7 @@ assert self.root.join('samplefile', abs=1) == self.root.join('samplefile') def test_str_gives_localpath(self): - assert str(self.root) == str(self.root.localpath) + assert str(self.root) == str(self.root.localpath) def test_versioned(self): assert self.root.check(versioned=1) @@ -119,11 +119,11 @@ self.root.propdel('gaga') def test_proplist_recursive(self): - s = self.root.join('samplefile') - s.propset('gugu', 'that') + s = self.root.join('samplefile') + s.propset('gugu', 'that') try: - p = self.root.proplist(rec=1) - assert self.root / 'samplefile' in p + p = self.root.proplist(rec=1) + assert self.root / 'samplefile' in p finally: s.propdel('gugu') @@ -134,7 +134,7 @@ """ try: self.root.propset('gaga', value) - backvalue = self.root.propget('gaga') + backvalue = self.root.propget('gaga') assert backvalue == value #assert len(backvalue.split('\n')) == 1 finally: @@ -149,8 +149,8 @@ self.root.join('a').remove(force=1) def test_not_versioned(self): - p = self.root.localpath.mkdir('whatever') - f = self.root.localpath.ensure('testcreatedfile') + p = self.root.localpath.mkdir('whatever') + f = self.root.localpath.ensure('testcreatedfile') try: assert self.root.join('whatever').check(versioned=0) assert self.root.join('testcreatedfile').check(versioned=0) Modified: py/dist/py/path/svn/urlcommand.py ============================================================================== --- py/dist/py/path/svn/urlcommand.py (original) +++ py/dist/py/path/svn/urlcommand.py Sun Jan 9 16:49:34 2005 @@ -1,38 +1,38 @@ """ module defining a subversion path object based on the external -command 'svn'. +command 'svn'. """ import os, sys, time, re -import py +import py from py import path, process -from py.__impl__.path import common -from py.__impl__.path.svn import svncommon -from py.__impl__.misc.cache import BuildcostAccessCache, AgingCache +from py.__impl__.path import common +from py.__impl__.path.svn import svncommon +from py.__impl__.misc.cache import BuildcostAccessCache, AgingCache class SvnCommandPath(svncommon.SvnPathBase): - _lsrevcache = BuildcostAccessCache(maxentries=128) - _lsnorevcache = AgingCache(maxentries=1000, maxseconds=60.0) + _lsrevcache = BuildcostAccessCache(maxentries=128) + _lsnorevcache = AgingCache(maxentries=1000, maxseconds=60.0) - def __new__(cls, path, rev=None): + def __new__(cls, path, rev=None): self = object.__new__(cls) - if not isinstance(path, str): - path = str(path) - path = path.rstrip('/') - self.strpath = path + if not isinstance(path, str): + path = str(path) + path = path.rstrip('/') + self.strpath = path self.rev = rev return self def __repr__(self): if self.rev == -1: - return 'svnurl(%r)' % self.strpath + return 'svnurl(%r)' % self.strpath else: - return 'svnurl(%r, %r)' % (self.strpath, self.rev) + return 'svnurl(%r, %r)' % (self.strpath, self.rev) def _svn(self, cmd, *args): - if self.rev is None: + if self.rev is None: l = ['svn %s' % cmd] else: l = ['svn %s -r %d' % (cmd, self.rev)] @@ -53,48 +53,48 @@ # fixing the locale because we can't otherwise parse string = svncommon.fixlocale() + " ".join(l) #print "execing", string - try: + try: out = process.cmdexec(string) - except py.process.cmdexec.Error, e: - if e.err.find('File Exists'): - raise py.error.EEXIST(self) - raise + except py.process.cmdexec.Error, e: + if e.err.find('File Exists'): + raise py.error.EEXIST(self) + raise return out def open(self, mode='r'): - assert 'w' not in mode and 'a' not in mode, "XXX not implemented for svn cmdline" + assert 'w' not in mode and 'a' not in mode, "XXX not implemented for svn cmdline" assert self.check(file=1) # svn cat returns an empty file otherwise def popen(cmd): return os.popen(cmd) if self.rev is None: - return popen(svncommon.fixlocale() + + return popen(svncommon.fixlocale() + 'svn cat "%s"' % (self.strpath, )) else: - return popen(svncommon.fixlocale() + + return popen(svncommon.fixlocale() + 'svn cat -r %s "%s"' % (self.rev, self.strpath)) - # modifying methods (cache must be invalidated) - def mkdir(self, *args, **kwargs): - commit_msg=kwargs.get('msg', "mkdir by py lib invocation") - createpath = self.join(*args) + # modifying methods (cache must be invalidated) + def mkdir(self, *args, **kwargs): + commit_msg=kwargs.get('msg', "mkdir by py lib invocation") + createpath = self.join(*args) createpath._svnwrite('mkdir', '-m', commit_msg) - self._lsnorevcache.delentry(createpath.dirpath().strpath) - return createpath + self._lsnorevcache.delentry(createpath.dirpath().strpath) + return createpath def copy(self, target, msg='copied by py lib invocation'): - if getattr(target, 'rev', None) is not None: + if getattr(target, 'rev', None) is not None: raise py.error.EINVAL(target, "can't copy to revisioned resource") process.cmdexec("svn copy -m %r %s %s" %(msg, str(self), str(target))) - self._lsnorevcache.delentry(target.dirpath().strpath) + self._lsnorevcache.delentry(target.dirpath().strpath) def remove(self, rec=1, msg='removed by py lib invocation'): if self.rev is not None: - raise py.error.EINVAL(self, "can't remove revisioned resource") + raise py.error.EINVAL(self, "can't remove revisioned resource") process.cmdexec("svn rm -m %r %s" %(msg, str(self))) - self._lsnorevcache.delentry(self.dirpath().strpath) + self._lsnorevcache.delentry(self.dirpath().strpath) - # end of modifying methods + # end of modifying methods def _propget(self, name): res = self._svn('propget', name) return res[:-1] # strip trailing newline @@ -107,19 +107,19 @@ def _listdir_nameinfo(self): """ return sequence of name-info directory entries of self """ - def builder(): + def builder(): try: res = self._svn('ls', '-v') except process.cmdexec.Error, e: if e.err.find('non-existent in that revision') != -1: raise py.error.ENOENT(self, e.err) elif e.err.find('not part of a repository')!=-1: - raise py.error.ENOENT(self, e.err) + raise py.error.ENOENT(self, e.err) elif e.err.find('Unable to open')!=-1: - raise py.error.ENOENT(self, e.err) + raise py.error.ENOENT(self, e.err) elif e.err.lower().find('method not allowed')!=-1: - raise py.error.EACCES(self, e.err) - raise py.error.Error(e.err) + raise py.error.EACCES(self, e.err) + raise py.error.Error(e.err) lines = res.split('\n') nameinfo_seq = [] for lsline in lines: @@ -127,9 +127,9 @@ info = InfoSvnCommand(lsline) nameinfo_seq.append((info._name, info)) return nameinfo_seq - if self.rev is not None: + if self.rev is not None: return self._lsrevcache.getorbuild((self.strpath, self.rev), builder) - else: + else: return self._lsnorevcache.getorbuild(self.strpath, builder) def log(self, rev_start=None, rev_end=1, verbose=False): @@ -143,7 +143,7 @@ rev_opt = "-r %s:%s" % (rev_start, rev_end) verbose_opt = verbose and "-v" or "" xmlpipe = os.popen(svncommon.fixlocale() + - 'svn log --xml %s %s "%s"' % + 'svn log --xml %s %s "%s"' % (rev_opt, verbose_opt, self.strpath)) from xml.dom import minidom tree = minidom.parse(xmlpipe) @@ -187,16 +187,16 @@ # helper functions #____________________________________________________ def parse_time_with_missing_year(timestr): - """ analyze the time part from a single line of "svn ls -v" + """ analyze the time part from a single line of "svn ls -v" the svn output doesn't show the year makes the 'timestr' - ambigous. + ambigous. """ t_now = time.gmtime() tparts = timestr.split() month = time.strptime(tparts.pop(0), '%b')[1] day = time.strptime(tparts.pop(0), '%d')[2] - last = tparts.pop(0) # year or hour:minute + last = tparts.pop(0) # year or hour:minute try: year = time.strptime(last, '%Y')[0] hour = minute = 0 @@ -233,7 +233,7 @@ self.msg = '' elif lpart.nodeName == u'date': #2003-07-29T20:05:11.598637Z - timestr = lpart.firstChild.nodeValue.encode('UTF-8') + timestr = lpart.firstChild.nodeValue.encode('UTF-8') self.date = svncommon.parse_apr_time(timestr) elif lpart.nodeName == u'paths': self.strpaths = [] @@ -243,7 +243,7 @@ def __repr__(self): return '' % ( self.rev, self.author, self.date) - + class _Head: def __str__(self): Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Sun Jan 9 16:49:34 2005 @@ -2,25 +2,25 @@ svn-Command based Implementation of a Subversion WorkingCopy Path. - SvnWCCommandPath is the main class. + SvnWCCommandPath is the main class. - SvnWC is an alias to this class. + SvnWC is an alias to this class. """ import os, sys, time, re from py import path -import py -from py.__impl__.path import common +import py +from py.__impl__.path import common from py.__impl__.path.svn import cache -from py.__impl__.path.svn import svncommon +from py.__impl__.path.svn import svncommon DEBUG = 0 class SvnWCCommandPath(common.FSPathBase): sep = os.sep - def __new__(cls, wcpath=None): + def __new__(cls, wcpath=None): self = object.__new__(cls) self.localpath = path.local(wcpath) return self @@ -28,7 +28,7 @@ strpath = property(lambda x: str(x.localpath), None, None, "string path") def __eq__(self, other): - return self.localpath == getattr(other, 'localpath', None) + return self.localpath == getattr(other, 'localpath', None) def _geturl(self): if getattr(self, '_url', None) is None: @@ -43,7 +43,7 @@ def svnurl(self): """ return current SvnPath for this WC-item. """ info = self.info() - return path.svnurl(info.url) + return path.svnurl(info.url) url = property(_geturl, None, None, "url of this WC item") @@ -62,15 +62,15 @@ string = svncommon.fixlocale() + " ".join(l) if DEBUG: print "execing", string - try: + try: out = py.process.cmdexec(string) - except py.process.cmdexec.Error, e: - if e.err.find('File Exists'): - raise py.error.EEXIST(self) + except py.process.cmdexec.Error, e: + if e.err.find('File Exists'): + raise py.error.EEXIST(self) raise return out - def checkout(self, url=None, rev = None): + def checkout(self, url=None, rev = None): """ checkout from url to local wcpath. """ if url is None: url = self.url @@ -100,9 +100,9 @@ return self def ensure(self, *args, **kwargs): - """ ensure that an args-joined path exists (by default as + """ ensure that an args-joined path exists (by default as a file). if you specify a keyword argument 'directory=True' - then the path is forced to be a directory path. + then the path is forced to be a directory path. """ try: p = self.join(*args) @@ -126,10 +126,10 @@ def add(self): self._svn('add') - def remove(self, rec=1, force=1): - """ remove a file or a directory tree. 'rec'ursive is - ignored and considered always true (because of - underlying svn semantics. + def remove(self, rec=1, force=1): + """ remove a file or a directory tree. 'rec'ursive is + ignored and considered always true (because of + underlying svn semantics. """ flags = [] if force: @@ -144,7 +144,7 @@ def status(self, updates=0, rec=0): """ return (collective) Status object for this file. """ - # http://svnbook.red-bean.com/book.html#svn-ch-3-sect-4.3.1 + # http://svnbook.red-bean.com/book.html#svn-ch-3-sect-4.3.1 # 2201 2192 jum test if rec: rec= '' @@ -182,7 +182,7 @@ elif c0 == 'I': wcpath = self.join(fn, abs=1) rootstatus.ignored.append(wcpath) - + continue #elif c0 in '~!' or c4 == 'S': @@ -199,7 +199,7 @@ update_rev = int(rest.split(':')[1].strip()) continue # keep trying - raise ValueError, "could not parse line %r" % line + raise ValueError, "could not parse line %r" % line else: rev, modrev, author, fn = m.groups() wcpath = self.join(fn, abs=1) @@ -276,7 +276,7 @@ lines = res.split('\n') lines = map(str.strip, lines[1:]) return svncommon.PropListDict(self, lines) - + def revert(self, rec=0): if rec: result = self._svn('revert -R') @@ -289,10 +289,10 @@ localpath = self.localpath.new(**kw) else: localpath = self.localpath - return self.__class__(localpath) - + return self.__class__(localpath) + def join(self, *args, **kwargs): - """ return a new Path (with the same revision) which is composed + """ return a new Path (with the same revision) which is composed of the self Path followed by 'args' path components. """ if not args: @@ -302,36 +302,36 @@ def info(self, usecache=1): """ return an Info structure with svn-provided information. """ - info = usecache and cache.info.get(self) + info = usecache and cache.info.get(self) if not info: try: output = self._svn('info') except py.process.cmdexec.Error, e: if e.err.find('Path is not a working copy directory') != -1: - raise py.error.ENOENT(self, e.err) + raise py.error.ENOENT(self, e.err) raise if output.find('Not a versioned resource') != -1: - raise py.error.ENOENT(self, output) + raise py.error.ENOENT(self, output) info = InfoSvnWCCommand(path.local(self.strpath), output) cache.info[self] = info self.rev = info.rev return info def listdir(self, fil=None, sort=None): - """ return a sequence of Paths. + """ return a sequence of Paths. listdir will return either a tuple or a list of paths - depending on implementation choices. + depending on implementation choices. """ if isinstance(fil, str): fil = common.fnmatch(fil) # XXX unify argument naming with LocalPath.listdir def notsvn(path): - return not path.get('basename') == '.svn' + return not path.get('basename') == '.svn' paths = [] for localpath in self.localpath.listdir(notsvn): - p = self.__class__(localpath) + p = self.__class__(localpath) paths.append(p) if fil or sort: @@ -352,7 +352,7 @@ class Checkers(path.local.Checkers): def __init__(self, path): self.svnwcpath = path - self.path = path.localpath + self.path = path.localpath def versioned(self): try: s = self.svnwcpath.status() @@ -394,9 +394,9 @@ return self.info().mtime def relto(self, rel): - """ Return a string which is the relative part of the Path to 'rel'. + """ Return a string which is the relative part of the Path to 'rel'. - If the Path is not relative to the given base, return an empty string. + If the Path is not relative to the given base, return an empty string. """ relpath = rel.strpath @@ -449,9 +449,9 @@ d = {} for line in output.split('\n'): - if not line.strip(): + if not line.strip(): continue - key, value = line.split(':', 1) + key, value = line.split(':', 1) key = key.lower().replace(' ', '') value = value.strip() d[key] = value @@ -467,7 +467,7 @@ self.last_author = d['lastchangedauthor'] self.mtime = parse_wcinfotime(d['lastchangeddate']) self.time = self.mtime * 1000000 - + def __eq__(self, other): return self.__dict__ == other.__dict__ @@ -482,8 +482,8 @@ parsedtime = time.strptime(timestr, "%Y-%m-%d %H:%M:%S") return time.mktime(parsedtime) -def make_recursive_propdict(wcroot, - output, +def make_recursive_propdict(wcroot, + output, rex = re.compile("Properties on '(.*)':")): """ Return a dictionary of path->PropListDict mappings. """ lines = filter(None, output.split('\n')) @@ -498,7 +498,7 @@ propnames = [] while lines and lines[0].startswith(' '): propname = lines.pop(0).strip() - propnames.append(propname) + propnames.append(propname) assert propnames, "must have found properties!" pdict[wcpath] = svncommon.PropListDict(wcpath, propnames) return pdict Modified: py/dist/py/path/svn/xsvnbinding.py ============================================================================== --- py/dist/py/path/svn/xsvnbinding.py (original) +++ py/dist/py/path/svn/xsvnbinding.py Sun Jan 9 16:49:34 2005 @@ -1,11 +1,11 @@ """ -module defining subversion path objects. +module defining subversion path objects. -SvnBindingPath implementation using svn-swig-py-bindings +SvnBindingPath implementation using svn-swig-py-bindings """ -# import svn swig-c-bindings +# import svn swig-c-bindings if 0: #import svn.client, svn.core, svn.util, atexit @@ -18,11 +18,11 @@ class SvnBindingPath(SvnPathBase): pool = svn.util.svn_pool_create(None) - + def _make_rev_t(self): rev = svn.core.svn_opt_revision_t() if self.rev is not None: - rev.kind = svn.core.svn_opt_revision_number + rev.kind = svn.core.svn_opt_revision_number rev.value.number = self.rev return rev @@ -58,7 +58,7 @@ rev = self._make_rev_t() cctx = self._make_cctx() table = svn.client.svn_client_proplist(url, rev, 0, cctx, self.pool) - + if not table: return {} content = table[0][1] Modified: py/dist/py/path/test/common.py ============================================================================== --- py/dist/py/path/test/common.py (original) +++ py/dist/py/path/test/common.py Sun Jan 9 16:49:34 2005 @@ -1,8 +1,8 @@ -from py.path import checker -import py +from py.path import checker +import py class CommonPathTests: - root = None # subclasses have to setup a 'root' attribute + root = None # subclasses have to setup a 'root' attribute def test_constructor_equality(self): p = self.root.__class__(self.root) @@ -28,14 +28,14 @@ def test_join_noargs(self): newpath = self.root.join() - assert self.root == newpath + assert self.root == newpath def test_add_something(self): p = self.root.join('sample') p = p + 'dir' assert p.check() - def test_parts(self): + def test_parts(self): newpath = self.root.join('sampledir', 'otherfile') par = newpath.parts()[-3:] assert par == [self.root, self.root.join('sampledir'), newpath] @@ -51,23 +51,23 @@ third = py.path.extpy('x', 'whatever') x = other.common(third) assert x is None - + #def test_parents_nonexisting_file(self): - # newpath = self.root / 'dirnoexist' / 'nonexisting file' + # newpath = self.root / 'dirnoexist' / 'nonexisting file' # par = list(newpath.parents()) # assert par[:2] == [self.root / 'dirnoexist', self.root] def test_basename_checks(self): newpath = self.root.join('sampledir') assert newpath.check(basename='sampledir') - assert newpath.check(notbasename='xyz') + assert newpath.check(notbasename='xyz') assert newpath.basename == 'sampledir' def test_basename(self): newpath = self.root.join('sampledir') assert newpath.check(basename='sampledir') - assert newpath.basename, 'sampledir' + assert newpath.basename, 'sampledir' def test_dirpath(self): newpath = self.root.join('sampledir') @@ -75,11 +75,11 @@ def test_dirpath_with_args(self): newpath = self.root.join('sampledir') - assert newpath.dirpath('x') == self.root.join('x') + assert newpath.dirpath('x') == self.root.join('x') def test_newbasename(self): newpath = self.root.join('samplefile') - newbase = newpath.new(basename="samplefile2") + newbase = newpath.new(basename="samplefile2") assert newbase.basename == "samplefile2" assert newbase.dirpath() == newpath.dirpath() @@ -94,7 +94,7 @@ def test_dir(self): #print repr(self.root.join("sampledir")) assert self.root.join("sampledir").check(dir=1) - assert self.root.join('samplefile').check(notdir=1) + assert self.root.join('samplefile').check(notdir=1) assert not self.root.join("samplefile").check(dir=1) def test_filter_dir(self): @@ -107,7 +107,7 @@ #def test_fnmatch_dir(self): - # pattern = self.root.sep.join(['s*file']) + # pattern = self.root.sep.join(['s*file']) # sfile = self.root.join("samplefile") # assert sfile.check(fnmatch=pattern) @@ -115,8 +115,8 @@ l=self.root.join("sampledir", "otherfile") assert l.relto(self.root) == l.sep.join(["sampledir", "otherfile"]) assert l.check(relto=self.root) - assert self.root.check(notrelto=l) - assert not self.root.check(relto=l) + assert self.root.check(notrelto=l) + assert not self.root.check(relto=l) def test_relto_not_relative(self): l1=self.root.join("sampledir") @@ -127,7 +127,7 @@ l = self.root.listdir() assert self.root.join('sampledir') in l assert self.root.join('samplefile') in l - py.test.raises(py.error.ENOTDIR, + py.test.raises(py.error.ENOTDIR, "self.root.join('samplefile').listdir()") def test_listdir_fnmatchstring(self): @@ -181,33 +181,33 @@ def test_endswith(self): assert self.root.check(notendswith='.py') - x = self.root.join('samplefile') - assert x.check(endswith='file') + x = self.root.join('samplefile') + assert x.check(endswith='file') def test_cmp(self): path1 = self.root.join('samplefile') - path2 = self.root.join('samplefile2') - assert cmp(path1, path2) == cmp('samplefile', 'samplefile2') + path2 = self.root.join('samplefile2') + assert cmp(path1, path2) == cmp('samplefile', 'samplefile2') assert cmp(path1, path1) == 0 def test_contains_path(self): path1 = self.root.join('samplefile') assert path1 in self.root - assert not self.root.join('not existing') in self.root + assert not self.root.join('not existing') in self.root def test_contains_path_with_basename(self): assert 'samplefile' in self.root assert 'not_existing' not in self.root def featuretest_check_docstring(self): - here = self.root.__class__ - assert here.check.__doc__ - doc = here.check.__doc__ + here = self.root.__class__ + assert here.check.__doc__ + doc = here.check.__doc__ for name in dir(local.Checkers): if name[0] != '_': - assert name in doc + assert name in doc def test_simple_read(self): x = self.root.join('samplefile').read() assert x == 'samplefile\n' - + Modified: py/dist/py/path/test/fscommon.py ============================================================================== --- py/dist/py/path/test/fscommon.py (original) +++ py/dist/py/path/test/fscommon.py Sun Jan 9 16:49:34 2005 @@ -1,17 +1,17 @@ -import py -from py.__impl__.path.test import common +import py +from py.__impl__.path.test import common checker = py.path.checker def setuptestfs(path): if path.join('samplefile').check(): - return + return #print "setting up test fs for", repr(path) samplefile = path.ensure('samplefile') samplefile.write('samplefile\n') execfile = path.ensure('execfile') - execfile.write('x=42') + execfile.write('x=42') d = {1:2, 'hello': 'world', 'answer': 42} path.ensure('samplepickle').dumpobj(d) @@ -38,7 +38,7 @@ ''') class CommonFSTests(common.CommonPathTests): - root = None # subclasses have to provide a current 'root' attribute + root = None # subclasses have to provide a current 'root' attribute def test_join_div_operator(self): newpath = self.root / '/sampledir' / '/test//' @@ -47,13 +47,13 @@ def test_ext(self): newpath = self.root.join('sampledir.ext') - assert newpath.ext == '.ext' + assert newpath.ext == '.ext' newpath = self.root.join('sampledir') - assert not newpath.ext + assert not newpath.ext def test_purebasename(self): newpath = self.root.join('samplefile.py') - assert newpath.purebasename == 'samplefile' + assert newpath.purebasename == 'samplefile' def test_multiple_parts(self): newpath = self.root.join('samplefile.py') @@ -66,9 +66,9 @@ def test_dotted_name_ext(self): newpath = self.root.join('a.b.c') - ext = newpath.ext + ext = newpath.ext assert ext == '.c' - assert newpath.ext == '.c' + assert newpath.ext == '.c' def test_newext(self): newpath = self.root.join('samplefile.py') @@ -103,7 +103,7 @@ assert self.root.join("sampledir.nothere").check(notexists=1) assert not self.root.join("sampledir.nothere").check(notfile=0) - # pattern = self.root.sep.join(['s*file']) + # pattern = self.root.sep.join(['s*file']) # sfile = self.root.join("samplefile") # assert sfile.check(fnmatch=pattern) @@ -143,57 +143,57 @@ assert chk(self.root.join('somepickle')) def test_copy_file(self): - otherdir = self.root.join('otherdir') + otherdir = self.root.join('otherdir') initpy = otherdir.join('__init__.py') - copied = otherdir.join('copied') + copied = otherdir.join('copied') initpy.copy(copied) try: assert copied.check() s1 = initpy.read() s2 = copied.read() - assert s1 == s2 + assert s1 == s2 finally: if copied.check(): copied.remove() def test_copy_dir(self): - otherdir = self.root.join('otherdir') - copied = self.root.join('newdir') + otherdir = self.root.join('otherdir') + copied = self.root.join('newdir') try: otherdir.copy(copied) assert copied.check(dir=1) assert copied.join('__init__.py').check(file=1) s1 = otherdir.join('__init__.py').read() s2 = copied.join('__init__.py').read() - assert s1 == s2 + assert s1 == s2 finally: if copied.check(dir=1): copied.remove(rec=1) def test_remove_file(self): - d = self.root.ensure('todeleted') + d = self.root.ensure('todeleted') assert d.check() - d.remove() - assert not d.check() + d.remove() + assert not d.check() def test_remove_dir_recursive_by_default(self): - d = self.root.ensure('to', 'be', 'deleted') + d = self.root.ensure('to', 'be', 'deleted') assert d.check() p = self.root.join('to') - p.remove() - assert not p.check() + p.remove() + assert not p.check() def test_mkdir_and_remove(self): - tmpdir = self.root - py.test.raises(py.error.EEXIST, tmpdir.mkdir, 'sampledir') + tmpdir = self.root + py.test.raises(py.error.EEXIST, tmpdir.mkdir, 'sampledir') new = tmpdir.join('mktest1') new.mkdir() assert new.check(dir=1) - new.remove() + new.remove() new = tmpdir.mkdir('mktest2') assert new.check(dir=1) - new.remove() + new.remove() assert tmpdir.join('mktest2') == new def test_move_file(self): @@ -208,13 +208,13 @@ source.ensure('moved', 'somefile').write("42") dest = source.new(basename='moveddir') source.move(dest) - assert dest.check(dir=1) + assert dest.check(dir=1) assert dest.join('moved', 'somefile').read() == '42' assert not source.check() def test_getpymodule(self): obj = self.root.join('execfile').getpymodule() - assert obj.x == 42 + assert obj.x == 42 def test_not_has_resolve(self): # because this would mean confusion with respect to Modified: py/dist/py/path/test/test_api.py ============================================================================== --- py/dist/py/path/test/test_api.py (original) +++ py/dist/py/path/test/test_api.py Sun Jan 9 16:49:34 2005 @@ -1,5 +1,5 @@ from py import path, test -from py.__impl__.path.svn.testing.test_wccommand import getrepowc +from py.__impl__.path.svn.testing.test_wccommand import getrepowc class TestAPI: def __init__(self): @@ -9,7 +9,7 @@ r = repr(p) from py.path import local,svnurl, svnwc, extpy y = eval(r) - assert y == p + assert y == p def test_defaultlocal(self): p = path.local() @@ -38,12 +38,12 @@ self.repr_eval_test(p) def test_svnwc(self): - p = path.svnwc(self.root) + p = path.svnwc(self.root) assert p.check(svnwc=1) self.repr_eval_test(p) #def test_fspy(self): - # p = path.py('smtplib.SMTP') + # p = path.py('smtplib.SMTP') # self.repr_eval_test(p) Modified: py/dist/py/process/cmdexec.py ============================================================================== --- py/dist/py/process/cmdexec.py (original) +++ py/dist/py/process/cmdexec.py Sun Jan 9 16:49:34 2005 @@ -1,7 +1,7 @@ """ module defining basic hook for executing commands -in a - as much as possible - platform independent way. +in a - as much as possible - platform independent way. Current list: @@ -31,8 +31,8 @@ stdin.close() # XXX sometimes we get a blocked r.read() call (see below) - # although select told us there is something to read. - # only the next three lines appear to prevent + # although select told us there is something to read. + # only the next three lines appear to prevent # the read call from blocking infinitely. import fcntl fcntl.fcntl(stdout, fcntl.F_SETFL, os.O_NONBLOCK) @@ -62,7 +62,7 @@ status = os.WTERMSIG(systemstatus) + 128 else: status = os.WEXITSTATUS(systemstatus) - raise ExecutionFailed(status, systemstatus, cmd, + raise ExecutionFailed(status, systemstatus, cmd, ''.join(out), ''.join(err)) return "".join(out) @@ -98,11 +98,11 @@ self.cmd = cmd self.err = err self.out = out - + def __str__(self): return "ExecutionFailed: %d %s\n%s" %(self.status, self.cmd, self.err) # -# choose correct platform-version +# choose correct platform-version # if sys.platform == 'win32': cmdexec = win32_exec_cmd Modified: py/dist/py/process/testing/__init__.py ============================================================================== --- py/dist/py/process/testing/__init__.py (original) +++ py/dist/py/process/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# Modified: py/dist/py/test/cmdline.py ============================================================================== --- py/dist/py/test/cmdline.py (original) +++ py/dist/py/test/cmdline.py Sun Jan 9 16:49:34 2005 @@ -1,13 +1,13 @@ from __future__ import generators -import py +import py import sys -from py.__impl__.test import run +from py.__impl__.test import run # # main entry point # -def _old(argv): +def _old(argv): if argv is None: argv = py.std.sys.argv frame = py.std.sys._getframe(1) @@ -17,19 +17,19 @@ import __main__ return [py.test.collect.Module(py.std.sys.argv[0])] -def main(): +def main(): args = py.std.sys.argv[1:] - py.test.config.readconfiguration(*run.getanchors(args)) + py.test.config.readconfiguration(*run.getanchors(args)) filenames = py.test.config.parseargs(args) - if not filenames: + if not filenames: filenames.append(str(py.path.local())) - option = py.test.config.option + option = py.test.config.option try: - if option.session or option.executable: - run.session(args, filenames) + if option.session or option.executable: + run.session(args, filenames) else: - run.inprocess(args, filenames) + run.inprocess(args, filenames) except KeyboardInterrupt: print print "Keybordinterrupt" Modified: py/dist/py/test/collect.py ============================================================================== --- py/dist/py/test/collect.py (original) +++ py/dist/py/test/collect.py Sun Jan 9 16:49:34 2005 @@ -1,43 +1,43 @@ from __future__ import generators import sys, inspect, types -from py import path, test +from py import path, test import py -def getfscollector(fspath): +def getfscollector(fspath): if fspath.check(file=1): col = py.test.config.getconfigvalue(fspath, 'Module') elif fspath.check(dir=1): col = py.test.config.getconfigvalue(fspath, 'Directory') else: - raise py.error.ENOENT(fspath) - return col(fspath) + raise py.error.ENOENT(fspath) + return col(fspath) + +def configproperty(name): + def fget(self): + return py.test.config.getconfigvalue(self.fspath, name) + return property(fget) -def configproperty(name): - def fget(self): - return py.test.config.getconfigvalue(self.fspath, name) - return property(fget) - class Error(object): """ represents a non-fatal exception while collecting. """ def __init__(self, excinfo): self.excinfo = py.code.ExceptionInfo(excinfo) def __repr__(self): - tb = list(self.excinfo)[-1] - return '' % (tb.frame.code.path, - tb.lineno+1) + tb = list(self.excinfo)[-1] + return '' % (tb.frame.code.path, + tb.lineno+1) class Collector(object): """ instances are *restartable iterators*. They will yield Units or - Collector instances during iteration. + Collector instances during iteration. """ - Item = test.Item - GenItem = test.GenItem + Item = test.Item + GenItem = test.GenItem Error = Error - Module = configproperty('Module') - Directory = configproperty('Directory') - Class = configproperty('Class') + Module = configproperty('Module') + Directory = configproperty('Directory') + Class = configproperty('Class') def iterunits(self): """ yield all units of the Collector instance. """ @@ -55,30 +55,30 @@ return Error(excinfo) # ---------------------------------------------- -# Collectors starting from a file system path +# Collectors starting from a file system path # ---------------------------------------------- class FSCollector(Collector): def __init__(self, fspath): self.fspath = py.path.local(fspath) def __repr__(self): - return '%s(%r)' %(self.__class__.__name__, + return '%s(%r)' %(self.__class__.__name__, self.fspath.relto(py.path.local())) class Directory(FSCollector): def fil(self, fspath): - return (fspath.check(file=1, fnmatch='test_*.py') or + return (fspath.check(file=1, fnmatch='test_*.py') or fspath.check(file=1, fnmatch='*_test.py')) rec = py.path.checker(dir=1, dotfile=0, link=0) def __iter__(self): try: - for fspath in self.fspath.listdir(sort=True): + for fspath in self.fspath.listdir(sort=True): if self.rec(fspath): # hack to get the correct Directory collector class yield self.Directory(fspath).Directory(fspath) elif self.fil(fspath): - yield self.Module(fspath) + yield self.Module(fspath) except: yield self._except() @@ -89,52 +89,52 @@ class PyCollector(Collector): def __init__(self, extpy): if not hasattr(extpy, 'resolve'): - extpy = py.path.extpy(extpy) - self.extpy = extpy - self.yielders = [getattr(self, x) - for x in dir(self.__class__) + extpy = py.path.extpy(extpy) + self.extpy = extpy + self.yielders = [getattr(self, x) + for x in dir(self.__class__) if x.startswith('collect_')] - fspath = property(lambda self: self.extpy.root) + fspath = property(lambda self: self.extpy.root) def __repr__(self): return '%s(%r)' %(self.__class__.__name__, str(self.extpy)) def __iter__(self): try: - # we want to sort according to lineno, so here goes - # the generator lazyness + # we want to sort according to lineno, so here goes + # the generator lazyness l = [] for extpy in self.extpy.listdir(): for meth in self.yielders: #print "looking at", extpy for x in meth(extpy): - #print "found", x - sortvalue = self.getsortvalue(x) - l.append((sortvalue, x)) - l.sort() + #print "found", x + sortvalue = self.getsortvalue(x) + l.append((sortvalue, x)) + l.sort() for x,y in l: yield y except: yield self._except() - def getsortvalue(self, obj): - """ sorting function to bring test methods in - the same order as int he file. - """ - if isinstance(obj, self.Item): - obj = obj.extpy.resolve() + def getsortvalue(self, obj): + """ sorting function to bring test methods in + the same order as int he file. + """ + if isinstance(obj, self.Item): + obj = obj.extpy.resolve() elif isinstance(obj, PyCollector): for x in obj: - return self.getsortvalue(x) + return self.getsortvalue(x) if hasattr(obj, 'im_func'): - obj = obj.im_func + obj = obj.im_func if hasattr(obj, 'func_code'): - obj = obj.func_code - # enough is enough - return (getattr(obj, 'co_filename', None), + obj = obj.func_code + # enough is enough + return (getattr(obj, 'co_filename', None), getattr(obj, 'co_firstlineno', sys.maxint)) - + class Module(PyCollector): def __iter__(self): try: @@ -142,18 +142,18 @@ if iter.check(exists=True): iter = iter.resolve()(self.extpy) else: - iter = super(Module, self).__iter__() - for x in iter: - yield x + iter = super(Module, self).__iter__() + for x in iter: + yield x except: yield self._except() def collect_function(self, extpy): if extpy.check(func=1, basestarts='test_'): - if extpy.check(genfunc=1): - yield Generator(extpy) - else: - #if self.extpy.samefile(extpy): not nfs/different mountpoint safe ? + if extpy.check(genfunc=1): + yield Generator(extpy) + else: + #if self.extpy.samefile(extpy): not nfs/different mountpoint safe ? yield self.Item(extpy) def collect_class(self, extpy): @@ -166,41 +166,41 @@ class Class(PyCollector): def collect_method(self, extpy): # note that we want to allow inheritance and thus - # we don't check for "samemodule"-ness of test + # we don't check for "samemodule"-ness of test # methods like in the Module Collector if extpy.check(basestarts='test_', func=1): - if extpy.check(genfunc=1): - yield Generator(extpy) - else: + if extpy.check(genfunc=1): + yield Generator(extpy) + else: func = extpy.resolve() try: - yield getattr(func.im_class, 'Item')(extpy) - except AttributeError: - yield self.Item(extpy) - -class Generator(PyCollector): - def builditem(self, obj): - if isinstance(obj, (tuple, list)): + yield getattr(func.im_class, 'Item')(extpy) + except AttributeError: + yield self.Item(extpy) + +class Generator(PyCollector): + def builditem(self, obj): + if isinstance(obj, (tuple, list)): call = obj[0] args = obj[1:] else: - call = obj + call = obj args = () - #if hasattr(call, 'gi_running'): - # return ... Generator(py.path.obj(call), *args) - return self.GenItem(self.extpy, call, *args) + #if hasattr(call, 'gi_running'): + # return ... Generator(py.path.obj(call), *args) + return self.GenItem(self.extpy, call, *args) def __iter__(self): try: - # XXX we need to setup/teardown state here - #sm = self.GenItem.setupmanager - #sm.setup_path(self.extpy) - #gen, teardown = sm.setup_method(self.extpy) - #assert not teardown, "%r not processoable in Generator-Collector (XXX)" + # XXX we need to setup/teardown state here + #sm = self.GenItem.setupmanager + #sm.setup_path(self.extpy) + #gen, teardown = sm.setup_method(self.extpy) + #assert not teardown, "%r not processoable in Generator-Collector (XXX)" gen = self.extpy.resolve() - if hasattr(gen, 'im_self') and not gen.im_self: - gen = gen.__get__(gen.im_class(), gen.im_class) - for call in gen(): - yield self.builditem(call) + if hasattr(gen, 'im_self') and not gen.im_self: + gen = gen.__get__(gen.im_class(), gen.im_class) + for call in gen(): + yield self.builditem(call) except: yield self._except() Modified: py/dist/py/test/compat.py ============================================================================== --- py/dist/py/test/compat.py (original) +++ py/dist/py/test/compat.py Sun Jan 9 16:49:34 2005 @@ -3,42 +3,42 @@ class TestCaseUnit(py.test.Item): """ compatibility Unit executor for TestCase methods - honouring setUp and tearDown semantics. + honouring setUp and tearDown semantics. """ def execute(self, driver): - unboundmethod = self.extpy.resolve() + unboundmethod = self.extpy.resolve() cls = unboundmethod.im_class instance = cls() instance.setUp() try: - unboundmethod(instance) + unboundmethod(instance) finally: instance.tearDown() return py.test.Item.Passed() class TestCase: """compatibility class of unittest's TestCase. """ - Item = TestCaseUnit + Item = TestCaseUnit - def setUp(self): + def setUp(self): pass - def tearDown(self): + def tearDown(self): pass def fail(self, msg=None): """ fail immediate with given message. """ - raise py.test.Item.Failed(msg=msg) + raise py.test.Item.Failed(msg=msg) def assertRaises(self, excclass, func, *args, **kwargs): py.test.raises(excclass, func, *args, **kwargs) failUnlessRaises = assertRaises - # dynamically construct (redundant) methods + # dynamically construct (redundant) methods aliasmap = [ ('x', 'not x', 'assert_, failUnless'), ('x', 'x', 'failIf'), - ('x,y', 'x!=y', 'failUnlessEqual,assertEqual, assertEquals'), + ('x,y', 'x!=y', 'failUnlessEqual,assertEqual, assertEquals'), ('x,y', 'x==y', 'failIfEqual,assertNotEqual, assertNotEquals'), ] items = [] @@ -53,6 +53,6 @@ """ % locals() ) source = "".join(items) - exec py.code.Source(source).compile() + exec py.code.Source(source).compile() __all__ = ['TestCase'] Modified: py/dist/py/test/config.py ============================================================================== --- py/dist/py/test/config.py (original) +++ py/dist/py/test/config.py Sun Jan 9 16:49:34 2005 @@ -1,16 +1,16 @@ from __future__ import generators import py -from py.__impl__.test.tool import optparse +from py.__impl__.test.tool import optparse defaultconfig = py.magic.autopath().dirpath('defaultconfig.py') -defaultconfig = py.path.extpy(defaultconfig) +defaultconfig = py.path.extpy(defaultconfig) dummy = object() # # config file handling (utest.conf) # -configbasename = 'conftest.py' +configbasename = 'conftest.py' class Config: def __init__(self): @@ -30,96 +30,96 @@ """ read configuration files left-to-right for the given anchor file. """ self.configpaths = [] d = {} - for anchor in anchors: - for p in anchor.parts(): + for anchor in anchors: + for p in anchor.parts(): x = p.join(configbasename) - if x.check(file=1): - extpy = py.path.extpy(x) - extpy.resolve() # trigger loading it - if extpy not in d: - self.configpaths.append(extpy) + if x.check(file=1): + extpy = py.path.extpy(x) + extpy.resolve() # trigger loading it + if extpy not in d: + self.configpaths.append(extpy) d[extpy] = True self.configpaths.sort(lambda x,y: cmp(len(str(x)), len(str(y)))) self.configpaths.append(defaultconfig) - def getconfigvalue(self, path, name): - for p in path.parts(reverse=True): - x = p.join(configbasename) - if x.check(file=1): - extpy = py.path.extpy(x, name) - if extpy.check(): - return extpy.resolve() - extpy = defaultconfig.join(name) - if extpy.check(): + def getconfigvalue(self, path, name): + for p in path.parts(reverse=True): + x = p.join(configbasename) + if x.check(file=1): + extpy = py.path.extpy(x, name) + if extpy.check(): + return extpy.resolve() + extpy = defaultconfig.join(name) + if extpy.check(): return extpy.resolve() - raise ValueError("could not find config value %r" % name) - + raise ValueError("could not find config value %r" % name) + def getfirst(self, param, default=dummy): """ return first found parameter. """ - for config in self.configpaths: + for config in self.configpaths: x = config.join(param) if x.check(): - return x.resolve() + return x.resolve() if default is dummy: raise AttributeError, param return default #if default is not dummy: # return getattr(self, param, default) #return getattr(self, param) - - def parseargs(self, args): - # first a small fight with optparse to merge the - # pytest.py file options correctly + + def parseargs(self, args): + # first a small fight with optparse to merge the + # pytest.py file options correctly parser = optparse.OptionParser() - for config in self.configpaths: - meth = config.join('options') - if meth.check(): - groupname, groupoptions = meth.resolve() - optgroup = optparse.OptionGroup(parser, groupname) + for config in self.configpaths: + meth = config.join('options') + if meth.check(): + groupname, groupoptions = meth.resolve() + optgroup = optparse.OptionGroup(parser, groupname) optgroup.add_options(groupoptions) parser.add_option_group(optgroup) # extract and remove defaults from options for option in flattenoptions(parser): if option.dest: - value = self.getfirst(option.dest, option.default) + value = self.getfirst(option.dest, option.default) #print "setting %r to %r" %(option.dest, value) - setattr(self.option, option.dest, value) + setattr(self.option, option.dest, value) option.default = 'NODEFAULT' - - # parse cmdline args - cmdlineoption, remaining = parser.parse_args(args, self.option) - self.fixoptions() - # override previously computed defaults + # parse cmdline args + cmdlineoption, remaining = parser.parse_args(args, self.option) + + self.fixoptions() + # override previously computed defaults #for name in cmdlineoption.__dict__: # if not name.startswith('_'): # print "resetting %r to %r" %(name, cmdlineoption.__dict__[name]) # setattr(self.option, name, cmdlineoption.__dict__[name]) - return remaining + return remaining - def fixoptions(self): - if self.option.session and self.option.usepdb: - raise ValueError, "--session together with --pdb not supported yet." - if self.option.executable and self.option.usepdb: - raise ValueError, "--exec together with --pdb not supported yet." + def fixoptions(self): + if self.option.session and self.option.usepdb: + raise ValueError, "--session together with --pdb not supported yet." + if self.option.executable and self.option.usepdb: + raise ValueError, "--exec together with --pdb not supported yet." - # setting a correct executable - if self.option.executable is not None: + # setting a correct executable + if self.option.executable is not None: exe = py.path.local(py.std.os.path.expanduser(self.option.executable)) - if not exe.check(): - exe = py.path.local.sysfind(self.option.executable) - assert exe.check() - self.option.executable = exe + if not exe.check(): + exe = py.path.local.sysfind(self.option.executable) + assert exe.check() + self.option.executable = exe config = Config() -# helpers +# helpers def flattenoptions(parser): for group in parser.option_groups: - for y in group.option_list: + for y in group.option_list: yield y for x in parser.option_list: - yield x + yield x Modified: py/dist/py/test/defaultconfig.py ============================================================================== --- py/dist/py/test/defaultconfig.py (original) +++ py/dist/py/test/defaultconfig.py Sun Jan 9 16:49:34 2005 @@ -1,8 +1,8 @@ -import py +import py Option = py.test.Option -Module = py.test.collect.Module -Directory = py.test.collect.Directory +Module = py.test.collect.Module +Directory = py.test.collect.Directory Class = py.test.collect.Class def getreporter(): @@ -11,34 +11,34 @@ additionalinfo = None options = ('py.test standard options', [ - Option('-v', '--verbose', + Option('-v', '--verbose', action="count", dest="verbose", default=0, help="increase verbosity"), - Option('-x', '--exitfirst', - action="store_true", dest="exitfirstproblem", default=False, + Option('-x', '--exitfirst', + action="store_true", dest="exitfirstproblem", default=False, help="exit instantly on first error or failed test."), - Option('-S', '--nocapture', + Option('-S', '--nocapture', action="store_true", dest="nocapture", default=False, help="disable catching of sys.stdout/stderr output."), - Option('-l', '--showlocals', - action="store_true", dest="showlocals", default=False, + Option('-l', '--showlocals', + action="store_true", dest="showlocals", default=False, help="show locals in tracebacks (disabled by default)"), - Option('', '--exec', + Option('', '--exec', action="store", dest="executable", default=None, help="python executable to run the tests with. "), - Option('', '--session', + Option('', '--session', action="store_true", dest="session", default=False, help="run a test session/rerun only failing tests. "), - Option('', '--fulltrace', - action="store_true", dest="fulltrace", default=False, + Option('', '--fulltrace', + action="store_true", dest="fulltrace", default=False, help="Don't try to cut any tracebacks (default is to cut)"), - Option('', '--nomagic', - action="store_true", dest="nomagic", default=False, + Option('', '--nomagic', + action="store_true", dest="nomagic", default=False, help="don't invoke magic to e.g. beautify failing/error statements."), Option('', '--pdb', action="store_true", dest="usepdb", default=False, help="Start pdb (the Python debugger) on errors."), - Option('', '--collectonly', + Option('', '--collectonly', action="store_true", dest="collectonly", default=False, help="only collect tests, don't execute them. "), ]) Modified: py/dist/py/test/drive.py ============================================================================== --- py/dist/py/test/drive.py (original) +++ py/dist/py/test/drive.py Sun Jan 9 16:49:34 2005 @@ -1,37 +1,37 @@ from __future__ import generators -import py -collect = py.test.collect +import py +collect = py.test.collect -class Exit(Exception): +class Exit(Exception): """ for immediate program exits without tracebacks and reporter/summary. """ def __init__(self, item=None): self.item = None - Exception.__init__(self) + Exception.__init__(self) def exit(*args): - """ exit immediately without tracebacks and reporter/summary. """ - raise Exit(*args) + """ exit immediately without tracebacks and reporter/summary. """ + raise Exit(*args) class Driver: - """ - A Driver gets test Items from Collectors, # executes the - Items and sends the Outcome to the Reporter. - """ + """ + A Driver gets test Items from Collectors, # executes the + Items and sends the Outcome to the Reporter. + """ option = py.test.config.option Exit = Exit - def __init__(self, channel): + def __init__(self, channel): self.reporter = py.test.config.getfirst('getreporter') () - self._channel = channel + self._channel = channel self._failed = [] def setup(self): - """ setup any neccessary resources. """ + """ setup any neccessary resources. """ def teardown(self): - """ teardown any resources we know about. """ - # XXX a cleaner way to teardown setupmanagers? - py.test.Item.teardownall() + """ teardown any resources we know about. """ + # XXX a cleaner way to teardown setupmanagers? + py.test.Item.teardownall() def run(self, collectors): """ main loop for running tests. """ @@ -39,17 +39,17 @@ try: try: self.reporter.start() - for x in collectors: - self.run_collector_or_item(x) + for x in collectors: + self.run_collector_or_item(x) finally: self.teardown() except self.Exit, ex: pass - self.reporter.end() + self.reporter.end() l = [] - for x in self._failed: + for x in self._failed: l.append((str(x.extpy.root), str(x.extpy.modpath))) - return l + return l def run_collector_or_item(self, obj): """ run (possibly many) testitems and/or collectors. """ @@ -59,12 +59,12 @@ self.runitem(obj) elif isinstance(obj, py.test.collect.Collector): self.runcollector(obj) - elif isinstance(obj, py.test.collect.Collector.Error): + elif isinstance(obj, py.test.collect.Collector.Error): try: self.reporter.report_collect_error(obj) except (KeyboardInterrupt, SystemExit): - raise - except: + raise + except: print "*" * 80 print "Reporter Error" print "*" * 80 @@ -72,7 +72,7 @@ traceback.print_exc() raise SystemExit, 1 if self.option.exitfirstproblem: - raise self.Exit() + raise self.Exit() else: raise TypeError("%r is not a Item or Collector instance" % obj) @@ -86,13 +86,13 @@ close() def runitem(self, item): - if not self.option.collectonly: + if not self.option.collectonly: self.reporter.startitem(item) try: item.run(self) except item.Outcome, res: if not hasattr(res, 'excinfo'): - res.excinfo = py.code.ExceptionInfo() + res.excinfo = py.code.ExceptionInfo() except (KeyboardInterrupt, SystemExit): raise except: @@ -101,8 +101,8 @@ res = item.Passed() res.item = item self.reporter.enditem(res) - if isinstance(res, (item.Failed,)): - self._failed.append(item) + if isinstance(res, (item.Failed,)): + self._failed.append(item) if py.test.config.option.exitfirstproblem: - raise self.Exit(res.item) + raise self.Exit(res.item) Modified: py/dist/py/test/item.py ============================================================================== --- py/dist/py/test/item.py (original) +++ py/dist/py/test/item.py Sun Jan 9 16:49:34 2005 @@ -1,168 +1,168 @@ -import py +import py from inspect import isclass, ismodule -class SetupState: - """ shared state for setting up/tearing down tests. """ - def __init__(self): +class SetupState: + """ shared state for setting up/tearing down tests. """ + def __init__(self): self._setupstack = [] - self._instance = None + self._instance = None -class SetupItem(object): - state = SetupState() +class SetupItem(object): + state = SetupState() - def teardownall(cls): - while cls.state._setupstack: - item, extpy, obj = cls.state._setupstack.pop() - item._dispatch_teardown(obj) - teardownall = classmethod(teardownall) + def teardownall(cls): + while cls.state._setupstack: + item, extpy, obj = cls.state._setupstack.pop() + item._dispatch_teardown(obj) + teardownall = classmethod(teardownall) def _dispatch_teardown(self, obj): - if ismodule(obj): - self.teardown_module(obj) - elif isclass(obj): - self.teardown_class(obj) + if ismodule(obj): + self.teardown_module(obj) + elif isclass(obj): + self.teardown_class(obj) def _dispatch_setup(self, obj): - if ismodule(obj): - self.setup_module(obj) - elif isclass(obj): - self.setup_class(obj) - else: - return False + if ismodule(obj): + self.setup_module(obj) + elif isclass(obj): + self.setup_class(obj) + else: + return False return True - + def setup_path(self, extpy): - """ setup objects along the path to the test-method - (pointed to by extpy). Tear down any previously - setup objects which are not directly needed. - """ - # the setupstack contains (item, extpy, obj) tuples of already + """ setup objects along the path to the test-method + (pointed to by extpy). Tear down any previously + setup objects which are not directly needed. + """ + # the setupstack contains (item, extpy, obj) tuples of already # setup objects. Strict ordering is maintained, i.e. each extpy in - # the stack is "relto" its previous extpy. - stack = self.state._setupstack - while stack and not extpy.relto(stack[-1][1]): + # the stack is "relto" its previous extpy. + stack = self.state._setupstack + while stack and not extpy.relto(stack[-1][1]): item, addr, obj = stack.pop() - item._dispatch_teardown(obj) + item._dispatch_teardown(obj) rest = extpy.parts()[len(stack):-1] - for x in rest: - obj = x.resolve() - if self._dispatch_setup(obj): - stack.append((self, x, obj)) - - def setup_module(self, mod): - if hasattr(mod, 'setup_module'): - mod.setup_module(mod) - - def teardown_module(self, mod): - if hasattr(mod, 'teardown_module'): - mod.teardown_module(mod) - - def setup_class(self, cls): - if hasattr(cls, 'setup_class'): - cls.setup_class.im_func(cls) - - def teardown_class(self, cls): - if hasattr(cls, 'teardown_class'): - cls.teardown_class.im_func(cls) - - def setup_method(self, method): - if hasattr(getattr(method, 'im_self', None), 'setup_method'): - method.im_self.setup_method(method) - - def teardown_method(self, method): - if hasattr(getattr(method, 'im_self', None), 'teardown_method'): - method.im_self.teardown_method(method) - - def setup_function(self, function): - x = function.func_globals.get('setup_function', None) - if x is not None: - x(function) - - def teardown_function(self, function): - x = function.func_globals.get('teardown_function', None) - if x is not None: - x(function) + for x in rest: + obj = x.resolve() + if self._dispatch_setup(obj): + stack.append((self, x, obj)) + + def setup_module(self, mod): + if hasattr(mod, 'setup_module'): + mod.setup_module(mod) + + def teardown_module(self, mod): + if hasattr(mod, 'teardown_module'): + mod.teardown_module(mod) + + def setup_class(self, cls): + if hasattr(cls, 'setup_class'): + cls.setup_class.im_func(cls) + + def teardown_class(self, cls): + if hasattr(cls, 'teardown_class'): + cls.teardown_class.im_func(cls) + + def setup_method(self, method): + if hasattr(getattr(method, 'im_self', None), 'setup_method'): + method.im_self.setup_method(method) + + def teardown_method(self, method): + if hasattr(getattr(method, 'im_self', None), 'teardown_method'): + method.im_self.teardown_method(method) + + def setup_function(self, function): + x = function.func_globals.get('setup_function', None) + if x is not None: + x(function) + + def teardown_function(self, function): + x = function.func_globals.get('teardown_function', None) + if x is not None: + x(function) - def make_callable(self, method): + def make_callable(self, method): assert callable(method) if not hasattr(method, 'im_class'): - return method - if self.state._instance.__class__ != method.im_class: - self.state._instance = method.im_class() - return method.__get__(self.state._instance, method.im_class) + return method + if self.state._instance.__class__ != method.im_class: + self.state._instance = method.im_class() + return method.__get__(self.state._instance, method.im_class) class Item(SetupItem): - """ an Item is responsible for locating and executing - a Python callable test object. + """ an Item is responsible for locating and executing + a Python callable test object. """ - def __init__(self, extpy, *args): + def __init__(self, extpy, *args): self.extpy = extpy - self.name = extpy.basename + self.name = extpy.basename self.args = args def run(self, driver): - self.setup_path(self.extpy) - method = self.make_callable(self.extpy.resolve()) - if hasattr(method, 'im_self'): - self.setup_method(method) - else: + self.setup_path(self.extpy) + method = self.make_callable(self.extpy.resolve()) + if hasattr(method, 'im_self'): + self.setup_method(method) + else: self.setup_function(method) try: self.execute(method, *self.args) - finally: - self.teardown_method(method) + finally: + self.teardown_method(method) + + def execute(self, target, *args): + """ default implementation for calling a test target is to + simply call it. + """ + target(*args) - def execute(self, target, *args): - """ default implementation for calling a test target is to - simply call it. + def reprcall(self): + """ return a string representing a call to the underlying + test function. """ - target(*args) + return "%s%r" % (self.extpy.modpath, self.args) - def reprcall(self): - """ return a string representing a call to the underlying - test function. - """ - return "%s%r" % (self.extpy.modpath, self.args) - - class Outcome: + class Outcome: def __init__(self, **kwargs): assert 'msg' not in kwargs or isinstance(kwargs['msg'], str), ( - "given 'msg' argument is not a string" ) + "given 'msg' argument is not a string" ) self.__dict__.update(kwargs) def __repr__(self): - return getattr(self, 'msg', object.__repr__(self)) + return getattr(self, 'msg', object.__repr__(self)) class Passed(Outcome): pass class Failed(Outcome): pass class ExceptionFailure(Failed): msg = 'DID NOT RAISE' - class Skipped(Outcome): pass + class Skipped(Outcome): pass + +class GenItem(Item): + def __init__(self, extpy, call, *args): + assert callable(call), "generated test %r is not callable" % (call,) + super(GenItem, self).__init__(extpy, *args) + self.call = call -class GenItem(Item): - def __init__(self, extpy, call, *args): - assert callable(call), "generated test %r is not callable" % (call,) - super(GenItem, self).__init__(extpy, *args) - self.call = call - - def execute(self, target, *args): - #print "calling %r%r" %(self.call, args) + def execute(self, target, *args): + #print "calling %r%r" %(self.call, args) return self.call(*args) - def reprcall(self): - """ return a string representing a call to the underlying - generated test function. - """ - name = getattr(self.call, '__name__', self.call) - return "%s -> %s%r" % (self.extpy.modpath, name, self.args) + def reprcall(self): + """ return a string representing a call to the underlying + generated test function. + """ + name = getattr(self.call, '__name__', self.call) + return "%s -> %s%r" % (self.extpy.modpath, name, self.args) # -# triggering specific outcomes from executing Items +# triggering specific outcomes from executing Items # -def skip(msg="unknown reason"): +def skip(msg="unknown reason"): """ skip with the given Message. """ - raise py.test.Item.Skipped(msg=msg, tbindex=-2) + raise py.test.Item.Skipped(msg=msg, tbindex=-2) -def fail(msg="unknown failure"): +def fail(msg="unknown failure"): """ fail with the given Message. """ - raise py.test.Item.Failed(msg=msg, tbindex=-2) + raise py.test.Item.Failed(msg=msg, tbindex=-2) Modified: py/dist/py/test/raises.py ============================================================================== --- py/dist/py/test/raises.py (original) +++ py/dist/py/test/raises.py Sun Jan 9 16:49:34 2005 @@ -1,10 +1,10 @@ import sys -import py -ExceptionFailure = py.test.Item.ExceptionFailure +import py +ExceptionFailure = py.test.Item.ExceptionFailure def raises(ExpectedException, *args, **kwargs): - """ raise AssertionError, if target code does not raise the expected - exception. + """ raise AssertionError, if target code does not raise the expected + exception. """ assert args if isinstance(args[0], str): @@ -17,17 +17,17 @@ source = py.code.Source(expr) try: __traceback__ = py.code.ExceptionInfo.TRACEBACK_HIDE - eval(source.compile(), frame.f_globals, loc) + eval(source.compile(), frame.f_globals, loc) del __traceback__ # XXX didn'T mean f_globals == f_locals something special? - # this is destroyed here ... + # this is destroyed here ... except ExpectedException: return py.code.ExceptionInfo() - raise ExceptionFailure(expr=expr, expected=ExpectedException, + raise ExceptionFailure(expr=expr, expected=ExpectedException, tbindex = -2) else: func = args[0] - assert callable + assert callable try: __traceback__ = py.code.ExceptionInfo.TRACEBACK_HIDE func(*args[1:], **kwargs) @@ -38,5 +38,5 @@ if k: k = ', ' + k expr = '%s(%r%s)' %(func.__name__, args, k) - raise ExceptionFailure(expr=args, expected=ExpectedException, + raise ExceptionFailure(expr=args, expected=ExpectedException, tbindex = -2) Modified: py/dist/py/test/report/memo.py ============================================================================== --- py/dist/py/test/report/memo.py (original) +++ py/dist/py/test/report/memo.py Sun Jan 9 16:49:34 2005 @@ -1,6 +1,6 @@ from __future__ import generators -from py.test import Item +from py.test import Item class MemoReporter: typemap = { @@ -31,7 +31,7 @@ def report_outcome(self, testresult): restype, c = self.processresult(testresult) - + def summary(self): pass Modified: py/dist/py/test/report/testing/__init__.py ============================================================================== --- py/dist/py/test/report/testing/__init__.py (original) +++ py/dist/py/test/report/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# Modified: py/dist/py/test/report/testing/test_memo.py ============================================================================== --- py/dist/py/test/report/testing/test_memo.py (original) +++ py/dist/py/test/report/testing/test_memo.py Sun Jan 9 16:49:34 2005 @@ -1,9 +1,9 @@ -import py +import py def setup_module(mod): - mod.tmpdir = py.path.local.make_numbered_dir() + mod.tmpdir = py.path.local.make_numbered_dir() def teardown_module(mod): - mod.tmpdir.remove() + mod.tmpdir.remove() del mod.tmpdir #def test_equal_should_raise(): @@ -11,13 +11,13 @@ #class MyUnit(collect.Auto, collect.Unit): # def execute(self, runner): -# try: +# try: # def test_memoreporter(): reporter = py.test.MemoReporter() p = tmpdir.join('memoimport.py') - p.write('raise IOError') - collector = py.test.collect.Module(p) + p.write('raise IOError') + collector = py.test.collect.Module(p) #main(collector=collector, reporter=reporter) #collect_errors = reporter.getlist(collect.Error) #assert len(collect_errors) == 1 Modified: py/dist/py/test/report/text/out.py ============================================================================== --- py/dist/py/test/report/text/out.py (original) +++ py/dist/py/test/report/text/out.py Sun Jan 9 16:49:34 2005 @@ -6,15 +6,15 @@ tty = False fullwidth = int(os.environ.get('COLUMNS', 80))-1 def __init__(self, file): - self.file = file + self.file = file def sep(self, sepchar, title=None): - fullwidth = self.fullwidth + fullwidth = self.fullwidth #spacing = " " * ((79 - compwidth)/2) if title is not None: size = len(title) + 2 half = (fullwidth-size) / 2.0 - #line = "%s%s %s %s%s" %(spacing, + #line = "%s%s %s %s%s" %(spacing, # sepchar * half, title, sepchar * half, spacing) fill = sepchar * int(half / len(sepchar)) line = "%s %s %s" % (fill, title, fill) @@ -47,7 +47,7 @@ self.file.flush() def rewrite(self, s=''): - self.write('%s' % s) + self.write('%s' % s) class FileOut(Out): def write(self, s): @@ -62,11 +62,11 @@ self.file.flush() def rewrite(self, s=''): - self.write(s) + self.write(s) def getout(file): - # investigate further into terminal, this is not enough - if False and file.isatty(): - return TerminalOut(file) + # investigate further into terminal, this is not enough + if False and file.isatty(): + return TerminalOut(file) else: - return FileOut(file) + return FileOut(file) Modified: py/dist/py/test/report/text/reporter.py ============================================================================== --- py/dist/py/test/report/text/reporter.py (original) +++ py/dist/py/test/report/text/reporter.py Sun Jan 9 16:49:34 2005 @@ -4,67 +4,67 @@ Collector = py.test.collect.Collector from time import time as now -# lazy relative Implementation imports -from summary import Summary -from out import getout +# lazy relative Implementation imports +from summary import Summary +from out import getout class TextReporter(object): - Summary = Summary + Summary = Summary typemap = { - Item.Passed: '.', - Item.Skipped: 's', + Item.Passed: '.', + Item.Skipped: 's', Item.Failed: 'F', - Collector.Error: 'C', + Collector.Error: 'C', } namemap = { - Item.Passed: 'ok', - Item.Skipped: 'SKIP', + Item.Passed: 'ok', + Item.Skipped: 'SKIP', Item.Failed: 'FAIL', - Collector.Error: 'COLLECT ERROR', + Collector.Error: 'COLLECT ERROR', } - def __init__(self, f=None): + def __init__(self, f=None): if f is None: - f = py.std.sys.stdout - self.out = getout(f) + f = py.std.sys.stdout + self.out = getout(f) self._started = {} - self.summary = self.Summary(self.out) - self.summary.option = self.option = py.test.config.option + self.summary = self.Summary(self.out) + self.summary.option = self.option = py.test.config.option def start(self): - self.out.sep("=", "test process starts") - option = py.test.config.option - if option.session: - mode = 'session/child process' - elif option.executable: - mode = 'child process' - else: - mode = 'inprocess' - self.out.line("testing-mode: %s" % mode) - self.out.line("executable : %s (%s)" % - (py.std.sys.executable, repr_pythonversion())) - - rev = py.__package__.getrev() + self.out.sep("=", "test process starts") + option = py.test.config.option + if option.session: + mode = 'session/child process' + elif option.executable: + mode = 'child process' + else: + mode = 'inprocess' + self.out.line("testing-mode: %s" % mode) + self.out.line("executable : %s (%s)" % + (py.std.sys.executable, repr_pythonversion())) + + rev = py.__package__.getrev() self.out.line("using py lib: %s " % ( py.path.local(py.__file__).dirpath(), rev)) - for i, x in py.builtin.enumerate(py.test.config.configpaths): + 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(): + additional = py.test.config.getfirst('additionalinfo') + if additional: + for key, descr in additional(): self.out.line("%s: %s" %(key, descr)) self.out.sep("=") if not self.option.nomagic: - py.magic.invoke(assertion=1) - self.summary.starttime = now() + py.magic.invoke(assertion=1) + self.summary.starttime = now() def end(self): if not self.option.nomagic: - py.magic.revoke(assertion=1) - self.summary.endtime = now() - self.summary.render() + py.magic.revoke(assertion=1) + self.summary.endtime = now() + self.summary.render() def open(self, collector): if self.option.collectonly: @@ -90,11 +90,11 @@ numunits = len(list(collector.iterunits())) if numunits > 0: #if verbose < 2: - # self.out.write('%s[%d]' % (collector.extpy, + # self.out.write('%s[%d]' % (collector.extpy, # numunits)) #else: - #self.out.line("collector.fspy.modpath) - return self.out.line + #self.out.line("collector.fspy.modpath) + return self.out.line def open_Directory(self, collector): if self.option.verbose < 1: @@ -114,44 +114,44 @@ def startitem(self, item): if self.option.collectonly: cols = self._opencollectors - if len(cols): + if len(cols): print ' ' * len(cols), - print "Item", item.extpy.modpath + print "Item", item.extpy.modpath return if not self.option.nocapture: - from py.__impl__.test.tool.outerrcapture import SimpleOutErrCapture + from py.__impl__.test.tool.outerrcapture import SimpleOutErrCapture item.iocapture = SimpleOutErrCapture() if self.out.tty: realpath, lineno = item.extpy.getfilelineno() location = "running %s:%d %s" % (realpath.basename, lineno, str(item.extpy.modpath)) - self.out.rewrite(location) - self._started[item] = now() + self.out.rewrite(location) + self._started[item] = now() def enditem(self, result): if self.option.collectonly: return endtime = now() - item = result.item - starttime = self._started[item] + item = result.item + starttime = self._started[item] del self._started[item] elapsed = endtime - starttime - item.elapsed = elapsed - + item.elapsed = elapsed + if not self.option.nocapture: result.out, result.err = item.iocapture.reset() - + restype, c = self.processresult(result) - writeinfo = None + writeinfo = None if self.out.tty: if not isinstance(result, py.test.Item.Passed) or self.option.verbose >=1: - writeinfo = '\n' - elif isinstance(result, py.test.Item.Passed): - writeinfo = '' + writeinfo = '\n' + elif isinstance(result, py.test.Item.Passed): + writeinfo = '' elif self.option.verbose >= 1: - writeinfo = '\n' + writeinfo = '\n' else: - self.out.write(c) - + self.out.write(c) + if writeinfo is not None: realpath, lineno = item.extpy.getfilelineno() location = "%s:%d" % (realpath.basename, lineno+1) @@ -171,23 +171,23 @@ pdb.post_mortem(result.excinfo._excinfo[2]) def report_collect_error(self, error): - restype, c = self.processresult(error) - writeinfo = None + restype, c = self.processresult(error) + writeinfo = None if self.out.tty: - if not isinstance(result, Item.Passed) or self.option.verbose >=1: - writeinfo = '\n' - elif isinstance(result, Item.Passed): - writeinfo = '' + if not isinstance(result, Item.Passed) or self.option.verbose >=1: + writeinfo = '\n' + elif isinstance(result, Item.Passed): + writeinfo = '' elif self.option.verbose >= 1: - writeinfo = '\n' + writeinfo = '\n' else: - self.out.write(c) - + self.out.write(c) + if writeinfo is not None: #exc, frame, filename,lineno = self.summary.getexinfo(error) tbentries = list(error.excinfo) - filename = tbentries[-1].frame.code.path - lineno = tbentries[-1].lineno + filename = tbentries[-1].frame.code.path + lineno = tbentries[-1].lineno self.out.line('CollectError: %s:%d' % (filename, lineno) ) def processresult(self, testresult): @@ -212,4 +212,4 @@ return "%s.%s.%s-%s-%s" % v except ValueError: return str(v) - + Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Sun Jan 9 16:49:34 2005 @@ -1,11 +1,11 @@ from __future__ import generators -import py -Item = py.test.Item +import py +Item = py.test.Item from py.__impl__.magic import exprinfo, assertion class Summary(object): - def __init__(self, out): - self.out = out + def __init__(self, out): + self.out = out def append(self, restype, testresult): self.getlist(restype).append(testresult) @@ -14,12 +14,12 @@ name = restype.__name__.lower() return self.__dict__.setdefault(name, []) - def repr_collect_error(self, error): + def repr_collect_error(self, error): self.out.line() - self.out.sep("_") + self.out.sep("_") self.out.sep("_", "Collect Error") self.out.line() - self.repr_traceback_raw(error.excinfo.getentries()) + self.repr_traceback_raw(error.excinfo.getentries()) #self.repr_failure_result(res) #self.out.line() #if isinstance(res.excinfo[1], AssertionError): @@ -32,14 +32,14 @@ # for name, value in frame.f_locals.items(): # self.out.line("%-10s = %r" %(name, value)) def summary_collect_errors(self): - for error in self.getlist(py.test.collect.Error): - self.repr_collect_error(error) + for error in self.getlist(py.test.collect.Error): + self.repr_collect_error(error) def render(self): self.out.write('\n') self.skippedreasons() self.failures() - self.summary_collect_errors() + self.summary_collect_errors() outlist = [] sum = 0 for typ in Item.Passed, Item.Failed, Item.Skipped: @@ -49,15 +49,15 @@ sum += len(l) elapsed = self.endtime-self.starttime status = "%s" % ", ".join(outlist) - self.out.sep('=', 'tests finished: %s in %4.2f seconds' % + self.out.sep('=', 'tests finished: %s in %4.2f seconds' % (status, elapsed)) def skippedreasons(self): d = {} for res in self.getlist(Item.Skipped): tbindex = getattr(res, 'tbindex', -1) - raisingtb = list(res.excinfo)[tbindex] - fn = raisingtb.frame.code.path + raisingtb = list(res.excinfo)[tbindex] + fn = raisingtb.frame.code.path lineno = raisingtb.lineno d[(fn,lineno)] = res if d: @@ -66,22 +66,22 @@ for (fn,lineno), res in d.items(): self.out.line('Skipped in %s:%d %s' %(fn,lineno+1,getattr(res, 'msg'))) self.out.line() - + def failures(self): for res in self.getlist(Item.Failed): self.repr_failure(res) def repr_failure(self, res): self.out.line() - self.out.sep("_") + self.out.sep("_") #self.out.line() - self.repr_traceback(res.item, res.excinfo, + self.repr_traceback(res.item, res.excinfo, getattr(res, 'tbindex', -1)) #self.out.line() self.repr_failure_result(res) - for name in 'out', 'err': - if hasattr(res, name): - out = getattr(res, name) + for name in 'out', 'err': + if hasattr(res, name): + out = getattr(res, name) if out.strip(): self.out.sep("- ", "recorded std%s" % name) self.out.line(out.strip()) @@ -103,86 +103,86 @@ "verbosity to see details)") self.out.line(exprinfo or res.excinfo) - def repr_source(self, tb): - # represent source code for a given traceback entry + def repr_source(self, tb): + # represent source code for a given traceback entry self.out.line() - try: - source = tb.frame.code.fullsource - except py.error.ENOENT: - self.out.line("failure to get at sourcelines from %r" % tb) + try: + source = tb.frame.code.fullsource + except py.error.ENOENT: + self.out.line("failure to get at sourcelines from %r" % tb) #self.out.line("(co_filename = %r)" % (frame.f_code.co_filename)) - #self.out.line("(f_lineno = %r)" % (frame.f_lineno)) + #self.out.line("(f_lineno = %r)" % (frame.f_lineno)) return - start = tb.frame.code.firstlineno + start = tb.frame.code.firstlineno end = tb.lineno - - for line in source[start:end]: + + for line in source[start:end]: self.out.line(line.rstrip()) - line = source[end] + line = source[end] if line.startswith(" "): line = line[1:] # to avoid the indentation caused by ">" self.out.line(">" + line) return - def cut_traceback(self, excinfo, item=None, tbindex=None): - if self.option.fulltrace or item is None: - startcondition = endcondition = None - else: + def cut_traceback(self, excinfo, item=None, tbindex=None): + if self.option.fulltrace or item is None: + startcondition = endcondition = None + else: path,lineno = item.extpy.getfilelineno() - def startcondition(entry): + def startcondition(entry): return entry.frame.code.path == path and \ - entry.frame.code.firstlineno == lineno - endcondition = None - entries = excinfo.getentries(startcondition, endcondition) - # XXX the cutting logic needs refactoring with respect - # to generative tests (which will not have the - # test item in their tb-path) - # - if not entries: - entries = excinfo.getentries() + entry.frame.code.firstlineno == lineno + endcondition = None + entries = excinfo.getentries(startcondition, endcondition) + # XXX the cutting logic needs refactoring with respect + # to generative tests (which will not have the + # test item in their tb-path) + # + if not entries: + entries = excinfo.getentries() if tbindex is not None and tbindex < -1: entries = entries[:tbindex+1] - return entries + return entries def repr_traceback(self, item, excinfo, tbindex=None): tbentries = self.cut_traceback(excinfo, item, tbindex) - self.repr_traceback_raw(tbentries) + self.repr_traceback_raw(tbentries) self.out.sep('-') - def repr_traceback_raw(self, tbentries): + def repr_traceback_raw(self, tbentries): recursioncache = {} - first = True + first = True for tb in tbentries: if first: - first = False + first = False else: self.out.sep('-') - path = tb.frame.code.path - lineno = tb.lineno - name = tb.frame.code.name - showfn = path + path = tb.frame.code.path + lineno = tb.lineno + name = tb.frame.code.name + showfn = path #showfn = filename.split(os.sep) #if len(showfn) > 5: # showfn = os.sep.join(['...'] + showfn[-5:]) - self.repr_source(tb) + self.repr_source(tb) self.out.line("") self.out.line("[%s:%d]" %(showfn, lineno+1)) # , name)) if self.option.showlocals: self.out.sep('- ', 'locals') for name, value in tb.frame.f_locals.items(): - if len(repr(value)) < 70 or not isinstance(value, + if 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) + py.std.pprint.pprint(value, stream=self.out) #self.out.line("%-10s = %r" %(name, value)) key = (path, lineno) if key not in recursioncache: recursioncache.setdefault(key, []).append(tb.frame.f_locals) else: f = tb.frame - loc = f.f_locals + loc = f.f_locals for x in recursioncache[key]: if f.is_true(f.eval(co_equal, __recursioncache_locals_1=loc, __recursioncache_locals_2=x)): Modified: py/dist/py/test/run.py ============================================================================== --- py/dist/py/test/run.py (original) +++ py/dist/py/test/run.py Sun Jan 9 16:49:34 2005 @@ -1,42 +1,42 @@ from __future__ import generators -import py +import py from py.__impl__.execnet.channel import ChannelFile, receive2file from py.__impl__.test.config import configbasename from py.__impl__.test.collect import getfscollector import sys -def checkpyfilechange(rootdir, statcache): - """ wait until project files are changed. """ +def checkpyfilechange(rootdir, statcache): + """ wait until project files are changed. """ fil = py.path.checker(fnmatch='*.py') - rec = py.path.checker(dotfile=0) + rec = py.path.checker(dotfile=0) changed = False for path in rootdir.visit(fil, rec): - oldstat = statcache.get(path, None) + oldstat = statcache.get(path, None) try: statcache[path] = curstat = path.stat() - except py.error.ENOENT: - if oldstat: + except py.error.ENOENT: + if oldstat: del statcache[path] - print "# WARN: race condition on", path + print "# WARN: race condition on", path else: - if oldstat: + if oldstat: if oldstat.st_mtime != curstat.st_mtime or \ - oldstat.st_size != curstat.st_size: - changed = True + oldstat.st_size != curstat.st_size: + changed = True print "# MODIFIED", path else: changed = True - return changed + return changed class FailingCollector(py.test.collect.Collector): def __init__(self, faileditems): - self._faileditems = faileditems + self._faileditems = faileditems def __iter__(self): - for x in self._faileditems: + for x in self._faileditems: yield x - + class StdouterrProxy: def __init__(self, gateway): self.gateway = gateway @@ -44,16 +44,16 @@ channel = self.gateway.remote_exec(""" import sys out, err = channel.newchannel(), channel.newchannel() - channel.send(out) - channel.send(err) - sys.stdout, sys.stderr = out.open('w'), err.open('w') + channel.send(out) + channel.send(err) + sys.stdout, sys.stderr = out.open('w'), err.open('w') """) - self.stdout = channel.receive() - self.stderr = channel.receive() + self.stdout = channel.receive() + self.stderr = channel.receive() channel.waitclose(1.0) - py.std.threading.Thread(target=receive2file, + py.std.threading.Thread(target=receive2file, args=(self.stdout, sys.stdout)).start() - py.std.threading.Thread(target=receive2file, + py.std.threading.Thread(target=receive2file, args=(self.stderr, sys.stderr)).start() def teardown(self): self.stdout.close() @@ -63,8 +63,8 @@ try: while 1: try: - channel.waitclose(0.1) - except (IOError, py.error.Error): + channel.waitclose(0.1) + except (IOError, py.error.Error): continue else: failures = channel.receive() @@ -75,16 +75,16 @@ channel.close() channel.gateway.exit() -def failure_master(args, filenames, failures): +def failure_master(args, filenames, failures): exe = py.test.config.option.executable - gw = py.execnet.PopenGateway(python=exe or sys.executable) - outproxy = StdouterrProxy(gw) + gw = py.execnet.PopenGateway(python=exe or sys.executable) + outproxy = StdouterrProxy(gw) outproxy.setup() try: channel = gw.remote_exec(""" from py.__impl__.test.run import failure_slave failure_slave(channel) - """) + """) channel.send((args, filenames, failures)) return waitfinish(channel) finally: @@ -94,69 +94,69 @@ """ we run this on the other side. """ args, filenames, failures = channel.receive() filenames = map(py.path.local, filenames) - py.test.config.readconfiguration(*filenames) + py.test.config.readconfiguration(*filenames) py.test.config.parseargs(args) - if failures: + if failures: col = FailureCollector(failures) - else: + else: col = list(getcollectors(filenames)) - driver = py.test.Driver(channel) + driver = py.test.Driver(channel) failures = driver.run(col) - channel.send(failures) + channel.send(failures) class FailureCollector(py.test.collect.Collector): def __init__(self, failures): self.failures = failures def __iter__(self): for root,modpath in self.failures: - extpy = py.path.extpy(root, modpath) - yield self.Item(extpy) - + extpy = py.path.extpy(root, modpath) + yield self.Item(extpy) + def getcollectors(filenames): current = py.path.local() for fn in filenames: fullfn = current.join(fn, abs=1) - yield getfscollector(fullfn) - + yield getfscollector(fullfn) + def getanchors(args): """ yield "anchors" from skimming the args for existing files/dirs. """ current = py.path.local() l = [] - for arg in args: - anchor = current.join(arg, abs=1) + for arg in args: + anchor = current.join(arg, abs=1) if anchor.check(): - l.append(anchor) + l.append(anchor) if not l: l = [current] - return l + return l # -# Testing Modes +# Testing Modes # -def inprocess(args, filenames): +def inprocess(args, filenames): """ we run this on the other side. """ fncollectors = list(getcollectors(filenames)) - driver = py.test.Driver(None) + driver = py.test.Driver(None) driver.run(fncollectors) def session(args, filenames): statcache = {} # XXX find out rootdir automatically with - # something like py.magic.autopath() ? + # something like py.magic.autopath() ? rootdir = py.path.local(py.test.config.getfirst('rootdir', py.path.local())) l = len(str(rootdir)) failures = [] while 1: - if py.test.config.option.session: - while not checkpyfilechange(rootdir, statcache): - py.std.time.sleep(0.4) + if py.test.config.option.session: + while not checkpyfilechange(rootdir, statcache): + py.std.time.sleep(0.4) failures = failure_master(args, filenames, failures) - if not py.test.config.option.session: - break + if not py.test.config.option.session: + break print "#" * 60 print "# session mode: %d failures remaining" % len(failures) - for x in failures: + for x in failures: print "Failure at: %r" % (x,) print "# watching py files below %s" % rootdir print "# ", "^" * l Modified: py/dist/py/test/testing/__init__.py ============================================================================== --- py/dist/py/test/testing/__init__.py (original) +++ py/dist/py/test/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# Modified: py/dist/py/test/testing/test/data/disabled.py ============================================================================== --- py/dist/py/test/testing/test/data/disabled.py (original) +++ py/dist/py/test/testing/test/data/disabled.py Sun Jan 9 16:49:34 2005 @@ -1,4 +1,4 @@ -class x: - class y: +class x: + class y: disabled = True - def test_method(self): pass + def test_method(self): pass Modified: py/dist/py/test/testing/test/data/disabledclass.py ============================================================================== --- py/dist/py/test/testing/test/data/disabledclass.py (original) +++ py/dist/py/test/testing/test/data/disabledclass.py Sun Jan 9 16:49:34 2005 @@ -1,5 +1,5 @@ class TestClass: disabled = True - def test_func(): + def test_func(): pass Modified: py/dist/py/test/testing/test/data/syntax_error.py ============================================================================== --- py/dist/py/test/testing/test/data/syntax_error.py (original) +++ py/dist/py/test/testing/test/data/syntax_error.py Sun Jan 9 16:49:34 2005 @@ -1,4 +1,4 @@ -this is really not python +this is really not python Modified: py/dist/py/test/testing/test/demo.py ============================================================================== --- py/dist/py/test/testing/test/demo.py (original) +++ py/dist/py/test/testing/test/demo.py Sun Jan 9 16:49:34 2005 @@ -2,7 +2,7 @@ def otherfunc(a,b): assert a==b - + def somefunc(x,y): otherfunc(x,y) @@ -38,12 +38,12 @@ def test_startswith(): s = "123" g = "456" - assert s.startswith(g) + assert s.startswith(g) def test_startswith_nested(): - def f(): + def f(): return "123" - def g(): + def g(): return "456" assert f().startswith(g()) @@ -73,7 +73,7 @@ def test_raise(self): raise ValueError("demo error") - + def test_tupleerror(self): a,b = [1] Modified: py/dist/py/test/testing/test/test_setup_nested.py ============================================================================== --- py/dist/py/test/testing/test/test_setup_nested.py (original) +++ py/dist/py/test/testing/test/test_setup_nested.py Sun Jan 9 16:49:34 2005 @@ -1,30 +1,30 @@ # -# test correct setup/teardowns at -# module, class, and instance level +# test correct setup/teardowns at +# module, class, and instance level modlevel = [] def setup_module(module): - module.modlevel.append(42) + module.modlevel.append(42) def teardown_module(module): modlevel.pop() -def setup_function(function): +def setup_function(function): function.answer = 17 -def teardown_function(function): +def teardown_function(function): del function.answer def test_modlevel(): assert modlevel[0] == 42 - assert test_modlevel.answer == 17 + assert test_modlevel.answer == 17 -class TestSimpleClassSetup: +class TestSimpleClassSetup: clslevel = [] def setup_class(cls): - cls.clslevel.append(23) + cls.clslevel.append(23) def teardown_class(cls): cls.clslevel.pop() @@ -33,7 +33,7 @@ assert self.clslevel[0] == 23 def test_modulelevel(self): - assert modlevel == [42] + assert modlevel == [42] class TestInheritedClassSetupStillWorks(TestSimpleClassSetup): def test_classlevel_anothertime(self): @@ -45,8 +45,8 @@ def teardown_method(self, method): x = self.clslevel.pop() - assert x == 17 + assert x == 17 def test_setup(self): - assert self.clslevel[-1] == 17 - + assert self.clslevel[-1] == 17 + Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Sun Jan 9 16:49:34 2005 @@ -2,18 +2,18 @@ import py from py.__impl__.test import collect autopath = py.magic.autopath() -testdir = autopath.dirpath('test') +testdir = autopath.dirpath('test') assert testdir.check(dir=1) datadir = testdir / 'data' def test_failing_import_execfile(): - fn = datadir / 'failingimport.py' + fn = datadir / 'failingimport.py' l = list(collect.Module(py.path.extpy(fn))) assert l ex, = l assert issubclass(ex.excinfo.type, ImportError) - + def test_failing_import_directory(): class MyDirectory(collect.Directory): fil = py.path.checker(basestarts="testspecial_", ext='.py') @@ -31,14 +31,14 @@ l = list(collect.Module(fn)) assert len(l) == 1 assert isinstance(l[0], collect.Error) - assert isinstance(l[0].excinfo.value, py.error.ENOENT) + assert isinstance(l[0].excinfo.value, py.error.ENOENT) def test_syntax_error_in_module(): modpath = py.path.extpy(datadir.join('syntax_error.py')) l2 = list(collect.Module(modpath)) assert len(l2) == 1 assert isinstance(l2[0], collect.Error) - assert issubclass(l2[0].excinfo.type, SyntaxError) + assert issubclass(l2[0].excinfo.type, SyntaxError) def test_disabled_class(): extpy = py.path.extpy(datadir.join('disabled.py')) @@ -50,15 +50,15 @@ def test_something(): raise ValueError - -class TestWithCustomItem: - class Item(py.test.Item): + +class TestWithCustomItem: + class Item(py.test.Item): flag = [] - def execute(self, target, *args): - self.flag.append(42) - target(*args) + def execute(self, target, *args): + self.flag.append(42) + target(*args) - def test_hello(self): + def test_hello(self): assert self.Item.flag == [42] l = [] @@ -84,61 +84,61 @@ # l2=[] -def func1(): +def func1(): print "in func1" - l2.append(1) + l2.append(1) -def func2(i): +def func2(i): print "in func2 with param %d" % i - l2.append(i) + l2.append(i) -def test_generator(): +def test_generator(): yield func1 - yield func2, 2 - yield func2, 3 + yield func2, 2 + yield func2, 3 -def test_stateful_previous(): +def test_stateful_previous(): x = l2 assert x == [1,2,3] -class TestGeneratorMethod: +class TestGeneratorMethod: l3 = [] - def func1(self, i): - self.l3.append(i) + def func1(self, i): + self.l3.append(i) - def test_generator(self): - yield self.func1, 4 + def test_generator(self): + yield self.func1, 4 yield self.func1, 5 - def test_previous_generator_worked(self): + def test_previous_generator_worked(self): assert self.l3 == [4,5] -def test_custom_collection_from_conftest(): +def test_custom_collection_from_conftest(): o = py.test.config.tmpdir.ensure('customconfigtest', dir=1) - o.ensure('conftest.py').write("""if 1: + o.ensure('conftest.py').write("""if 1: import py - class MyItem(py.test.Item): + class MyItem(py.test.Item): pass - class Directory(py.test.collect.Directory): - def fil(self, fspath): + class Directory(py.test.collect.Directory): + def fil(self, fspath): return fspath.check(basestarts='check_') - class Module(py.test.collect.Module): - def collect_function(self, extpy): - if extpy.check(basestarts='check_', func=1): - yield self.Item(extpy) - class Class(py.test.collect.Class): - def collect_method(self, extpy): + class Module(py.test.collect.Module): + def collect_function(self, extpy): + if extpy.check(basestarts='check_', func=1): + yield self.Item(extpy) + class Class(py.test.collect.Class): + def collect_method(self, extpy): if extpy.check(basestarts='check_', func=1): - yield MyItem(extpy) + yield MyItem(extpy) """) - o.ensure('somedir', 'check_something').write("""if 1: - def check_func(): - assert 42 == 42 - class TestClass: - def check_method(self): + o.ensure('somedir', 'check_something').write("""if 1: + def check_func(): + assert 42 == 42 + class TestClass: + def check_method(self): assert 23 == 23 """) - from py.__impl__.test.collect import getfscollector - units = list(getfscollector(o).iterunits()) + from py.__impl__.test.collect import getfscollector + units = list(getfscollector(o).iterunits()) assert len(units) == 2 - assert units[1].__class__.__name__ == 'MyItem' + assert units[1].__class__.__name__ == 'MyItem' Modified: py/dist/py/test/testing/test_compat.py ============================================================================== --- py/dist/py/test/testing/test_compat.py (original) +++ py/dist/py/test/testing/test_compat.py Sun Jan 9 16:49:34 2005 @@ -1,7 +1,7 @@ from __future__ import generators -import py +import py -class TestCompatTestCaseSetupSemantics(py.test.compat.TestCase): +class TestCompatTestCaseSetupSemantics(py.test.compat.TestCase): globlist = [] def setUp(self): @@ -44,8 +44,8 @@ #self.%(name)s(%(paramfail)s) def test_%(name)s_failing(self): - self.assertRaises(py.test.Item.Failed, + self.assertRaises(py.test.Item.Failed, self.%(name)s, %(paramfail)s) """ % locals() - co = py.code.Source(source).compile() - exec co + co = py.code.Source(source).compile() + exec co Modified: py/dist/py/test/testing/test_config.py ============================================================================== --- py/dist/py/test/testing/test_config.py (original) +++ py/dist/py/test/testing/test_config.py Sun Jan 9 16:49:34 2005 @@ -1,6 +1,6 @@ from __future__ import generators import py -config = py.test.config +config = py.test.config class MyClass: def getoptions(self): @@ -23,18 +23,18 @@ assert not obj.option.verbose def test_tmpdir(): - d1 = config.tmpdir - d2 = config.tmpdir + d1 = config.tmpdir + d2 = config.tmpdir assert d1 == d2 def test_config_order(): - from py.__impl__.test import config + from py.__impl__.test import config o = py.test.config.tmpdir.ensure('configorder', dir=1) - o.ensure('conftest.py').write('x=1 ; import py ; py._x = [x]') + o.ensure('conftest.py').write('x=1 ; import py ; py._x = [x]') o.ensure('a/conftest.py').write('x=2 ; import py ; py._x.append(x)') o.ensure('a/b/c/conftest.py').write('x=3 ; import py ; py._x.append(x)') - cfg = config.Config() - cfg.readconfiguration(o) + cfg = config.Config() + cfg.readconfiguration(o) assert cfg.getfirst('x') == 1 assert py._x == [1] @@ -42,11 +42,11 @@ cfg.readconfiguration(o.join('a/b/c')) assert cfg.getfirst('x') == 1 assert py._x == [1,2,3] - + def test_getconfigvalue(): - from py.__impl__.test import config - cfg = config.Config() + from py.__impl__.test import config + cfg = config.Config() o = py.test.config.tmpdir.ensure('configtest', dir=1) - o.ensure('conftest.py').write('x=1') + o.ensure('conftest.py').write('x=1') assert cfg.getconfigvalue(o, 'x') == 1 py.test.raises(ValueError, "cfg.getconfigvalue(o, 'y')") Modified: py/dist/py/test/testing/test_raises.py ============================================================================== --- py/dist/py/test/testing/test_raises.py (original) +++ py/dist/py/test/testing/test_raises.py Sun Jan 9 16:49:34 2005 @@ -1,9 +1,9 @@ -from py import test +from py import test def somefunc(x, y): assert x == y -class TestClass: +class TestClass: def test_raises(self): test.raises(ValueError, "int('qwe')") Modified: py/dist/py/test/tool/optparse.py ============================================================================== --- py/dist/py/test/tool/optparse.py (original) +++ py/dist/py/test/tool/optparse.py Sun Jan 9 16:49:34 2005 @@ -69,7 +69,7 @@ import sys, os import types -from py.__impl__.test.tool import textwrap +from py.__impl__.test.tool import textwrap class OptParseError (Exception): def __init__ (self, msg): Modified: py/dist/py/test/tool/outerrcapture.py ============================================================================== --- py/dist/py/test/tool/outerrcapture.py (original) +++ py/dist/py/test/tool/outerrcapture.py Sun Jan 9 16:49:34 2005 @@ -1,6 +1,6 @@ """ -capture stdout/stderr +capture stdout/stderr """ import sys @@ -8,10 +8,10 @@ except ImportError: from StringIO import StringIO class SimpleOutErrCapture: - """ capture sys.stdout/sys.stderr (but not system level fd 1 and 2). - + """ capture sys.stdout/sys.stderr (but not system level fd 1 and 2). + this captures only "In-Memory" and is currently intended to be - used by the unittest package to capture print-statements in tests. + used by the unittest package to capture print-statements in tests. """ def __init__(self): self.oldout = sys.stdout Modified: py/dist/py/test/tool/testing/__init__.py ============================================================================== --- py/dist/py/test/tool/testing/__init__.py (original) +++ py/dist/py/test/tool/testing/__init__.py Sun Jan 9 16:49:34 2005 @@ -1 +1 @@ -# \ No newline at end of file +# Modified: py/dist/py/test/tool/testing/test_outerrcapture.py ============================================================================== --- py/dist/py/test/tool/testing/test_outerrcapture.py (original) +++ py/dist/py/test/tool/testing/test_outerrcapture.py Sun Jan 9 16:49:34 2005 @@ -1,6 +1,6 @@ import sys from py import test -from py.__impl__.test.tool.outerrcapture import SimpleOutErrCapture +from py.__impl__.test.tool.outerrcapture import SimpleOutErrCapture def test_capturing_simple(): cap = SimpleOutErrCapture() From arigo at codespeak.net Sun Jan 9 19:28:38 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 9 Jan 2005 19:28:38 +0100 (MET) Subject: [py-svn] r8187 - py/dist/py Message-ID: <20050109182838.EA1C027B75@code1.codespeak.net> Author: arigo Date: Sun Jan 9 19:28:38 2005 New Revision: 8187 Modified: py/dist/py/initpkg.py Log: Temporary fix for "import py; py.magic.greenlet" raising an ImportError if the 'py' lib is not in your PYTHONPATH: make the package __path__ absolute. This prevents os.chdir() from breaking imports. Modified: py/dist/py/initpkg.py ============================================================================== --- py/dist/py/initpkg.py (original) +++ py/dist/py/initpkg.py Sun Jan 9 19:28:38 2005 @@ -22,7 +22,7 @@ """ from __future__ import generators -import sys +import sys, os assert sys.version_info >= (2,2,0), "py lib requires python 2.2 or higher" ModuleType = type(sys.modules[__name__]) @@ -46,7 +46,8 @@ self.implmodule = ModuleType(implname) self.implmodule.__name__ = implname self.implmodule.__file__ = pkgmodule.__file__ - self.implmodule.__path__ = pkgmodule.__path__ + self.implmodule.__path__ = [os.path.abspath(p) + for p in pkgmodule.__path__] pkgmodule.__impl__ = self.implmodule setmodule(implname, self.implmodule) # inhibit further direct filesystem imports through the package module From hpk at codespeak.net Sun Jan 9 20:39:26 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 9 Jan 2005 20:39:26 +0100 (MET) Subject: [py-svn] r8188 - py/dist/py/path/extpy/testing/test_data Message-ID: <20050109193926.78CD027B75@code1.codespeak.net> Author: hpk Date: Sun Jan 9 20:39:26 2005 New Revision: 8188 Modified: py/dist/py/path/extpy/testing/test_data/no_trailing_newline.py Log: beware of formatting fixes: this file does want to have no newline at end (filename makes it obvious) Modified: py/dist/py/path/extpy/testing/test_data/no_trailing_newline.py ============================================================================== --- py/dist/py/path/extpy/testing/test_data/no_trailing_newline.py (original) +++ py/dist/py/path/extpy/testing/test_data/no_trailing_newline.py Sun Jan 9 20:39:26 2005 @@ -4,4 +4,4 @@ ############################################################################# # 2004 M.E.Farmer Jr. -# Python license +# Python license \ No newline at end of file From hpk at codespeak.net Tue Jan 11 15:31:44 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 11 Jan 2005 15:31:44 +0100 (MET) Subject: [py-svn] r8212 - py/dist/py/bin Message-ID: <20050111143144.34F8A27BD6@code1.codespeak.net> Author: hpk Date: Tue Jan 11 15:31:44 2005 New Revision: 8212 Added: py/dist/py/bin/py.cleanup (contents, props changed) Log: added another useful cmdline-tool: py.cleanup which erases all *.pyc files under the current working directory. Added: py/dist/py/bin/py.cleanup ============================================================================== --- (empty file) +++ py/dist/py/bin/py.cleanup Tue Jan 11 15:31:44 2005 @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +from _findpy import py +import py + +for x in py.path.local().visit('*.pyc', py.path.checker(dotfile=0)): + x.remove() From hpk at codespeak.net Tue Jan 11 17:31:19 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 11 Jan 2005 17:31:19 +0100 (MET) Subject: [py-svn] r8218 - py/dist/py/execnet Message-ID: <20050111163119.3B08227BF6@code1.codespeak.net> Author: hpk Date: Tue Jan 11 17:31:19 2005 New Revision: 8218 Modified: py/dist/py/execnet/register.py Log: be prepared for undefined PYTHONPATHs Modified: py/dist/py/execnet/register.py ============================================================================== --- py/dist/py/execnet/register.py (original) +++ py/dist/py/execnet/register.py Tue Jan 11 17:31:19 2005 @@ -70,7 +70,7 @@ # of the py lib, but only works for PopenGateways # --> we need proper remote imports working # across any kind of gateway! - plist = os.environ['PYTHONPATH'].split(':') + plist = os.environ.get('PYTHONPATH', '').split(':') s = "import sys ; sys.path[:0] = %r" % (plist,) s = "\n".join([extra, s]) super(PopenGateway, self).remote_bootstrap_gateway(io, s) From hpk at codespeak.net Wed Jan 12 16:08:55 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 12 Jan 2005 16:08:55 +0100 (MET) Subject: [py-svn] r8228 - in py/dist/py: documentation/example/pytest test test/report/text Message-ID: <20050112150855.4594827BDB@code1.codespeak.net> Author: hpk Date: Wed Jan 12 16:08:55 2005 New Revision: 8228 Modified: py/dist/py/documentation/example/pytest/failure_demo.py py/dist/py/test/drive.py py/dist/py/test/report/text/summary.py Log: experimental: don't let SystemExits from executing tests propagate. add an example to the failure_demo.py series. Basically we only let KeyboardErrors through now. Modified: py/dist/py/documentation/example/pytest/failure_demo.py ============================================================================== --- py/dist/py/documentation/example/pytest/failure_demo.py (original) +++ py/dist/py/documentation/example/pytest/failure_demo.py Wed Jan 12 16:08:55 2005 @@ -109,3 +109,6 @@ def globf(x): return x+1 + +def test_systemexit_doesnt_leave(): + raise SystemExit Modified: py/dist/py/test/drive.py ============================================================================== --- py/dist/py/test/drive.py (original) +++ py/dist/py/test/drive.py Wed Jan 12 16:08:55 2005 @@ -62,15 +62,15 @@ elif isinstance(obj, py.test.collect.Collector.Error): try: self.reporter.report_collect_error(obj) - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, self.Exit): raise except: print "*" * 80 - print "Reporter Error" + print "internal Reporter Error" print "*" * 80 import traceback traceback.print_exc() - raise SystemExit, 1 + raise self.Exit if self.option.exitfirstproblem: raise self.Exit() else: @@ -93,9 +93,9 @@ except item.Outcome, res: if not hasattr(res, 'excinfo'): res.excinfo = py.code.ExceptionInfo() - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, self.Exit): raise - except: + except: res = item.Failed(excinfo=py.code.ExceptionInfo()) else: res = item.Passed() Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Wed Jan 12 16:08:55 2005 @@ -88,7 +88,8 @@ def repr_failure_result(self, res): exprinfo = None - if not self.option.nomagic: + if not self.option.nomagic and \ + not isinstance(res.excinfo.value, SystemExit): try: exprinfo = res.excinfo.reinterpret() # very detailed info except KeyboardInterrupt: From arigo at codespeak.net Wed Jan 12 17:34:08 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 12 Jan 2005 17:34:08 +0100 (MET) Subject: [py-svn] r8238 - in py/dist/py: misc path/local Message-ID: <20050112163408.39FC927BDE@code1.codespeak.net> Author: arigo Date: Wed Jan 12 17:34:08 2005 New Revision: 8238 Added: py/dist/py/misc/buildcmodule.py py/dist/py/misc/stdoutcapture.py - copied unchanged from r8202, py/dist/py/path/local/stdoutcapture.py Removed: py/dist/py/path/local/stdoutcapture.py Modified: py/dist/py/path/local/local.py Log: - moved make_module_from_c() into its own file in misc/ - moved stdoutcapture.py along - save and restore os.environ across calls to distutils It would be even better to fork or use py.execnet to run distutils in its own process... Added: py/dist/py/misc/buildcmodule.py ============================================================================== --- (empty file) +++ py/dist/py/misc/buildcmodule.py Wed Jan 12 17:34:08 2005 @@ -0,0 +1,81 @@ +""" +A utility to build a Python extension module from C, wrapping distutils. +""" +import py + +# XXX we should distutils in a subprocess, because it messes up the +# environment and who knows what else. Currently we just save +# and restore os.environ. + +def make_module_from_c(cfile): + import os, sys, imp + from distutils.core import setup + from distutils.extension import Extension + import stdoutcapture + debug = 0 + + #try: + # from distutils.log import set_threshold + # set_threshold(10000) + #except ImportError: + # print "ERROR IMPORTING" + # pass + + dirpath = cfile.dirpath() + modname = cfile.purebasename + + # find the expected extension of the compiled C module + for ext, mode, filetype in imp.get_suffixes(): + if filetype == imp.C_EXTENSION: + break + else: + raise ValueError, "cannot find the file name suffix of C ext modules" + lib = dirpath.join(modname+ext) + + # argl! we need better "build"-locations alltogether! + if lib.check(): + lib.remove() + + c = stdoutcapture.Capture(mixed_out_err = True) + try: + try: + saved_environ = os.environ.items() + try: + lastdir = dirpath.chdir() + try: + setup( + name = "pylibmodules", + ext_modules=[ + Extension(modname, [str(cfile)]) + ], + script_name = 'setup.py', + script_args = ['-q', 'build_ext', '--inplace'] + #script_args = ['build_ext', '--inplace'] + ) + finally: + lastdir.chdir() + finally: + for key, value in saved_environ: + if os.environ.get(key) != value: + os.environ[key] = value + finally: + foutput, foutput = c.done() + except KeyboardInterrupt: + raise + except SystemExit, e: + raise RuntimeError("cannot compile %s: %s\n%s" % (cfile, e, + foutput.read())) + # XXX do we need to do some check on fout/ferr? + # XXX not a nice way to import a module + if debug: + print "inserting path to sys.path", dirpath + sys.path.insert(0, str(dirpath)) + if debug: + print "import %(modname)s as testmodule" % locals() + exec py.code.compile("import %(modname)s as testmodule" % locals()) + try: + sys.path.remove(str(dirpath)) + except ValueError: + pass + + return testmodule Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Wed Jan 12 17:34:08 2005 @@ -332,6 +332,7 @@ def getpymodule(self): if self.ext != '.c': return super(LocalPath, self).getpymodule() + from py.__impl__.misc.buildcmodule import make_module_from_c mod = make_module_from_c(self) return mod @@ -506,57 +507,3 @@ fdest.close() finally: fsrc.close() - -def make_module_from_c(cfile): - from distutils.core import setup - from distutils.extension import Extension - import stdoutcapture - debug = 0 - - #try: - # from distutils.log import set_threshold - # set_threshold(10000) - #except ImportError: - # print "ERROR IMPORTING" - # pass - - dirpath = cfile.dirpath() - lastdir = dirpath.chdir() - try: - modname = cfile.purebasename - lib = py.path.local(modname+'.so') - # argl! we need better "build"-locations alltogether! - if lib.check(): - lib.remove() - c = stdoutcapture.Capture(mixed_out_err = True) - try: - try: - setup( - name = "pylibmodules", - ext_modules=[ - Extension(modname, [str(cfile)]) - ], - script_name = 'setup.py', - script_args = ['-q', 'build_ext', '--inplace'] - #script_args = ['build_ext', '--inplace'] - ) - finally: - foutput, foutput = c.done() - except KeyboardInterrupt: - raise - except SystemExit: - raise RuntimeError("cannot compile %s:\n%s" % (cfile, foutput.read(),)) - # XXX do we need to do some check on fout/ferr? - # XXX not a nice way to import a module - if debug: - print "inserting path to sys.path", dirpath - sys.path.insert(0, '.') - if debug: - print "import %(modname)s as testmodule" % locals() - exec py.code.compile("import %(modname)s as testmodule" % locals()) - sys.path.pop(0) - finally: - lastdir.chdir() - #if not debug: - #dirpath.rmtree() - return testmodule Deleted: /py/dist/py/path/local/stdoutcapture.py ============================================================================== --- /py/dist/py/path/local/stdoutcapture.py Wed Jan 12 17:34:08 2005 +++ (empty file) @@ -1,73 +0,0 @@ -""" -A quick hack to capture stdout/stderr. -""" - -import os, sys - - -class Capture: - - def __init__(self, mixed_out_err = False): - "Start capture of the Unix-level stdout and stderr." - if (not hasattr(os, 'tmpfile') or - not hasattr(os, 'dup') or - not hasattr(os, 'dup2') or - not hasattr(os, 'fdopen')): - self.dummy = 1 - else: - self.dummy = 0 - # make new stdout/stderr files if needed - self.localoutfd = os.dup(1) - self.localerrfd = os.dup(2) - if hasattr(sys.stdout, 'fileno') and sys.stdout.fileno() == 1: - self.saved_stdout = sys.stdout - sys.stdout = os.fdopen(self.localoutfd, 'w', 1) - else: - self.saved_stdout = None - if hasattr(sys.stderr, 'fileno') and sys.stderr.fileno() == 2: - self.saved_stderr = sys.stderr - sys.stderr = os.fdopen(self.localerrfd, 'w', 0) - else: - self.saved_stderr = None - self.tmpout = os.tmpfile() - if mixed_out_err: - self.tmperr = self.tmpout - else: - self.tmperr = os.tmpfile() - os.dup2(self.tmpout.fileno(), 1) - os.dup2(self.tmperr.fileno(), 2) - - def done(self): - "End capture and return the captured text (stdoutfile, stderrfile)." - if self.dummy: - import cStringIO - return cStringIO.StringIO(), cStringIO.StringIO() - else: - os.dup2(self.localoutfd, 1) - os.dup2(self.localerrfd, 2) - if self.saved_stdout is not None: - f = sys.stdout - sys.stdout = self.saved_stdout - f.close() - else: - os.close(self.localoutfd) - if self.saved_stderr is not None: - f = sys.stderr - sys.stderr = self.saved_stderr - f.close() - else: - os.close(self.localerrfd) - self.tmpout.seek(0) - self.tmperr.seek(0) - return self.tmpout, self.tmperr - - -if __name__ == '__main__': - # test - c = Capture() - try: - os.system('echo hello') - finally: - fout, ferr = c.done() - print 'Output:', `fout.read()` - print 'Error:', `ferr.read()` From hpk at codespeak.net Wed Jan 12 19:06:23 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 12 Jan 2005 19:06:23 +0100 (MET) Subject: [py-svn] r8243 - py/dist/py/path/local Message-ID: <20050112180623.9787427BDE@code1.codespeak.net> Author: hpk Date: Wed Jan 12 19:06:23 2005 New Revision: 8243 Modified: py/dist/py/path/local/local.py Log: ignore permission denied for session-directory-management Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Wed Jan 12 19:06:23 2005 @@ -472,7 +472,7 @@ if num is not None and num <= (maxnum - keep): try: path.remove(rec=1) - except py.error.ENOENT: + except (py.error.ENOENT, py.error.EACCES): pass return udir make_numbered_dir = classmethod(make_numbered_dir) From hpk at codespeak.net Wed Jan 12 19:28:14 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 12 Jan 2005 19:28:14 +0100 (MET) Subject: [py-svn] r8249 - in py/dist/py: execnet path/local Message-ID: <20050112182814.D148727BDE@code1.codespeak.net> Author: hpk Date: Wed Jan 12 19:28:14 2005 New Revision: 8249 Modified: py/dist/py/execnet/register.py py/dist/py/path/local/local.py Log: minor hacks Modified: py/dist/py/execnet/register.py ============================================================================== --- py/dist/py/execnet/register.py (original) +++ py/dist/py/execnet/register.py Wed Jan 12 19:28:14 2005 @@ -67,10 +67,14 @@ def remote_bootstrap_gateway(self, io, extra=''): # XXX the following hack helps us to import the same version - # of the py lib, but only works for PopenGateways - # --> we need proper remote imports working + # of the py lib and other dependcies, but only works for + # PopenGateways because we can assume to have access to + # the same filesystem + # --> we definitely need proper remote imports working # across any kind of gateway! + x = py.path.local(py.__file__).dirpath().dirpath() plist = os.environ.get('PYTHONPATH', '').split(':') + plist.insert(0, str(x)) s = "import sys ; sys.path[:0] = %r" % (plist,) s = "\n".join([extra, s]) super(PopenGateway, self).remote_bootstrap_gateway(io, s) Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Wed Jan 12 19:28:14 2005 @@ -472,7 +472,7 @@ if num is not None and num <= (maxnum - keep): try: path.remove(rec=1) - except (py.error.ENOENT, py.error.EACCES): + except py.error.Error: pass return udir make_numbered_dir = classmethod(make_numbered_dir) From hpk at codespeak.net Sat Jan 15 11:20:33 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 15 Jan 2005 11:20:33 +0100 (MET) Subject: [py-svn] r8286 - py/dist/py/path/svn Message-ID: <20050115102033.06C7427B72@code1.codespeak.net> Author: hpk Date: Sat Jan 15 11:20:32 2005 New Revision: 8286 Modified: py/dist/py/path/svn/svncommon.py Log: a preliminary way to get at revisions Modified: py/dist/py/path/svn/svncommon.py ============================================================================== --- py/dist/py/path/svn/svncommon.py (original) +++ py/dist/py/path/svn/svncommon.py Sat Jan 15 11:20:32 2005 @@ -190,12 +190,12 @@ return tuple(res) - #def _childmaxrev(self): - # """ return maximum revision number of childs (or self.rev if no childs) """ - # rev = self.rev - # for name, info in self._listdir_nameinfo(): - # rev = max(rev, info.created_rev) - # return rev + def _childmaxrev(self): + """ return maximum revision number of childs (or self.rev if no childs) """ + rev = self.rev + for name, info in self._listdir_nameinfo(): + rev = max(rev, info.created_rev) + return rev #def _getlatestrevision(self): # """ return latest repo-revision for this path. """ From hpk at codespeak.net Sat Jan 15 11:26:48 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 15 Jan 2005 11:26:48 +0100 (MET) Subject: [py-svn] r8287 - in py/dist/py: . code code/testing documentation/example/pytest magic test test/report/text Message-ID: <20050115102648.8647B27B72@code1.codespeak.net> Author: hpk Date: Sat Jan 15 11:26:48 2005 New Revision: 8287 Added: py/dist/py/code/traceback.py Modified: py/dist/py/__init__.py py/dist/py/code/excinfo.py py/dist/py/code/testing/test_excinfo.py py/dist/py/code/testing/test_source.py py/dist/py/documentation/example/pytest/failure_demo.py py/dist/py/magic/exprinfo.py py/dist/py/test/raises.py py/dist/py/test/report/text/reporter.py py/dist/py/test/report/text/summary.py Log: major test "reporter" related cleanup. I hope you'll all like it. It gives IMO a _lot_ better error reporting. Please report any glitches. - The higher level introspection py.code.* classes now have a "Traceback" object which is a list of TracebackEntries. This allows to manipulate (cut) tracebacks more easily in order to show relevant portions. - the test summary now is structured more easily (basically you see what happens to show a test failure in summary.py-repr_failure which calls various other repr_* functions in order to display locals, stdout/stderr and whatnot) - traceback hiding of internal functions now happens by just setting __tracebackhide__ = True in functions that you don't want to see in your traceback. --fulltrace disables this behaviour. The py lib currently uses it to hide e.g. a custom import hook when it just defers to the original hook (you can change the value of __tracebackhide__ during the execution of your functions. Modified: py/dist/py/__init__.py ============================================================================== --- py/dist/py/__init__.py (original) +++ py/dist/py/__init__.py Sat Jan 15 11:26:48 2005 @@ -44,7 +44,7 @@ 'code.Code' : ('./code/frame.py', 'Code'), 'code.Frame' : ('./code/frame.py', 'Frame'), 'code.ExceptionInfo' : ('./code/excinfo.py', 'ExceptionInfo'), - 'code.TracebackEntry' : ('./code/excinfo.py', 'TracebackEntry'), + 'code.Traceback' : ('./code/traceback.py', 'Traceback'), 'builtin.enumerate' : ('./builtin/enumerate.py', 'enumerate'), Modified: py/dist/py/code/excinfo.py ============================================================================== --- py/dist/py/code/excinfo.py (original) +++ py/dist/py/code/excinfo.py Sat Jan 15 11:26:48 2005 @@ -6,8 +6,6 @@ """ wraps sys.exc_info() objects and offers help for navigating the traceback. """ - TRACEBACK_HIDE = object() - def __init__(self, tup=None, exprinfo=None): # NB. all attributes are private! Subclasses or other # ExceptionInfo-like classes may have different attributes. @@ -19,8 +17,8 @@ if exprinfo.startswith('assert '): strip = 'AssertionError: ' self._excinfo = tup - self.exprinfo = exprinfo self.type, self.value, tb = self._excinfo + self.traceback = py.code.Traceback(tb) # get the text representation of the exception lines = py.std.traceback.format_exception_only(self.type, self.value) text = ''.join(lines) @@ -33,69 +31,3 @@ def __str__(self): return self.exception_text - def reinterpret(self): - """Reinterpret the failing statement and returns a detailed information - about what operations are performed.""" - if self.exprinfo is None: - from py.__impl__.magic import exprinfo - self.exprinfo = exprinfo.getmsg(self) - return self.exprinfo - - def __iter__(self): - current = self._excinfo[2] - while current is not None: - special = current.tb_frame.f_locals.get('__traceback__') - if special is not self.TRACEBACK_HIDE: - yield TracebackEntry(current) - current = current.tb_next - - def getentries(self, startcondition=None, endcondition=None): - if startcondition is not None and not callable(startcondition): - raise TypeError("%r is not callable or None" % startcondition) - if endcondition is not None and not callable(endcondition): - raise TypeError("%r is not callable or None" % endcondition) - result = [] - gen = iter(self) - for x in gen: - if startcondition is None or startcondition(x): - result.append(x) - break - for x in gen: - result.append(x) - if endcondition is not None and endcondition(x): - break - return result - #entries = list(self) - #gen = py.builtin.enumerate(self) - #if start is not None: - # for i, entry in gen: - # p,l = entry.frame.code.path, entry.frame.code.firstlineno - # if start == i or (p,l) == start: - # break - #res = [] - #for i, entry in gen: - # res.append(entry) - # if end is not None: - # p,l = entry.frame.code.path, entry.frame.code.firstlineno - # if i == end or (p,l) == end: - # break - #return res - -class TracebackEntry(object): - def __init__(self, rawentry): - self._rawentry = rawentry - self.frame = py.code.Frame(rawentry.tb_frame) - self.lineno = rawentry.tb_lineno - 1 - - def statement(self): - source = self.frame.code.fullsource - return source.getstatement(self.lineno) - statement = property(statement, None, None, - "statement of this traceback entry.") - - def path(self): - return self.frame.path - path = property(path, None, None, "path to the full source code") - - def __repr__(self): - return "" %(self.frame.code.path, self.lineno + 1) Modified: py/dist/py/code/testing/test_excinfo.py ============================================================================== --- py/dist/py/code/testing/test_excinfo.py (original) +++ py/dist/py/code/testing/test_excinfo.py Sat Jan 15 11:26:48 2005 @@ -16,12 +16,12 @@ try: f() except ValueError: - info = py.code.ExceptionInfo() - l = list(info) + excinfo = py.code.ExceptionInfo() linenumbers = [f.func_code.co_firstlineno-1+3, f.func_code.co_firstlineno-1+1, g.func_code.co_firstlineno-1+1,] - foundlinenumbers = [x.lineno for x in info] + l = list(excinfo.traceback) + foundlinenumbers = [x.lineno for x in l] print l[0].frame.statement assert foundlinenumbers == linenumbers #for x in info: @@ -36,44 +36,55 @@ def h(): g() -def test_excinfo_getentries_nocut(): - try: - h() - except ValueError: - pass - excinfo = py.code.ExceptionInfo() - entries = excinfo.getentries() - assert len(entries) == 4 # fragile - names = ['f','g','h'] - for entry in entries: +class TestTraceback_f_g_h: + def setup_method(self, method): try: - names.remove(entry.frame.code.name) + h() except ValueError: - pass - assert not names + self.excinfo = py.code.ExceptionInfo() -def test_excinfo_getentries_cut(): - excinfo = py.test.raises(ValueError, h) - entries = excinfo.getentries( - lambda x: x.frame.code.name != 'raises', - lambda x: x.frame.code.name != 'f') - names = [x.frame.code.name for x in entries] - assert names == ['h','g'] - -def test_excinfo_getentries_type_error(): - excinfo = py.test.raises(ValueError, h) - entries = excinfo.getentries( - lambda x: x.frame.code.name != 'raises', - lambda x: x.frame.code.name != 'f') - names = [x.frame.code.name for x in entries] - assert names == ['h','g'] + def test_traceback_entries(self): + tb = self.excinfo.traceback + entries = list(tb) + assert len(tb) == 4 # maybe fragile test + assert len(entries) == 4 # maybe fragile test + names = ['f', 'g', 'h'] + for entry in entries: + try: + names.remove(entry.frame.code.name) + except ValueError: + pass + assert not names + + #def test_traceback_display_func(self): + # tb = self.excinfo.traceback + # for x in tb: + # x.setdisplay(lambda entry: entry.frame.code.name + '\n') + ## l = tb.display().rstrip().split('\n') + # assert l == ['setup_method', 'h', 'g', 'f'] + + +def hello(x): + x + 5 + +def test_tbentry_reinterpret(): + try: + hello("hello") + except TypeError: + excinfo = py.code.ExceptionInfo() + tbentry = excinfo.traceback[-1] + msg = tbentry.reinterpret() + assert msg.startswith("TypeError: ('hello' + 5)") + +#def test_excinfo_getentries_type_error(): +# excinfo = py.test.raises(ValueError, h) +# entries = excinfo.getentries( +# lambda x: x.frame.code.name != 'raises', +# lambda x: x.frame.code.name != 'f') +# names = [x.frame.code.name for x in entries] +# assert names == ['h','g'] def test_excinfo_exception_text(): excinfo = py.test.raises(ValueError, h) assert excinfo.exception_text.startswith('ValueError') -def test_excinfo_reinterpret(): - x = 'foobar' - excinfo = py.test.raises(TypeError, "x+5") - del x - assert excinfo.reinterpret().startswith("TypeError: ('foobar' + 5)") Modified: py/dist/py/code/testing/test_source.py ============================================================================== --- py/dist/py/code/testing/test_source.py (original) +++ py/dist/py/code/testing/test_source.py Sat Jan 15 11:26:48 2005 @@ -148,7 +148,7 @@ exec co except ValueError: excinfo = py.code.ExceptionInfo(py.std.sys.exc_info()) - l = list(excinfo) + l = excinfo.traceback tb = l[0] inner = l[1] print "inner frame-statement:", inner.frame.statement @@ -166,7 +166,7 @@ exec co f(7) excinfo = py.test.raises(AssertionError, "f(6)") - frame = list(excinfo)[-1].frame + frame = excinfo.traceback[-1].frame stmt = frame.code.fullsource.getstatement(frame.lineno) #print "block", str(block) assert str(stmt).strip().startswith('assert') @@ -207,7 +207,7 @@ if teardown: teardown() """) - source = list(excinfo)[-1].statement + source = excinfo.traceback[-1].statement assert str(source).strip() == 'c(1)' def test_getfuncsource_dynamic(): Added: py/dist/py/code/traceback.py ============================================================================== --- (empty file) +++ py/dist/py/code/traceback.py Sat Jan 15 11:26:48 2005 @@ -0,0 +1,69 @@ +from __future__ import generators +import py + +class TracebackEntry(object): + exprinfo = None + + def __init__(self, rawentry): + self._rawentry = rawentry + self.frame = py.code.Frame(rawentry.tb_frame) + self.lineno = rawentry.tb_lineno - 1 + + def __repr__(self): + return "" %(self.frame.code.path, self.lineno+1) + + def statement(self): + source = self.frame.code.fullsource + return source.getstatement(self.lineno) + statement = property(statement, None, None, + "statement of this traceback entry.") + + def path(self): + return self.frame.code.path + path = property(path, None, None, "path to the full source code") + + def reinterpret(self): + """Reinterpret the failing statement and returns a detailed information + about what operations are performed.""" + if self.exprinfo is None: + from py.__impl__.magic import exprinfo + source = str(self.statement).strip() + x = exprinfo.interpret(source, self.frame, should_fail=True) + if not isinstance(x, str): + raise TypeError, "interpret returned non-string %r" % (x,) + self.exprinfo = x + return self.exprinfo + + def getsource(self): + """ return failing source code. """ + source = self.frame.code.fullsource + start, end = self.frame.code.firstlineno, self.lineno + _, end = source.getstatementrange(end) + return source[start:end] + + def __str__(self): + try: + fn = str(self.path) + except py.error.Error: + fn = '???' + name = self.frame.code.name + line = str(self.statement).lstrip() + return " File %r:%d in %s\n %s\n" %(fn, self.lineno+1, name, line) + +class Traceback(list): + 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)) + +# def __str__(self): +# for x in self +# l = [] +## for func, entry in self._tblist: +# l.append(entry.display()) +# return "".join(l) + Modified: py/dist/py/documentation/example/pytest/failure_demo.py ============================================================================== --- py/dist/py/documentation/example/pytest/failure_demo.py (original) +++ py/dist/py/documentation/example/pytest/failure_demo.py Sat Jan 15 11:26:48 2005 @@ -7,6 +7,10 @@ def somefunc(x,y): otherfunc(x,y) +def otherfunc_multi(a,b): + assert (a == + b) + class TestFailing(object): def test_simple(self): def f(): @@ -16,6 +20,11 @@ assert f() == g() + def test_simple_multiline(self): + otherfunc_multi( + 42, + 6*9) + def test_not(self): def f(): return 42 @@ -109,6 +118,3 @@ def globf(x): return x+1 - -def test_systemexit_doesnt_leave(): - raise SystemExit Modified: py/dist/py/magic/exprinfo.py ============================================================================== --- py/dist/py/magic/exprinfo.py (original) +++ py/dist/py/magic/exprinfo.py Sat Jan 15 11:26:48 2005 @@ -420,7 +420,7 @@ #frame = py.code.Frame(frame) #return interpret(line, frame) - tb = list(excinfo)[-1] + tb = excinfo.traceback[-1] source = str(tb.statement).strip() x = interpret(source, tb.frame, should_fail=True) if not isinstance(x, str): Modified: py/dist/py/test/raises.py ============================================================================== --- py/dist/py/test/raises.py (original) +++ py/dist/py/test/raises.py Sat Jan 15 11:26:48 2005 @@ -7,6 +7,7 @@ exception. """ assert args + __tracebackhide__ = True if isinstance(args[0], str): expr, = args assert isinstance(expr, str) @@ -16,9 +17,8 @@ #print "raises frame scope: %r" % frame.f_locals source = py.code.Source(expr) try: - __traceback__ = py.code.ExceptionInfo.TRACEBACK_HIDE eval(source.compile(), frame.f_globals, loc) - del __traceback__ + #del __traceback__ # XXX didn'T mean f_globals == f_locals something special? # this is destroyed here ... except ExpectedException: @@ -29,14 +29,12 @@ func = args[0] assert callable try: - __traceback__ = py.code.ExceptionInfo.TRACEBACK_HIDE func(*args[1:], **kwargs) - del __traceback__ + #del __traceback__ except ExpectedException: return py.code.ExceptionInfo() k = ", ".join(["%s=%r" % x for x in kwargs.items()]) if k: k = ', ' + k expr = '%s(%r%s)' %(func.__name__, args, k) - raise ExceptionFailure(expr=args, expected=ExpectedException, - tbindex = -2) + raise ExceptionFailure(expr=args, expected=ExpectedException) Modified: py/dist/py/test/report/text/reporter.py ============================================================================== --- py/dist/py/test/report/text/reporter.py (original) +++ py/dist/py/test/report/text/reporter.py Sat Jan 15 11:26:48 2005 @@ -185,7 +185,7 @@ if writeinfo is not None: #exc, frame, filename,lineno = self.summary.getexinfo(error) - tbentries = list(error.excinfo) + tbentries = error.excinfo.traceback filename = tbentries[-1].frame.code.path lineno = tbentries[-1].lineno self.out.line('CollectError: %s:%d' % (filename, lineno) ) Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Sat Jan 15 11:26:48 2005 @@ -19,18 +19,8 @@ self.out.sep("_") self.out.sep("_", "Collect Error") self.out.line() - self.repr_traceback_raw(error.excinfo.getentries()) - #self.repr_failure_result(res) - #self.out.line() - #if isinstance(res.excinfo[1], AssertionError): - # from std.utest.tool import hackexpr - # res.msg = "failed: " + hackexpr.getmsg(res.excinfo) - self.out.line(error.excinfo) - - #if self.option.showlocals: - # self.out.sep('- ', 'locals') - # for name, value in frame.f_locals.items(): - # self.out.line("%-10s = %r" %(name, value)) + self.repr_failure(error.excinfo) + def summary_collect_errors(self): for error in self.getlist(py.test.collect.Error): self.repr_collect_error(error) @@ -56,7 +46,7 @@ d = {} for res in self.getlist(Item.Skipped): tbindex = getattr(res, 'tbindex', -1) - raisingtb = list(res.excinfo)[tbindex] + raisingtb = res.excinfo.traceback[tbindex] fn = raisingtb.frame.code.path lineno = raisingtb.lineno d[(fn,lineno)] = res @@ -68,17 +58,102 @@ self.out.line() def failures(self): - for res in self.getlist(Item.Failed): - self.repr_failure(res) + l = self.getlist(Item.Failed) + if l: + self.out.sep('_') + for res in self.getlist(Item.Failed): + self.repr_failure(res.excinfo, res) + + def repr_failure(self, excinfo, res=None): + traceback = excinfo.traceback + if res: + self.cut_traceback(traceback, res.item) + last = traceback[-1] + for entry in traceback: + self.out.line("") + if entry == last: + indent = self.repr_source(entry, 'E') + self.repr_failure_explanation(excinfo, indent) + else: + self.repr_source(entry, '>') + self.out.line("") + self.out.line("[%s:%d]" %(entry.frame.code.path, entry.lineno+1)) + self.repr_locals(entry) + if res: + self.repr_out_err(res) + if entry == last: + self.out.sep("_") + else: + self.out.sep("_ ") + + def repr_source(self, entry, marker=">"): + 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 - def repr_failure(self, res): - self.out.line() - self.out.sep("_") - #self.out.line() - self.repr_traceback(res.item, res.excinfo, - getattr(res, 'tbindex', -1)) - #self.out.line() - self.repr_failure_result(res) + def cut_traceback(self, traceback, item=None, tbindex=None): + if self.option.fulltrace or item is None: + return + path, lineno = item.extpy.getfilelineno() + for i, entry in py.builtin.enumerate(traceback): + if entry.frame.code.path == path and \ + entry.frame.code.firstlineno == lineno: + del traceback[:i] + break + # get rid of all frames marked with __tracebackhide__ + l = [] + for entry in traceback: + try: + x = entry.frame.eval("__tracebackhide__") + except: + x = None + if not x: + l.append(entry) + traceback[:] = l + #if tbindex is not None and tbindex < -1: + # del traceback[tbindex:] + + def repr_failure_explanation(self, excinfo, indent): + info = None + if not self.option.nomagic: + try: + info = excinfo.traceback[-1].reinterpret() # very detailed info + except KeyboardInterrupt: + raise + except: + if self.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]") + indent = " " * indent + if info is None: + info = str(excinfo) + + 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, res): for name in 'out', 'err': if hasattr(res, name): out = getattr(res, name) @@ -86,97 +161,24 @@ self.out.sep("- ", "recorded std%s" % name) self.out.line(out.strip()) - def repr_failure_result(self, res): - exprinfo = None - if not self.option.nomagic and \ - not isinstance(res.excinfo.value, SystemExit): - try: - exprinfo = res.excinfo.reinterpret() # very detailed info - except KeyboardInterrupt: - raise - except: - if self.option.verbose > 1: - self.out.line("reinterpretation traceback") - py.std.traceback.print_exc() + def repr_locals(self, entry): + if self.option.showlocals: + self.out.sep('- ', 'locals') + for name, value in entry.frame.f_locals.items(): + if len(repr(value)) < 70 or not isinstance(value, + (list, tuple, dict)): + self.out.line("%-10s = %r" %(name, value)) else: - self.out.line("(reinterpretation failed, " - "you may increase " - "verbosity to see details)") - self.out.line(exprinfo or res.excinfo) + self.out.line("%-10s =\\" % (name,)) + py.std.pprint.pprint(value, stream=self.out) - def repr_source(self, tb): - # represent source code for a given traceback entry - self.out.line() - try: - source = tb.frame.code.fullsource - except py.error.ENOENT: - self.out.line("failure to get at sourcelines from %r" % tb) - #self.out.line("(co_filename = %r)" % (frame.f_code.co_filename)) - #self.out.line("(f_lineno = %r)" % (frame.f_lineno)) - return - start = tb.frame.code.firstlineno - end = tb.lineno - - for line in source[start:end]: - self.out.line(line.rstrip()) - line = source[end] - if line.startswith(" "): - line = line[1:] # to avoid the indentation caused by ">" - self.out.line(">" + line) - return - - def cut_traceback(self, excinfo, item=None, tbindex=None): - if self.option.fulltrace or item is None: - startcondition = endcondition = None - else: - path,lineno = item.extpy.getfilelineno() - def startcondition(entry): - return entry.frame.code.path == path and \ - entry.frame.code.firstlineno == lineno - endcondition = None - entries = excinfo.getentries(startcondition, endcondition) - # XXX the cutting logic needs refactoring with respect - # to generative tests (which will not have the - # test item in their tb-path) - # - if not entries: - entries = excinfo.getentries() - if tbindex is not None and tbindex < -1: - entries = entries[:tbindex+1] - return entries - - def repr_traceback(self, item, excinfo, tbindex=None): - tbentries = self.cut_traceback(excinfo, item, tbindex) - self.repr_traceback_raw(tbentries) - self.out.sep('-') - - def repr_traceback_raw(self, tbentries): + def Xrepr_traceback_raw(self, traceback): recursioncache = {} - first = True for tb in tbentries: if first: first = False else: self.out.sep('-') - path = tb.frame.code.path - lineno = tb.lineno - name = tb.frame.code.name - showfn = path - #showfn = filename.split(os.sep) - #if len(showfn) > 5: - # showfn = os.sep.join(['...'] + showfn[-5:]) - self.repr_source(tb) - self.out.line("") - self.out.line("[%s:%d]" %(showfn, lineno+1)) # , name)) - if self.option.showlocals: - self.out.sep('- ', 'locals') - for name, value in tb.frame.f_locals.items(): - if 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) #self.out.line("%-10s = %r" %(name, value)) key = (path, lineno) if key not in recursioncache: From hpk at codespeak.net Sat Jan 15 11:59:21 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 15 Jan 2005 11:59:21 +0100 (MET) Subject: [py-svn] r8289 - py/dist/py/path Message-ID: <20050115105921.3453A27B84@code1.codespeak.net> Author: hpk Date: Sat Jan 15 11:59:20 2005 New Revision: 8289 Modified: py/dist/py/path/common.py Log: hide the custom import hook in test-tracebacks if the hook defers to the original ... Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Sat Jan 15 11:59:20 2005 @@ -356,6 +356,7 @@ old_import_hook = None def custom_import_hook(name, glob=None, loc=None, fromlist=None): + __tracebackhide__ = False __file__ = glob and glob.get('__file__') if isinstance(__file__, PathStr): # try to perform a relative import @@ -379,4 +380,5 @@ else: return modules[0] # outermost package # fall-back + __tracebackhide__ = True return old_import_hook(name, glob, loc, fromlist) From hpk at codespeak.net Sat Jan 15 14:11:04 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 15 Jan 2005 14:11:04 +0100 (MET) Subject: [py-svn] r8296 - in py/dist/py/path: . extpy local svn test Message-ID: <20050115131104.38DC527B88@code1.codespeak.net> Author: hpk Date: Sat Jan 15 14:11:04 2005 New Revision: 8296 Modified: py/dist/py/path/common.py py/dist/py/path/extpy/extpy.py py/dist/py/path/local/local.py py/dist/py/path/svn/svncommon.py py/dist/py/path/svn/wccommand.py py/dist/py/path/test/common.py Log: - unified relto() handling (triggered by Armin's complaint on py-dev :-) - came up with a new format for py.path.extpy paths: /path/to/file.py/.some.module.path.inside - fixed some tests to not check for exact str(path) formatting. Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Sat Jan 15 14:11:04 2005 @@ -109,6 +109,19 @@ return self.get('basename')[0] basename = property(basename, None, None, 'basename part of path') + def relto(self, relpath): + """ return a string which is the relative part of the path + to the given 'relpath'. + """ + strrelpath = str(relpath) + if strrelpath and strrelpath[-1] != self.sep: + strrelpath += self.sep + strself = str(self) + print "%r relto %r" %(strself, strrelpath) + if strself.startswith(strrelpath): + return strself[len(strrelpath):] + return "" + def parts(self, reverse=False): """ return a root-first list of all ancestor directories plus the path itself. Modified: py/dist/py/path/extpy/extpy.py ============================================================================== --- py/dist/py/path/extpy/extpy.py (original) +++ py/dist/py/path/extpy/extpy.py Sat Jan 15 14:11:04 2005 @@ -15,14 +15,16 @@ """ path object for addressing python objects. """ sep = '.' def __new__(cls, root, modpath=''): - if isinstance(root, str): - root = py.path.local(root) - #root = py.path.local(root) - #raise TypeError("first root argument is not resolvable") if not isinstance(modpath, str): raise TypeError("second 'modpath' argument must be a dotted name.") - #assert not isinstance(root, Extpy) + if isinstance(root, str): + root = py.path.local(root) + self = object.__new__(cls) + if isinstance(root, Extpy): + # we don't want it nested, do we? + assert not modpath + root = root.root self.modpath = modpath self.root = root return self @@ -34,7 +36,7 @@ return 'extpy(%r, %r)' % (self.root, self.modpath) def __str__(self): - return str(self.root.new(ext=self.modpath)) + return "%s%s.%s" %(self.root, self.root.sep, self.modpath) def join(self, *args): for arg in args: @@ -44,6 +46,11 @@ modpath = self.sep.join(modpath) return self.__class__(self.root, modpath) + def relto(self, other): + if self.root != other.root: + return '' + return super(Extpy, self).relto(other) + def dirpath(self, *args): modpath = self.modpath.split(self.sep) [:-1] modpath = self.sep.join(modpath+list(args)) @@ -92,13 +99,6 @@ else: return self.root.getpymodule() - def relto(self, otherpath): - if self.root == otherpath.root: - if self.modpath.startswith(otherpath.modpath): - s = self.modpath[len(otherpath.modpath):] - return s.lstrip(self.sep) - return '' - def listobj(self, fil=None, **kw): l = [] for x in self.listdir(fil, **kw): Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Sat Jan 15 14:11:04 2005 @@ -197,15 +197,6 @@ """ return last modification time of the path. """ return self.stat().st_mtime - def relto(self, relpath): - """ return a string which is the relative part of the path - to the given 'relpath' (which might be a string or a path object). - """ - relpath = str(relpath) - if self.strpath.startswith(relpath): - return self.strpath[len(relpath)+(relpath[-1:] != self.sep):] - return "" - def remove(self, rec=1): """ remove a file or directory (or a directory tree if rec=1). """ if self.check(dir=1, link=0): Modified: py/dist/py/path/svn/svncommon.py ============================================================================== --- py/dist/py/path/svn/svncommon.py (original) +++ py/dist/py/path/svn/svncommon.py Sat Jan 15 14:11:04 2005 @@ -166,17 +166,6 @@ """ Return the last modification time of the file. """ return self.info().mtime - def relto(self, rel): - """ Return a string which is the relative part of the Path to 'rel'. - - If the Path is not relative to the given base, return an empty string. - """ - relpath = rel.strpath - if self.strpath.startswith(relpath): - return self.strpath[len(relpath)+1:] - return "" - - # shared help methods def _make_path_tuple(self, nameinfo_seq): Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Sat Jan 15 14:11:04 2005 @@ -393,17 +393,6 @@ """ Return the last modification time of the file. """ return self.info().mtime - def relto(self, rel): - """ Return a string which is the relative part of the Path to 'rel'. - - If the Path is not relative to the given base, return an empty string. - """ - - relpath = rel.strpath - if self.strpath.startswith(relpath): - return self.strpath[len(relpath)+1:] - return "" - def __hash__(self): return hash((self.strpath, self.__class__)) Modified: py/dist/py/path/test/common.py ============================================================================== --- py/dist/py/path/test/common.py (original) +++ py/dist/py/path/test/common.py Sat Jan 15 14:11:04 2005 @@ -18,13 +18,19 @@ def test_join(self): p = self.root.join('sampledir') - assert str(p) == self.root.sep.join([str(self.root), 'sampledir']) + strp = str(p) + assert strp.endswith('sampledir') + assert strp.startswith(str(self.root)) def test_join_normalized(self): newpath = self.root.join(self.root.sep+'sampledir') - assert str(newpath) == self.root.sep.join([str(self.root), 'sampledir']) + strp = str(newpath) + assert strp.endswith('sampledir') + assert strp.startswith(str(self.root)) newpath = self.root.join((self.root.sep*2) + 'sampledir') - assert str(newpath) == self.root.sep.join([str(self.root), 'sampledir']) + strp = str(newpath) + assert strp.endswith('sampledir') + assert strp.startswith(str(self.root)) def test_join_noargs(self): newpath = self.root.join() @@ -119,9 +125,10 @@ assert not self.root.check(relto=l) def test_relto_not_relative(self): - l1=self.root.join("sampledir") - l2=self.root.join("samplefile") + l1=self.root.join("bcde") + l2=self.root.join("b") assert not l1.relto(l2) + assert not l2.relto(l1) def test_listdir(self): l = self.root.listdir() From hpk at codespeak.net Sat Jan 15 14:12:02 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 15 Jan 2005 14:12:02 +0100 (MET) Subject: [py-svn] r8297 - py/dist/py/path Message-ID: <20050115131202.0A09F27B88@code1.codespeak.net> Author: hpk Date: Sat Jan 15 14:12:01 2005 New Revision: 8297 Modified: py/dist/py/path/common.py Log: aehem Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Sat Jan 15 14:12:01 2005 @@ -117,7 +117,6 @@ if strrelpath and strrelpath[-1] != self.sep: strrelpath += self.sep strself = str(self) - print "%r relto %r" %(strself, strrelpath) if strself.startswith(strrelpath): return strself[len(strrelpath):] return "" From hpk at codespeak.net Sat Jan 15 14:49:32 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 15 Jan 2005 14:49:32 +0100 (MET) Subject: [py-svn] r8298 - in py/dist/py: magic test/tool test/tool/testing Message-ID: <20050115134932.C7C4A27B88@code1.codespeak.net> Author: hpk Date: Sat Jan 15 14:49:32 2005 New Revision: 8298 Removed: py/dist/py/magic/stdoutcapture.py Modified: py/dist/py/test/tool/outerrcapture.py py/dist/py/test/tool/testing/test_outerrcapture.py Log: improved simple stdout/stderr handling removed duplicate file Deleted: /py/dist/py/magic/stdoutcapture.py ============================================================================== --- /py/dist/py/magic/stdoutcapture.py Sat Jan 15 14:49:32 2005 +++ (empty file) @@ -1,71 +0,0 @@ -""" -A quick hack to capture stdout/stderr. -""" - -import os, sys - -class Capture: - def __init__(self, mixed_out_err = False): - "Start capture of the Unix-level stdout and stderr." - if (not hasattr(os, 'tmpfile') or - not hasattr(os, 'dup') or - not hasattr(os, 'dup2') or - not hasattr(os, 'fdopen')): - self.dummy = 1 - else: - self.dummy = 0 - # make new stdout/stderr files if needed - self.localoutfd = os.dup(1) - self.localerrfd = os.dup(2) - if hasattr(sys.stdout, 'fileno') and sys.stdout.fileno() == 1: - self.saved_stdout = sys.stdout - sys.stdout = os.fdopen(self.localoutfd, 'w', 1) - else: - self.saved_stdout = None - if hasattr(sys.stderr, 'fileno') and sys.stderr.fileno() == 2: - self.saved_stderr = sys.stderr - sys.stderr = os.fdopen(self.localerrfd, 'w', 0) - else: - self.saved_stderr = None - self.tmpout = os.tmpfile() - if mixed_out_err: - self.tmperr = self.tmpout - else: - self.tmperr = os.tmpfile() - os.dup2(self.tmpout.fileno(), 1) - os.dup2(self.tmperr.fileno(), 2) - - def done(self): - "End capture and return the captured text (stdoutfile, stderrfile)." - if self.dummy: - import cStringIO - return cStringIO.StringIO(), cStringIO.StringIO() - else: - os.dup2(self.localoutfd, 1) - os.dup2(self.localerrfd, 2) - if self.saved_stdout is not None: - f = sys.stdout - sys.stdout = self.saved_stdout - f.close() - else: - os.close(self.localoutfd) - if self.saved_stderr is not None: - f = sys.stderr - sys.stderr = self.saved_stderr - f.close() - else: - os.close(self.localerrfd) - self.tmpout.seek(0) - self.tmperr.seek(0) - return self.tmpout, self.tmperr - - -if __name__ == '__main__': - # test - c = Capture() - try: - os.system('echo hello') - finally: - fout, ferr = c.done() - print 'Output:', `fout.read()` - print 'Error:', `ferr.read()` Modified: py/dist/py/test/tool/outerrcapture.py ============================================================================== --- py/dist/py/test/tool/outerrcapture.py (original) +++ py/dist/py/test/tool/outerrcapture.py Sat Jan 15 14:49:32 2005 @@ -16,15 +16,14 @@ def __init__(self): self.oldout = sys.stdout self.olderr = sys.stderr - sys.stdout = StringIO() - sys.stderr = StringIO() - + sys.stdout = self.newout = StringIO() + sys.stderr = self.newerr = StringIO() def reset(self): """ return captured output and restore sys.stdout/err.""" o,e = sys.stdout, sys.stderr sys.stdout, sys.stderr = self.oldout, self.olderr del self.oldout, self.olderr - out = o.getvalue() - err = e.getvalue() + out = self.newout.getvalue() + err = self.newerr.getvalue() return out, err Modified: py/dist/py/test/tool/testing/test_outerrcapture.py ============================================================================== --- py/dist/py/test/tool/testing/test_outerrcapture.py (original) +++ py/dist/py/test/tool/testing/test_outerrcapture.py Sat Jan 15 14:49:32 2005 @@ -1,5 +1,5 @@ import sys -from py import test +import py from py.__impl__.test.tool.outerrcapture import SimpleOutErrCapture def test_capturing_simple(): @@ -10,15 +10,31 @@ assert out == "hello world\n" assert err == "hello error\n" -def test_capturing_error(): +def test_capturing_twice_error(): cap = SimpleOutErrCapture() print "hello" cap.reset() - test.raises(AttributeError, "cap.reset()") + py.test.raises(AttributeError, "cap.reset()") + +def test_capturing_modify_sysouterr_in_between(): + oldout = sys.stdout + olderr = sys.stderr + cap = SimpleOutErrCapture() + print "hello", + print >>sys.stderr, "world", + sys.stdout = py.std.StringIO.StringIO() + sys.stderr = py.std.StringIO.StringIO() + print "not seen" + print >>sys.stderr, "not seen" + out, err = cap.reset() + assert out == "hello" + assert err == "world" + assert sys.stdout == oldout + assert sys.stderr == olderr def test_capturing_error_recursive(): cap = SimpleOutErrCapture() cap2 = SimpleOutErrCapture() print "hello" cap2.reset() - test.raises(AttributeError, "cap2.reset()") + py.test.raises(AttributeError, "cap2.reset()") From hpk at codespeak.net Sat Jan 15 20:50:42 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 15 Jan 2005 20:50:42 +0100 (MET) Subject: [py-svn] r8299 - py/dist/py/test/report/text Message-ID: <20050115195042.7C35E27B99@code1.codespeak.net> Author: hpk Date: Sat Jan 15 20:50:42 2005 New Revision: 8299 Modified: py/dist/py/test/report/text/reporter.py Log: fix Modified: py/dist/py/test/report/text/reporter.py ============================================================================== --- py/dist/py/test/report/text/reporter.py (original) +++ py/dist/py/test/report/text/reporter.py Sat Jan 15 20:50:42 2005 @@ -162,7 +162,7 @@ if self.option.usepdb: if (issubclass(restype, Collector.Error) or issubclass(restype, Item.Failed)): - self.summary.repr_failure(result) + self.summary.repr_failure(result.excinfo) import pdb self.out.rewrite( '\n%s: %s\n' From hpk at codespeak.net Sun Jan 16 10:02:50 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 10:02:50 +0100 (MET) Subject: [py-svn] r8301 - in py/dist/py/execnet: . bin testing Message-ID: <20050116090250.C5C5B27BAC@code1.codespeak.net> Author: hpk Date: Sun Jan 16 10:02:50 2005 New Revision: 8301 Modified: py/dist/py/execnet/bin/startserver.py py/dist/py/execnet/channel.py py/dist/py/execnet/gateway.py py/dist/py/execnet/inputoutput.py py/dist/py/execnet/message.py py/dist/py/execnet/register.py py/dist/py/execnet/testing/test_gateway.py Log: refactoring of execnet, now in gateway there is a NamedThreadPool which manages the sender/receiver/worker threads more cleanly. Various fixes here and there. It seems that things start to work for Win32 (the tests pass, the socketserver one is disabled as it hangs and i don't know why yet). Modified: py/dist/py/execnet/bin/startserver.py ============================================================================== --- py/dist/py/execnet/bin/startserver.py (original) +++ py/dist/py/execnet/bin/startserver.py Sun Jan 16 10:02:50 2005 @@ -15,29 +15,33 @@ f = open('/tmp/execnet-socket-pyout.log', 'a', 0) old = sys.stdout, sys.stderr sys.stdout = sys.stderr = f + #import py + #compile = py.code.compile def execloop(serversock): - while 1: + print progname, 'Entering Accept loop', serversock.getsockname() + clientsock,address = serversock.accept() + print progname, 'got new connection from %s %s' % address + clientfile = clientsock.makefile('r+b',0) + print "reading line" + source = clientfile.readline() + clientfile.close() + g = {'clientsock' : clientsock, 'address' : address} + source = eval(source) + if source: + co = compile(source+'\n', source, 'exec') + print progname, 'compiled source, executing' try: - print progname, 'Entering Accept loop', serversock.getsockname() - clientsock,address = serversock.accept() - print progname, 'got new connection from %s %s' % address - clientfile = clientsock.makefile('r+b',0) - print "reading line" - source = clientfile.readline() - clientfile.close() - g = {'clientsock' : clientsock, 'address' : address} - source = eval(source) - if not source: - break - co = compile(source+'\n', source, 'exec') - print progname, 'compiled source, executing' - try: - exec co in g - finally: - print progname, 'finished executing code' - except (SystemExit, KeyboardInterrupt): - break + exec co in g + finally: + print progname, 'finished executing code' + #except: + # if debug: + # import py + # excinfo = py.code.ExceptionInfo() + # #print excinfo.traceback + # #print excinfo + #except: # import traceback # traceback.print_exc() @@ -47,6 +51,7 @@ host, port = hostport.split(':') hostport = (host, int(port)) serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversock.bind(hostport) serversock.listen(5) return serversock Modified: py/dist/py/execnet/channel.py ============================================================================== --- py/dist/py/execnet/channel.py (original) +++ py/dist/py/execnet/channel.py Sun Jan 16 10:02:50 2005 @@ -88,6 +88,7 @@ """ x = self._items.get() if isinstance(x, EOFError): + self._items.put(x) raise x return x Modified: py/dist/py/execnet/gateway.py ============================================================================== --- py/dist/py/execnet/gateway.py (original) +++ py/dist/py/execnet/gateway.py Sun Jan 16 10:02:50 2005 @@ -15,7 +15,7 @@ assert Message and ChannelFactory, "Import/Configuration Error" import os -debug = 0 # open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') +debug = 0 # or open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') sysex = (KeyboardInterrupt, SystemExit) @@ -31,6 +31,44 @@ def __repr__(self): return "%s: %s" %(self.__class__.__name__, self.formatted) +class NamedThreadPool: + def __init__(self, **kw): + self._namedthreads = {} + for name, value in kw.items(): + self.start(name, value) + + def __repr__(self): + return "" %(self._namedthreads) + + def get(self, name=None): + if name is None: + l = [] + for x in self._namedthreads.values(): + l.extend(x) + return l + else: + return self._namedthreads.get(name, []) + + def getstarted(self, name=None): + return [t for t in self.get(name) if t.isAlive()] + + def prunestopped(self, name=None): + if name is None: + for name in self.names(): + self.prunestopped(name) + else: + self._namedthreads[name] = self.getstarted(name) + + def names(self): + return self._namedthreads.keys() + + def start(self, name, func): + l = self._namedthreads.setdefault(name, []) + thread = threading.Thread(name="%s%d" % (name, len(l)), + target=func) + thread.start() + l.append(thread) + class Gateway(object): num_worker_threads = 2 RemoteError = RemoteError @@ -41,47 +79,40 @@ self._outgoing = Queue.Queue() self.channelfactory = ChannelFactory(self, startcount) self._exitlock = threading.Lock() - self.iothreads = [ - threading.Thread(target=self.thread_receiver, name='receiver'), - threading.Thread(target=self.thread_sender, name='sender'), - ] - self.workerthreads = w = [] + self.pool = NamedThreadPool(receiver = self.thread_receiver, + sender = self.thread_sender) for x in range(self.num_worker_threads): - w.append(threading.Thread(target=self.thread_executor, - name='executor %d' % x)) - for x in self.iothreads + w: - x.start() + self.pool.start('executor', self.thread_executor) if not _gateways: atexit.register(cleanup_atexit) _gateways.append(self) + def __repr__(self): + R = len(self.pool.getstarted('receiver')) + S = len(self.pool.getstarted('sender')) + i = len(self.channelfactory.values()) + return "<%s %d/%d (%d active channels)>" %(self.__class__.__name__, + R, S, i) + def _stopexec(self): - if self.workerthreads: - for x in self.workerthreads: - self._execqueue.put(None) - for x in self.workerthreads: - if x.isAlive(): - self.trace("joining %r" % x) - x.join() - self.workerthreads[:] = [] - self.trace("workerthreads are empty now") + self.pool.prunestopped() + for x in self.pool.getstarted('executor'): + self._execqueue.put(None) def exit(self): self._exitlock.acquire() try: - #for channel in self.channelfactory.values(): - # channel.close() - if self.workerthreads: - self._stopexec() + self._stopexec() + if self.pool.getstarted('sender'): self._outgoing.put(Message.EXIT_GATEWAY()) - return True + #self.join() finally: self._exitlock.release() def join(self): current = threading.currentThread() - for x in self.iothreads: - if x != current and x.isAlive(): + for x in self.pool.getstarted(): + if x != current: self.trace("joining %s" % x) x.join() @@ -114,7 +145,7 @@ raise except: self.traceex(sys.exc_info()) - break + break finally: self.trace('leaving %r' % threading.currentThread()) @@ -175,7 +206,14 @@ executing 'source' code which will have a corresponding 'channel' object in its executing namespace. """ - source = str(Source(source)) + try: + source = str(Source(source)) + except NameError: + try: + import py + source = str(py.code.Source(source)) + except ImportError: + pass channel = self.channelfactory.new() self._outgoing.put(Message.CHANNEL_OPEN(channel.id, source)) return channel Modified: py/dist/py/execnet/inputoutput.py ============================================================================== --- py/dist/py/execnet/inputoutput.py (original) +++ py/dist/py/execnet/inputoutput.py Sun Jan 16 10:02:50 2005 @@ -9,11 +9,11 @@ server_stmt = """ io = SocketIO(clientsock) import sys -try: - sys.stdout = sys.stderr = open('/tmp/execnet-socket-debug.log', 'a', 0) -except (IOError, OSError): - sys.stdout = sys.stderr = open('/dev/null', 'w') -print '='*60 +#try: +# sys.stdout = sys.stderr = open('/tmp/execnet-socket-debug.log', 'a', 0) +#except (IOError, OSError): +# sys.stdout = sys.stderr = open('/dev/null', 'w') +#print '='*60 """ error = (socket.error, EOFError) @@ -52,13 +52,14 @@ class Popen2IO: server_stmt = """ -import sys +import sys, StringIO io = Popen2IO(sys.stdout, sys.stdin) -try: - sys.stdout = sys.stderr = open('/tmp/execnet-popen-debug.log', 'a', 0) -except (IOError, OSError): - sys.stdout = sys.stderr = open('/dev/null', 'w') -print '='*60 +sys.stdout = sys.stderr = StringIO.StringIO() +#try: +# sys.stdout = sys.stderr = open('/tmp/execnet-popen-debug.log', 'a', 0) +#except (IOError, OSError): +# sys.stdout = sys.stderr = open('/dev/null', 'w') +#print '='*60 """ error = (IOError, OSError, EOFError) Modified: py/dist/py/execnet/message.py ============================================================================== --- py/dist/py/execnet/message.py (original) +++ py/dist/py/execnet/message.py Sun Jan 16 10:02:50 2005 @@ -63,14 +63,17 @@ # class EXIT_GATEWAY(Message): def received(self, gateway): + # executes in receiver thread gateway._stopexec() gateway._outgoing.put(self.STOP_RECEIVING()) for x in gateway.channelfactory.values(): x._close() raise SystemExit def post_sent(self, gateway, excinfo=None): + # executes in sender thread gateway.io.close_write() raise SystemExit + class STOP_RECEIVING(Message): def received(self, gateway): # note that we don't need to close io.close_read() @@ -104,6 +107,7 @@ def received(self, gateway): channel = gateway.channelfactory[self.channelid] channel._close() + class CHANNEL_CLOSE_ERROR(Message): def received(self, gateway): channel = gateway.channelfactory[self.channelid] Modified: py/dist/py/execnet/register.py ============================================================================== --- py/dist/py/execnet/register.py (original) +++ py/dist/py/execnet/register.py Sun Jan 16 10:02:50 2005 @@ -48,8 +48,8 @@ if not super(PopenCmdGateway, self).exit(): return try: - pid = self._pidchannel.receive() self._pidchannel.waitclose(timeout=0.5) + pid = self._pidchannel.receive() except IOError: self.trace("could not receive child PID") else: @@ -73,10 +73,13 @@ # --> we definitely need proper remote imports working # across any kind of gateway! x = py.path.local(py.__file__).dirpath().dirpath() - plist = os.environ.get('PYTHONPATH', '').split(':') - plist.insert(0, str(x)) - s = "import sys ; sys.path[:0] = %r" % (plist,) - s = "\n".join([extra, s]) + ppath = os.environ.get('PYTHONPATH', '') + plist = [str(x)] + ppath.split(':') + s = "\n".join([extra, + "import sys ; sys.path[:0] = %r" % (plist,), + "import os ; os.environ['PYTHONPATH'] = %r" % ppath, + "" + ]) super(PopenGateway, self).remote_bootstrap_gateway(io, s) class SocketGateway(InstallableGateway): Modified: py/dist/py/execnet/testing/test_gateway.py ============================================================================== --- py/dist/py/execnet/testing/test_gateway.py (original) +++ py/dist/py/execnet/testing/test_gateway.py Sun Jan 16 10:02:50 2005 @@ -58,7 +58,8 @@ class BasicRemoteExecution: def test_correct_setup(self): - assert self.gw.workerthreads and self.gw.iothreads + for x in 'sender', 'receiver', 'executor': + assert self.gw.pool.getstarted(x) def test_remote_exec_waitclose(self): channel = self.gw.remote_exec('pass') @@ -77,6 +78,14 @@ channel = self.gw.remote_exec('raise ValueError') py.test.raises(gateway.RemoteError, channel.receive) + def test_channel_finish_and_then_EOFError(self): + channel = self.gw.remote_exec('channel.send(42)') + x = channel.receive() + assert x == 42 + py.test.raises(EOFError, channel.receive) + py.test.raises(EOFError, channel.receive) + py.test.raises(EOFError, channel.receive) + def test_channel_close_and_then_receive_error_multiple(self): channel = self.gw.remote_exec('channel.send(42) ; raise ValueError') x = channel.receive() @@ -113,6 +122,7 @@ newchan.waitclose(0.3) class TestBasicPopenGateway(PopenGatewayTestSetup, BasicRemoteExecution): + #disabled = True def test_many_popen(self): num = 4 l = [] @@ -136,58 +146,40 @@ class SocketGatewaySetup: def setup_class(cls): - portrange = (7770, 7800) cls.proxygw = py.execnet.PopenGateway() + cls.port = 7770 socketserverbootstrap = py.code.Source( mypath.dirpath().dirpath('bin', 'startserver.py').read(), """ import socket - portrange = channel.receive() - for i in portrange: - try: - sock = bind_and_listen(("localhost", i)) - except socket.error: - print "got error" - import traceback - traceback.print_exc() - continue - else: - channel.send(i) - startserver(sock) - break - else: - channel.send(None) - """) + sock = bind_and_listen(("localhost", %r)) + channel.send("ok") + startserver(sock) + """ % cls.port) # open a gateway to a fresh child process cls.proxygw = py.execnet.PopenGateway() # execute asynchronously the above socketserverbootstrap on the other channel = cls.proxygw.remote_exec(socketserverbootstrap) - # send parameters for the for-loop - channel.send((7770, 7800)) - # - # the other side should start the for loop now, we - # wait for the result - # - cls.listenport = channel.receive() - if cls.listenport is None: - raise IOError, "could not setup remote SocketServer" - cls.gw = py.execnet.SocketGateway('localhost', cls.listenport) - print "initialized socket gateway on port", cls.listenport + # the other side should start the socket server now + assert channel.receive() == "ok" + cls.gw = py.execnet.SocketGateway('localhost', cls.port) + print "initialized socket gateway to port", cls.port def teardown_class(cls): - print "trying to tear down remote socket gateway" + #print "trying to tear down remote socket gateway" cls.gw.exit() - if cls.gw.port: - print "trying to tear down remote socket loop" - import socket - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect(('localhost', cls.listenport)) - sock.sendall('"raise KeyboardInterrupt"') - sock.shutdown(2) - print "trying to tear proxy gateway" + #if cls.gw.port: + # print "trying to tear down remote socket loop" + # import socket + # sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + # sock.connect(('localhost', cls.gw.port)) + # sock.sendall('"raise KeyboardInterrupt"') + # sock.shutdown(2) + #print "trying to tear proxy gateway" cls.proxygw.exit() class TestSocketGateway(SocketGatewaySetup, BasicRemoteExecution): + disabled = sys.platform == "win32" pass From bob at codespeak.net Sun Jan 16 12:12:40 2005 From: bob at codespeak.net (bob at codespeak.net) Date: Sun, 16 Jan 2005 12:12:40 +0100 (MET) Subject: [py-svn] r8302 - py/dist/py/execnet/bin Message-ID: <20050116111240.DF2C527BAC@code1.codespeak.net> Author: bob Date: Sun Jan 16 12:12:40 2005 New Revision: 8302 Modified: py/dist/py/execnet/bin/startserver.py Log: set close-on-exec on the socket conditionally set SO_REUSEADDR Modified: py/dist/py/execnet/bin/startserver.py ============================================================================== --- py/dist/py/execnet/bin/startserver.py (original) +++ py/dist/py/execnet/bin/startserver.py Sun Jan 16 12:12:40 2005 @@ -10,6 +10,10 @@ debug = 0 import sys, socket, os +try: + import fcntl +except ImportError: + fcntl = None if debug: # and not os.isatty(sys.stdin.fileno()): f = open('/tmp/execnet-socket-pyout.log', 'a', 0) @@ -24,7 +28,8 @@ print progname, 'got new connection from %s %s' % address clientfile = clientsock.makefile('r+b',0) print "reading line" - source = clientfile.readline() + # rstrip so that we can use \r\n for telnet testing + source = clientfile.readline().rstrip() clientfile.close() g = {'clientsock' : clientsock, 'address' : address} source = eval(source) @@ -35,6 +40,7 @@ exec co in g finally: print progname, 'finished executing code' + clientsock.close() #except: # if debug: # import py @@ -51,7 +57,14 @@ host, port = hostport.split(':') hostport = (host, int(port)) serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + # set close-on-exec + if hasattr(fcntl, 'FD_CLOEXEC'): + old = fcntl.fcntl(serversock.fileno(), fcntl.F_GETFD) + fcntl.fcntl(serversock.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC) + # allow the address to be re-used in a reasonable amount of time + if os.name == 'posix' and sys.platform != 'cygwin': + serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + serversock.bind(hostport) serversock.listen(5) return serversock From bob at codespeak.net Sun Jan 16 13:07:39 2005 From: bob at codespeak.net (bob at codespeak.net) Date: Sun, 16 Jan 2005 13:07:39 +0100 (MET) Subject: [py-svn] r8303 - py/dist/py/execnet/bin Message-ID: <20050116120739.892F527B92@code1.codespeak.net> Author: bob Date: Sun Jan 16 13:07:39 2005 New Revision: 8303 Modified: py/dist/py/execnet/bin/startserver.py Log: don't close clientsock anymore Modified: py/dist/py/execnet/bin/startserver.py ============================================================================== --- py/dist/py/execnet/bin/startserver.py (original) +++ py/dist/py/execnet/bin/startserver.py Sun Jan 16 13:07:39 2005 @@ -40,7 +40,8 @@ exec co in g finally: print progname, 'finished executing code' - clientsock.close() + # background thread might hold a reference to this (!?) + #clientsock.close() #except: # if debug: # import py From hpk at codespeak.net Sun Jan 16 13:27:09 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 13:27:09 +0100 (MET) Subject: [py-svn] r8304 - py/dist/py/execnet/bin Message-ID: <20050116122709.A113B27B92@code1.codespeak.net> Author: hpk Date: Sun Jan 16 13:27:09 2005 New Revision: 8304 Modified: py/dist/py/execnet/bin/startserver.py Log: slight refactoring to allow looping (default when invoked from command line) this allows to have socketgateways and execnet/bin/shell's to the same socketserver. Modified: py/dist/py/execnet/bin/startserver.py ============================================================================== --- py/dist/py/execnet/bin/startserver.py (original) +++ py/dist/py/execnet/bin/startserver.py Sun Jan 16 13:27:09 2005 @@ -22,7 +22,7 @@ #import py #compile = py.code.compile -def execloop(serversock): +def exec_from_one_connection(serversock): print progname, 'Entering Accept loop', serversock.getsockname() clientsock,address = serversock.accept() print progname, 'got new connection from %s %s' % address @@ -42,16 +42,6 @@ print progname, 'finished executing code' # background thread might hold a reference to this (!?) #clientsock.close() - #except: - # if debug: - # import py - # excinfo = py.code.ExceptionInfo() - # #print excinfo.traceback - # #print excinfo - - #except: - # import traceback - # traceback.print_exc() def bind_and_listen(hostport): if isinstance(hostport, str): @@ -70,9 +60,18 @@ serversock.listen(5) return serversock -def startserver(serversock): +def startserver(serversock, loop=False): try: - execloop(serversock) + while 1: + try: + exec_from_one_connection(serversock) + except (KeyboardInterrupt, SystemExit): + raise + except: + import traceback + traceback.print_exc() + if not loop: + break finally: print "leaving socketserver execloop" serversock.shutdown(2) @@ -84,5 +83,5 @@ else: hostport = ':8888' serversock = bind_and_listen(hostport) - startserver(serversock) + startserver(serversock, loop=True) From hpk at codespeak.net Sun Jan 16 13:33:03 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 13:33:03 +0100 (MET) Subject: [py-svn] r8305 - in py/dist/py: documentation execnet/bin execnet/testing Message-ID: <20050116123303.CD9E627B92@code1.codespeak.net> Author: hpk Date: Sun Jan 16 13:33:03 2005 New Revision: 8305 Added: py/dist/py/execnet/bin/socketserver.py - copied unchanged from r8304, py/dist/py/execnet/bin/startserver.py Removed: py/dist/py/execnet/bin/startserver.py Modified: py/dist/py/documentation/execnet.txt py/dist/py/execnet/testing/test_gateway.py Log: renamed startserver.py to socketserver.py fixed execnet documentation Modified: py/dist/py/documentation/execnet.txt ============================================================================== --- py/dist/py/documentation/execnet.txt (original) +++ py/dist/py/documentation/execnet.txt Sun Jan 16 13:33:03 2005 @@ -180,52 +180,28 @@ basically listens and accepts socket connections, receives one liners and executes them. -Here is the code for making the above triangle happen:: +Here are 20 lines of code making the above triangle happen:: - import py - socketserverbootstrap = py.code.Source( - autopath.dirpath('bin/socketserver').read(), - """ - import socket - portrange = channel.receive() - for i in portrange: - try: - sock = bind_and_listen(("localhost", i)) - except socket.error: - continue - else: - channel.send(i) - startserver(sock) - print "started server with socket" - break - else: - channel.send(None) - """) - - # open a gateway to a fresh child process + import py + port = 7770 + socketserverbootstrap = py.code.Source( + mypath.dirpath().dirpath('bin', 'socketserver.py').read(), + """ + import socket + sock = bind_and_listen(("localhost", %r)) + channel.send("ok") + startserver(sock) + """ % port) + # open a gateway to a fresh child process proxygw = py.execnet.PopenGateway() # execute asynchronously the above socketserverbootstrap on the other - channel = proxygw.remote_exec_async(socketserverbootstrap) + channel = proxygw.remote_exec(socketserverbootstrap) - # send socket-port range to the receiving for-loop - channel.send((7770, 7800)) - - # - # the other side should start the for loop now, we - # wait for the result - # - listenport = channel.receive() - if listenport is None: - raise IOError, "could not setup remote SocketServer" - - # open another gateway to the freshly installed socket server - socketgw = py.execnet.SocketGateway('localhost', listenport) - print "initialized socket gateway on port", listenport - - # later you can exit / close down the gateways - socketgw.exit() - proxygw.exit() + # the other side should start the socket server now + assert channel.receive() == "ok" + gw = py.execnet.SocketGateway('localhost', cls.port) + print "initialized socket gateway to port", cls.port .. _`py API`: api.html Deleted: /py/dist/py/execnet/bin/startserver.py ============================================================================== --- /py/dist/py/execnet/bin/startserver.py Sun Jan 16 13:33:03 2005 +++ (empty file) @@ -1,87 +0,0 @@ -#! /usr/bin/env python - -""" - start socket based minimal readline exec server -""" -# this part of the program only executes on the server side -# - -progname = 'socket_readline_exec_server-1.2' -debug = 0 - -import sys, socket, os -try: - import fcntl -except ImportError: - fcntl = None - -if debug: # and not os.isatty(sys.stdin.fileno()): - f = open('/tmp/execnet-socket-pyout.log', 'a', 0) - old = sys.stdout, sys.stderr - sys.stdout = sys.stderr = f - #import py - #compile = py.code.compile - -def exec_from_one_connection(serversock): - print progname, 'Entering Accept loop', serversock.getsockname() - clientsock,address = serversock.accept() - print progname, 'got new connection from %s %s' % address - clientfile = clientsock.makefile('r+b',0) - print "reading line" - # rstrip so that we can use \r\n for telnet testing - source = clientfile.readline().rstrip() - clientfile.close() - g = {'clientsock' : clientsock, 'address' : address} - source = eval(source) - if source: - co = compile(source+'\n', source, 'exec') - print progname, 'compiled source, executing' - try: - exec co in g - finally: - print progname, 'finished executing code' - # background thread might hold a reference to this (!?) - #clientsock.close() - -def bind_and_listen(hostport): - if isinstance(hostport, str): - host, port = hostport.split(':') - hostport = (host, int(port)) - serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - # set close-on-exec - if hasattr(fcntl, 'FD_CLOEXEC'): - old = fcntl.fcntl(serversock.fileno(), fcntl.F_GETFD) - fcntl.fcntl(serversock.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC) - # allow the address to be re-used in a reasonable amount of time - if os.name == 'posix' and sys.platform != 'cygwin': - serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - serversock.bind(hostport) - serversock.listen(5) - return serversock - -def startserver(serversock, loop=False): - try: - while 1: - try: - exec_from_one_connection(serversock) - except (KeyboardInterrupt, SystemExit): - raise - except: - import traceback - traceback.print_exc() - if not loop: - break - finally: - print "leaving socketserver execloop" - serversock.shutdown(2) - -if __name__ == '__main__': - import sys - if len(sys.argv)>1: - hostport = sys.argv[1] - else: - hostport = ':8888' - serversock = bind_and_listen(hostport) - startserver(serversock, loop=True) - Modified: py/dist/py/execnet/testing/test_gateway.py ============================================================================== --- py/dist/py/execnet/testing/test_gateway.py (original) +++ py/dist/py/execnet/testing/test_gateway.py Sun Jan 16 13:33:03 2005 @@ -146,10 +146,9 @@ class SocketGatewaySetup: def setup_class(cls): - cls.proxygw = py.execnet.PopenGateway() cls.port = 7770 socketserverbootstrap = py.code.Source( - mypath.dirpath().dirpath('bin', 'startserver.py').read(), + mypath.dirpath().dirpath('bin', 'socketserver.py').read(), """ import socket sock = bind_and_listen(("localhost", %r)) From hpk at codespeak.net Sun Jan 16 15:19:03 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 15:19:03 +0100 (MET) Subject: [py-svn] r8306 - in py/dist/py/path: extpy/testing local/testing svn/testing test testing Message-ID: <20050116141903.2707527B5C@code1.codespeak.net> Author: hpk Date: Sun Jan 16 15:19:02 2005 New Revision: 8306 Added: py/dist/py/path/testing/ - copied from r8305, py/dist/py/path/test/ Removed: py/dist/py/path/test/ Modified: py/dist/py/path/extpy/testing/test_extpy.py py/dist/py/path/local/testing/test_local.py py/dist/py/path/local/testing/test_posix.py py/dist/py/path/svn/testing/svntestbase.py py/dist/py/path/testing/fscommon.py py/dist/py/path/testing/test_api.py Log: renamed test to testing directory fixed a test for win Modified: py/dist/py/path/extpy/testing/test_extpy.py ============================================================================== --- py/dist/py/path/extpy/testing/test_extpy.py (original) +++ py/dist/py/path/extpy/testing/test_extpy.py Sun Jan 16 15:19:02 2005 @@ -1,7 +1,7 @@ import os import py -from py.__impl__.path.test import common +from py.__impl__.path.testing import common mypath = py.magic.autopath().dirpath('inc_test_extpy.py') 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 Jan 16 15:19:02 2005 @@ -1,6 +1,6 @@ import py from py.path import local, checker -from py.__impl__.path.test.fscommon import CommonFSTests, setuptestfs +from py.__impl__.path.testing.fscommon import CommonFSTests, setuptestfs class LocalSetup: def setup_class(cls): 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 Jan 16 15:19:02 2005 @@ -1,6 +1,6 @@ import py import sys -from py.__impl__.path.test.fscommon import setuptestfs +from py.__impl__.path.testing.fscommon import setuptestfs checker = py.path.checker local = py.path.local Modified: py/dist/py/path/svn/testing/svntestbase.py ============================================================================== --- py/dist/py/path/svn/testing/svntestbase.py (original) +++ py/dist/py/path/svn/testing/svntestbase.py Sun Jan 16 15:19:02 2005 @@ -1,6 +1,6 @@ import py from py import path, test, process -from py.__impl__.path.test.fscommon import CommonFSTests, setuptestfs +from py.__impl__.path.testing.fscommon import CommonFSTests, setuptestfs from py.__impl__.path.svn import cache mypath = py.magic.autopath() Modified: py/dist/py/path/testing/fscommon.py ============================================================================== --- py/dist/py/path/test/fscommon.py (original) +++ py/dist/py/path/testing/fscommon.py Sun Jan 16 15:19:02 2005 @@ -1,5 +1,5 @@ import py -from py.__impl__.path.test import common +from py.__impl__.path.testing import common checker = py.path.checker Modified: py/dist/py/path/testing/test_api.py ============================================================================== --- py/dist/py/path/test/test_api.py (original) +++ py/dist/py/path/testing/test_api.py Sun Jan 16 15:19:02 2005 @@ -14,7 +14,7 @@ def test_defaultlocal(self): p = path.local() assert hasattr(p, 'atime') - assert hasattr(p, 'group') + #assert hasattr(p, 'group') # XXX win32? assert hasattr(p, 'setmtime') assert p.check() assert p.check(local=1) From hpk at codespeak.net Sun Jan 16 17:21:09 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 17:21:09 +0100 (MET) Subject: [py-svn] r8307 - py/dist/py/code Message-ID: <20050116162109.AF17827B5D@code1.codespeak.net> Author: hpk Date: Sun Jan 16 17:21:09 2005 New Revision: 8307 Modified: py/dist/py/code/traceback.py Log: hack a bit to get better tracebackentry.getsource() heuristics ... Modified: py/dist/py/code/traceback.py ============================================================================== --- py/dist/py/code/traceback.py (original) +++ py/dist/py/code/traceback.py Sun Jan 16 17:21:09 2005 @@ -39,6 +39,14 @@ source = self.frame.code.fullsource start, end = self.frame.code.firstlineno, self.lineno _, end = source.getstatementrange(end) + # heuristic to stop displaying source on e.g. + # if something: # assume this causes a NameError + # # _this_ lines and the one + # below we don't want from entry.getsource() + for i in range(self.lineno, end): + if source[i].rstrip().endswith(':'): + end = i + 1 + break return source[start:end] def __str__(self): From hpk at codespeak.net Sun Jan 16 17:32:01 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 17:32:01 +0100 (MET) Subject: [py-svn] r8308 - py/dist/py/misc Message-ID: <20050116163201.90DB927B5D@code1.codespeak.net> Author: hpk Date: Sun Jan 16 17:32:01 2005 New Revision: 8308 Modified: py/dist/py/misc/cache.py Log: fix BuildCostCache to deal with elapsed builttime being measured == 0 Modified: py/dist/py/misc/cache.py ============================================================================== --- py/dist/py/misc/cache.py (original) +++ py/dist/py/misc/cache.py Sun Jan 16 17:32:01 2005 @@ -25,7 +25,7 @@ def weight(): def fget(self): - return self.num * self.oneweight + return (self.num * self.oneweight, self.num) return property(fget, None, None, "cumulative weight") weight = weight() @@ -37,6 +37,9 @@ return property(fget, None, None) value = value() + def __repr__(self): + return "<%s weight=%s>" % (self.__class__.__name__, self.weight) + class BasicCache(object): def __init__(self, maxentries=128): self.maxentries = maxentries From hpk at codespeak.net Sun Jan 16 17:34:33 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 17:34:33 +0100 (MET) Subject: [py-svn] r8309 - in py/dist/py/misc: . testing Message-ID: <20050116163433.5EC8F27B5D@code1.codespeak.net> Author: hpk Date: Sun Jan 16 17:34:33 2005 New Revision: 8309 Modified: py/dist/py/misc/error.py py/dist/py/misc/testing/test_initpkg.py Log: let import-all generate tests for each import ... Modified: py/dist/py/misc/error.py ============================================================================== --- py/dist/py/misc/error.py (original) +++ py/dist/py/misc/error.py Sun Jan 16 17:34:33 2005 @@ -20,7 +20,7 @@ ModuleType = type(py) class py_error(ModuleType): - """ py.error contains higher level Exception classes + """ py.error lazily provides higher level Exception classes for each possible POSIX errno (as defined per the 'errno' module. All such Exceptions derive from py.error.Error, which itself is a subclass Modified: py/dist/py/misc/testing/test_initpkg.py ============================================================================== --- py/dist/py/misc/testing/test_initpkg.py (original) +++ py/dist/py/misc/testing/test_initpkg.py Sun Jan 16 17:34:33 2005 @@ -1,3 +1,5 @@ +from __future__ import generators + import py import types @@ -24,7 +26,7 @@ from py.path import local as local2 assert local1 is local2 -def test_importing_all_implementations(): +def test_importall(): base = py.path.local(py.__file__).dirpath() nodirs = ( base.join('test', 'testing', 'test'), @@ -45,7 +47,10 @@ else: relpath = relpath.replace(base.sep, '.') modpath = 'py.__impl__.%s' % relpath - assert __import__(modpath) + yield check_import, modpath + +def check_import(modpath): + assert __import__(modpath) def test_shahexdigest(): hex = py.__package__.shahexdigest() From hpk at codespeak.net Sun Jan 16 17:35:39 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 17:35:39 +0100 (MET) Subject: [py-svn] r8310 - in py/dist/py: execnet/testing path path/testing Message-ID: <20050116163539.D6BC627B5D@code1.codespeak.net> Author: hpk Date: Sun Jan 16 17:35:39 2005 New Revision: 8310 Modified: py/dist/py/execnet/testing/sshtesting.py py/dist/py/path/common.py py/dist/py/path/testing/fscommon.py Log: various windows related fixes/hacks (some of which i don't fully understand yet) Modified: py/dist/py/execnet/testing/sshtesting.py ============================================================================== --- py/dist/py/execnet/testing/sshtesting.py (original) +++ py/dist/py/execnet/testing/sshtesting.py Sun Jan 16 17:35:39 2005 @@ -6,10 +6,10 @@ #REMOTE_HOST = 'codespeak.net' #REMOTE_HOSTNAME = 'thoth.codespeak.net' -REMOTE_HOST = 'localhost' # you need to have a local ssh-daemon running! -REMOTE_HOSTNAME = py.std.socket.gethostname() # the remote's socket.gethostname() def test_sshgateway(): + REMOTE_HOST = 'localhost' # you need to have a local ssh-daemon running! + REMOTE_HOSTNAME = py.std.socket.gethostname() # the remote's socket.gethostname() gw = py.execnet.SshGateway(REMOTE_HOST) c = gw.remote_exec('import socket; channel.send(socket.gethostname())') msg = c.receive() Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Sun Jan 16 17:35:39 2005 @@ -3,7 +3,7 @@ """ from __future__ import generators -import sys +import os, sys import py def checktype(pathinstance, kw): @@ -189,6 +189,7 @@ def _callex(self, func, *args): """ call a function and raise errno-exception if applicable. """ + #__tracebackhide__ = True try: return func(*args) except (py.error.Error, KeyboardInterrupt, SystemExit): @@ -196,10 +197,21 @@ except EnvironmentError, e: if not hasattr(e, 'errno'): raise + #__tracebackhide__ = False cls, value, tb = sys.exc_info() - cls = py.error._geterrnoclass(e.errno) + errno = e.errno + try: + if isinstance(e, WindowsError): + if errno == 3: + errno = 2 # XXX HACK + else: + raise cls, value, tb + except NameError: + pass + cls = py.error._geterrnoclass(errno) value = cls("%s%r" % (func.__name__, args)) - raise cls, value, tb + #__tracebackhide__ = True + raise cls, value class fnmatch: def __init__(self, pattern): Modified: py/dist/py/path/testing/fscommon.py ============================================================================== --- py/dist/py/path/testing/fscommon.py (original) +++ py/dist/py/path/testing/fscommon.py Sun Jan 16 17:35:39 2005 @@ -59,7 +59,7 @@ newpath = self.root.join('samplefile.py') dirname, purebasename, basename, ext = newpath.get( 'dirname,purebasename,basename,ext') - assert dirname == str(self.root) + assert str(self.root).endswith(dirname) # be careful with win32 'drive' assert purebasename == 'samplefile' assert basename == 'samplefile.py' assert ext == '.py' From hpk at codespeak.net Sun Jan 16 18:11:49 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 18:11:49 +0100 (MET) Subject: [py-svn] r8311 - in py/dist/py: misc path Message-ID: <20050116171149.2AE3827B5C@code1.codespeak.net> Author: hpk Date: Sun Jan 16 18:11:48 2005 New Revision: 8311 Modified: py/dist/py/misc/error.py py/dist/py/path/common.py Log: try to get Win32 to report ENOTDIR's as ENOTDIRs ... Modified: py/dist/py/misc/error.py ============================================================================== --- py/dist/py/misc/error.py (original) +++ py/dist/py/misc/error.py Sun Jan 16 18:11:48 2005 @@ -17,6 +17,11 @@ " ".join(map(str, self.args)), ) +_winerrnomap = { + 3: py.std.errno.ENOENT, + 267: py.std.errno.ENOTDIR, +} + ModuleType = type(py) class py_error(ModuleType): @@ -28,6 +33,10 @@ """ Error = Error + def _getwinerrnoclass(cls, eno): + return cls._geterrnoclass(_winerrnomap[eno]) + _getwinerrnoclass = classmethod(_getwinerrnoclass) + def _geterrnoclass(eno, _errno2class = {}): try: return _errno2class[eno] Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Sun Jan 16 18:11:48 2005 @@ -200,15 +200,17 @@ #__tracebackhide__ = False cls, value, tb = sys.exc_info() errno = e.errno - try: - if isinstance(e, WindowsError): - if errno == 3: - errno = 2 # XXX HACK - else: - raise cls, value, tb + try: + if not isinstance(e, WindowsError): + raise NameError except NameError: - pass - cls = py.error._geterrnoclass(errno) + # we are not on Windows, or we got a proper OSError + cls = py.error._geterrnoclass(errno) + else: + try: + cls = py.error._getwinerrnoclass(errno) + except KeyError: + raise cls, value, tb value = cls("%s%r" % (func.__name__, args)) #__tracebackhide__ = True raise cls, value From hpk at codespeak.net Sun Jan 16 18:57:46 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 18:57:46 +0100 (MET) Subject: [py-svn] r8312 - py/dist/py/bin Message-ID: <20050116175746.EB64F27B5A@code1.codespeak.net> Author: hpk Date: Sun Jan 16 18:57:46 2005 New Revision: 8312 Modified: py/dist/py/bin/_findpy.py Log: really insert 'py lib path' as first entry in sys.path if we are not already in the first entry. Previously, it would accept being later in sys.path somewhere but then you can get the "wrong" version of the py lib ... Modified: py/dist/py/bin/_findpy.py ============================================================================== --- py/dist/py/bin/_findpy.py (original) +++ py/dist/py/bin/_findpy.py Sun Jan 16 18:57:46 2005 @@ -13,11 +13,12 @@ pydir = join(current, 'py') # recognize py-package and ensure it is importable if exists(pydir) and exists(join(pydir, '__init__.py')): - for p in sys.path: - if p == current: - return True - print "inserting into sys.path:", current - sys.path.insert(0, current) + #for p in sys.path: + # if p == current: + # return True + if current != sys.path[0]: # if we are already first, then ok + print "inserting into sys.path:", current + sys.path.insert(0, current) return True current = opd(current) if last == current: From hpk at codespeak.net Sun Jan 16 18:59:43 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 18:59:43 +0100 (MET) Subject: [py-svn] r8313 - in py/dist/py/path/local: . testing Message-ID: <20050116175943.E4E8427B5A@code1.codespeak.net> Author: hpk Date: Sun Jan 16 18:59:43 2005 New Revision: 8313 Modified: py/dist/py/path/local/local.py py/dist/py/path/local/testing/test_local.py Log: yet some more windows support: x = py.path.local.sysfind("python") now works (and you may even succeed running x.sysexec("-c", "print 42") if you have win32all installed). Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Sun Jan 16 18:59:43 2005 @@ -388,13 +388,20 @@ Note: This is probably not working on plain win32 systems but may work on cygwin. """ - for x in py.std.os.environ['PATH'].split(':'): - p = py.path.local(x).join(name) - if p.check(file=1): - if checker: - if not checker(p): - continue - return p + if py.std.sys.platform == 'win32': + paths = py.std.os.environ['Path'].split(';') + tryadd = '', '.exe', '.com', '.bat' # XXX add more? + else: + paths = py.std.os.environ['PATH'].split(':') + tryadd = ('',) + for x in paths: + for addext in tryadd: + p = py.path.local(x).join(name) + addext + if p.check(file=1): + if checker: + if not checker(p): + continue + return p raise py.error.ENOENT(name) sysfind = classmethod(sysfind) #""" 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 Jan 16 18:59:43 2005 @@ -126,6 +126,16 @@ assert t == newfile assert newfile.check(dir=1) +class TestExecutionOnWindows(LocalSetup): + disabled = py.std.sys.platform != 'win32' + + def test_sysfind(self): + x = py.path.local.sysfind('cmd') + assert x.check(file=1) + py.test.raises(py.error.ENOENT, """ + py.path.local.sysfind('jaksdkasldqwe') + """) + class TestExecution(LocalSetup): disabled = py.std.sys.platform == 'win32' From hpk at codespeak.net Sun Jan 16 21:22:01 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 21:22:01 +0100 (MET) Subject: [py-svn] r8317 - in py/dist/py/code: . testing Message-ID: <20050116202201.AD9E627B55@code1.codespeak.net> Author: hpk Date: Sun Jan 16 21:22:01 2005 New Revision: 8317 Modified: py/dist/py/code/source.py py/dist/py/code/testing/test_source.py Log: conceptually a Sourcecode object is a list of lines so it has an obvious iterator and len() introduce default "rstripping" for constructing Source objects. Modified: py/dist/py/code/source.py ============================================================================== --- py/dist/py/code/source.py (original) +++ py/dist/py/code/source.py Sun Jan 16 21:22:01 2005 @@ -6,18 +6,21 @@ class Source(object): """ a mutable object holding a source code fragment, - automatically deindenting it. + possibly deindenting it. """ def __init__(self, *parts, **kwargs): self.lines = lines = [] de = kwargs.get('deindent', True) + rstrip = kwargs.get('rstrip', True) for part in parts: if isinstance(part, Source): partlines = part.lines elif isinstance(part, str): + if rstrip: + part = part.rstrip() partlines = part.split('\n') else: - partlines = getsource(part, deindent=False).lines + partlines = getsource(part, deindent=de).lines if de: partlines = deindent(partlines) lines.extend(partlines) @@ -28,6 +31,9 @@ else: return self.__getslice__(key) + def __len__(self): + return len(self.lines) + def __getslice__(self, start, end): newsource = Source() newsource.lines = self.lines[start:end] @@ -47,14 +53,14 @@ source.lines[:] = self.lines[start:end+1] return source - def putaround(self, before='', after=''): - """ modifies a new source object embedded/indented - between before and after. + def putaround(self, before='', after='', indent=' ' * 4): + """ return a copy of the source object with + 'before' and 'after' wrapped around it. """ before = Source(before) after = Source(after) newsource = Source() - lines = [' ' + line for line in self.lines] + lines = [ (indent + line) for line in self.lines] newsource.lines = before.lines + lines + after.lines return newsource @@ -94,7 +100,9 @@ trysource = self[start:end+1] if trysource.isparseable(): break - assert start <= lineno <= end, "could not locate statement" + #print str(self[start-2:start+2]) + assert start <= lineno <= end, "%d <= %d <= %d" %(start,lineno,end) + # "could not locate statement in %r" % self[lineno]) return start, end + 1 def getblockend(self, lineno): @@ -220,7 +228,7 @@ offset = 0 newlines = [] for line in lines: - #line = line.expandtabs() + line = line.expandtabs() s = line.lstrip() if s and line[:offset].isspace(): line = line[offset:] Modified: py/dist/py/code/testing/test_source.py ============================================================================== --- py/dist/py/code/testing/test_source.py (original) +++ py/dist/py/code/testing/test_source.py Sun Jan 16 21:22:01 2005 @@ -11,9 +11,14 @@ x = Source(""" 3 - """) + """, rstrip=False) assert str(x) == "\n3\n " + x = Source(""" + 3 + """, rstrip=True) + assert str(x) == "\n3" + def test_source_from_function(): source = py.code.Source(test_source_str_function) assert str(source).startswith('def test_source_str_function():') @@ -54,7 +59,7 @@ assert Source(" \nif 1:\n pass").isparseable() assert not Source(" \nif 1:\npass").isparseable() -class TestSliceAccess: +class TestAccesses: source = Source("""\ def f(x): pass @@ -71,6 +76,14 @@ x = self.source[0] assert x == "def f(x):" + def test_len(self): + assert len(self.source) == 4 + + def test_iter(self): + l = [x for x in self.source] + assert len(l) == 4 + + class TestCodeHacks: def test_newcode(self): from py.__impl__.code.source import newcode From hpk at codespeak.net Sun Jan 16 22:09:36 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 22:09:36 +0100 (MET) Subject: [py-svn] r8318 - in py/dist/py/code: . testing Message-ID: <20050116210936.17BB027B55@code1.codespeak.net> Author: hpk Date: Sun Jan 16 22:09:35 2005 New Revision: 8318 Modified: py/dist/py/code/source.py py/dist/py/code/testing/test_source.py Log: crash if we can't find a proper statementrange improved tests for source.getstatementrange(lineno) -> (start, end) Modified: py/dist/py/code/source.py ============================================================================== --- py/dist/py/code/source.py (original) +++ py/dist/py/code/source.py Sun Jan 16 22:09:35 2005 @@ -29,7 +29,7 @@ if isinstance(key, int): return self.lines[key] else: - return self.__getslice__(key) + return self.__getslice__(key.start, key.stop) def __len__(self): return len(self.lines) @@ -72,13 +72,14 @@ return self[start:end] def getstatementrange(self, lineno): - """ return (start, end) tuple which span the statement - region which contains the given lineno. + """ return (start, end) tuple which spans the minimal + statement region which containing the given lineno. """ # XXX there must be a better than these heuristic ways ... + # XXX there may even be better heuristics :-) for end in range(lineno, len(self)): trysource = self[lineno:end+1] - if trysource.isparseable(): + if trysource.isparseable(): start = lineno break else: @@ -100,10 +101,9 @@ trysource = self[start:end+1] if trysource.isparseable(): break - #print str(self[start-2:start+2]) - assert start <= lineno <= end, "%d <= %d <= %d" %(start,lineno,end) - # "could not locate statement in %r" % self[lineno]) - return start, end + 1 + if start <= lineno <= end: + return start, end + 1 + raise IndexError("could not find lineno statement at %d" % lineno) def getblockend(self, lineno): # XXX @@ -130,7 +130,7 @@ def isparseable(self, deindent=True): """ return True if source is parseable, heuristically - deindenting it by default. + deindenting it by default. """ import parser if deindent: Modified: py/dist/py/code/testing/test_source.py ============================================================================== --- py/dist/py/code/testing/test_source.py (original) +++ py/dist/py/code/testing/test_source.py Sun Jan 16 22:09:35 2005 @@ -57,6 +57,7 @@ assert Source("hello").isparseable() assert Source("if 1:\n pass").isparseable() assert Source(" \nif 1:\n pass").isparseable() + assert not Source("if 1:\n").isparseable() assert not Source(" \nif 1:\npass").isparseable() class TestAccesses: @@ -146,33 +147,27 @@ #x = s.deindent() assert str(s) == ass - def XXXtest_getstatement_within_constructs(self): + def test_getstatementrange_within_constructs(self): source = Source("""\ try: - raise ValueError + try: + raise ValueError + except SomeThing: + pass finally: 42 """) - stmt = source.getstatement(1) - assert str(stmt).strip() == 'raise ValueError' - xxx - co = source.compile() - try: - exec co - except ValueError: - excinfo = py.code.ExceptionInfo(py.std.sys.exc_info()) - l = excinfo.traceback - tb = l[0] - inner = l[1] - print "inner frame-statement:", inner.frame.statement - print "inner frame-lineno:", inner.frame.lineno - print "inner tb-statement:", inner.statement - print "inner tb-lineno:", inner.lineno - print "...", repr(inner.frame.code.fullsource[inner.lineno]) - - print "tb-statement:", tb.statement - print "tb-lineno:", tb.lineno - XXX + assert len(source) == 7 + assert source.getstatementrange(0) == (0, 7) + assert source.getstatementrange(1) == (1, 5) + assert source.getstatementrange(2) == (2, 3) + assert py.test.raises(IndexError, + "source.getstatementrange(3)") + assert source.getstatementrange(4) == (4, 5) + assert py.test.raises(IndexError, + "source.getstatementrange(5)") + assert source.getstatementrange(6) == (6, 7) + def test_compile_and_getsource(self): co = self.source.compile() From hpk at codespeak.net Sun Jan 16 22:29:41 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 16 Jan 2005 22:29:41 +0100 (MET) Subject: [py-svn] r8319 - in py/dist/py/code: . testing Message-ID: <20050116212941.8288127B55@code1.codespeak.net> Author: hpk Date: Sun Jan 16 22:29:41 2005 New Revision: 8319 Modified: py/dist/py/code/testing/test_excinfo.py py/dist/py/code/traceback.py Log: refined tracebackentry.getsource() Modified: py/dist/py/code/testing/test_excinfo.py ============================================================================== --- py/dist/py/code/testing/test_excinfo.py (original) +++ py/dist/py/code/testing/test_excinfo.py Sun Jan 16 22:29:41 2005 @@ -56,6 +56,30 @@ pass assert not names + def test_traceback_entry_getsource(self): + tb = self.excinfo.traceback + s = str(tb[-1].getsource() ) + assert s.startswith("def f():") + assert s.endswith("raise ValueError") + + def test_traceback_entry_getsource_in_construct(self): + source = py.code.Source("""\ + def xyz(): + try: + raise ValueError + except somenoname: + pass + xyz() + """) + try: + exec source.compile() + except NameError: + tb = py.code.ExceptionInfo().traceback + print tb[-1].getsource() + s = str(tb[-1].getsource()) + assert s.startswith("def xyz():\n try:") + assert s.endswith("except somenoname:") + #def test_traceback_display_func(self): # tb = self.excinfo.traceback # for x in tb: Modified: py/dist/py/code/traceback.py ============================================================================== --- py/dist/py/code/traceback.py (original) +++ py/dist/py/code/traceback.py Sun Jan 16 22:29:41 2005 @@ -38,7 +38,10 @@ """ return failing source code. """ source = self.frame.code.fullsource start, end = self.frame.code.firstlineno, self.lineno - _, end = source.getstatementrange(end) + try: + _, end = source.getstatementrange(end) + except IndexError: + end = self.lineno + 1 # heuristic to stop displaying source on e.g. # if something: # assume this causes a NameError # # _this_ lines and the one From hpk at codespeak.net Mon Jan 17 00:06:30 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 17 Jan 2005 00:06:30 +0100 (MET) Subject: [py-svn] r8321 - in py/dist/py: . test test/testing Message-ID: <20050116230630.BFDD927B55@code1.codespeak.net> Author: hpk Date: Mon Jan 17 00:06:30 2005 New Revision: 8321 Added: py/dist/py/test/testing/test_api.py Modified: py/dist/py/__init__.py py/dist/py/test/item.py Log: introduce new py.test.skip_on_error(callable, *args, **kwargs) function which performs "callable(*args, **kwargs)" and upon any exception issues py.test.skip(). Modified: py/dist/py/__init__.py ============================================================================== --- py/dist/py/__init__.py (original) +++ py/dist/py/__init__.py Mon Jan 17 00:06:30 2005 @@ -1,6 +1,7 @@ from initpkg import initpkg initpkg(__name__, exportdefs = { 'test.skip' : ('./test/item.py', 'skip'), + 'test.skip_on_error' : ('./test/item.py', 'skip_on_error'), 'test.raises' : ('./test/raises.py', 'raises'), 'test.fail' : ('./test/item.py', 'fail'), 'test.exit' : ('./test/drive.py', 'exit'), Modified: py/dist/py/test/item.py ============================================================================== --- py/dist/py/test/item.py (original) +++ py/dist/py/test/item.py Mon Jan 17 00:06:30 2005 @@ -156,11 +156,20 @@ return "%s -> %s%r" % (self.extpy.modpath, name, self.args) # -# triggering specific outcomes from executing Items +# triggering specific outcomes while executing Items # -def skip(msg="unknown reason"): +def skip(msg="unknown reason", tbindex=-2): """ skip with the given Message. """ - raise py.test.Item.Skipped(msg=msg, tbindex=-2) + raise py.test.Item.Skipped(msg=msg, tbindex=tbindex) + +def skip_on_error(func, *args, **kwargs): + """ skip test if the given call fails. """ + try: + func(*args, **kwargs) + except Exception, e: + s = py.code.ExceptionInfo().exconly() + name = getattr(func, '__name__', func) + py.test.skip("%s(...) -> %s" %(name, s.rstrip(), ), tbindex=-3) def fail(msg="unknown failure"): """ fail with the given Message. """ Added: py/dist/py/test/testing/test_api.py ============================================================================== --- (empty file) +++ py/dist/py/test/testing/test_api.py Mon Jan 17 00:06:30 2005 @@ -0,0 +1,11 @@ + +import py + +def test_skipfailure(): + def f(): + raise ValueError() + excinfo = py.test.raises( + py.test.Item.Skipped, + "py.test.skip_on_error(f)") + print excinfo + assert str(excinfo).find("ValueError") != -1 From hpk at codespeak.net Mon Jan 17 00:06:58 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 17 Jan 2005 00:06:58 +0100 (MET) Subject: [py-svn] r8322 - py/dist/py Message-ID: <20050116230658.5AE2027B55@code1.codespeak.net> Author: hpk Date: Mon Jan 17 00:06:58 2005 New Revision: 8322 Modified: py/dist/py/initpkg.py Log: hide traceback when raising AttributeError Modified: py/dist/py/initpkg.py ============================================================================== --- py/dist/py/initpkg.py (original) +++ py/dist/py/initpkg.py Mon Jan 17 00:06:58 2005 @@ -150,6 +150,7 @@ try: extpy = self.__map__[name] except KeyError: + __tracebackhide__ = True raise AttributeError(name) #print "getattr(%r, %r)" %(self, name) result = self.__package__._resolve(extpy) From hpk at codespeak.net Mon Jan 17 00:07:24 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 17 Jan 2005 00:07:24 +0100 (MET) Subject: [py-svn] r8323 - in py/dist/py: code test/report/text Message-ID: <20050116230724.4775027B55@code1.codespeak.net> Author: hpk Date: Mon Jan 17 00:07:24 2005 New Revision: 8323 Modified: py/dist/py/code/excinfo.py py/dist/py/test/report/text/summary.py Log: improve "skipped reasons" reporting in summary. Modified: py/dist/py/code/excinfo.py ============================================================================== --- py/dist/py/code/excinfo.py (original) +++ py/dist/py/code/excinfo.py Mon Jan 17 00:07:24 2005 @@ -20,13 +20,17 @@ self.type, self.value, tb = self._excinfo self.traceback = py.code.Traceback(tb) # get the text representation of the exception + text = self.exconly() + if text.startswith(strip): + text = text[len(strip):] + self.exception_text = text + + def exconly(self): lines = py.std.traceback.format_exception_only(self.type, self.value) text = ''.join(lines) if text.endswith('\n'): text = text[:-1] - if text.startswith(strip): - text = text[len(strip):] - self.exception_text = text + return text def __str__(self): return self.exception_text Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Mon Jan 17 00:07:24 2005 @@ -43,19 +43,23 @@ (status, elapsed)) def skippedreasons(self): - d = {} + texts = {} for res in self.getlist(Item.Skipped): tbindex = getattr(res, 'tbindex', -1) raisingtb = res.excinfo.traceback[tbindex] fn = raisingtb.frame.code.path lineno = raisingtb.lineno - d[(fn,lineno)] = res - if d: + d = texts.setdefault(res.excinfo.exconly(), {}) + d[(fn,lineno)] = res + + if texts: self.out.line() self.out.sep('_', 'reasons for skipped tests') - for (fn,lineno), res in d.items(): - self.out.line('Skipped in %s:%d %s' %(fn,lineno+1,getattr(res, 'msg'))) - self.out.line() + for text, dict in texts.items(): + for (fn, lineno), res in dict.items(): + self.out.line('Skipped in %s:%d' %(fn,lineno)) + self.out.line("reason: %s" % text) + self.out.line() def failures(self): l = self.getlist(Item.Failed) From hpk at codespeak.net Mon Jan 17 00:13:29 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 17 Jan 2005 00:13:29 +0100 (MET) Subject: [py-svn] r8325 - in py/dist/py/test: . testing Message-ID: <20050116231329.29F3827B55@code1.codespeak.net> Author: hpk Date: Mon Jan 17 00:13:28 2005 New Revision: 8325 Modified: py/dist/py/test/item.py py/dist/py/test/testing/test_api.py Log: ups ... Modified: py/dist/py/test/item.py ============================================================================== --- py/dist/py/test/item.py (original) +++ py/dist/py/test/item.py Mon Jan 17 00:13:28 2005 @@ -165,7 +165,7 @@ def skip_on_error(func, *args, **kwargs): """ skip test if the given call fails. """ try: - func(*args, **kwargs) + return func(*args, **kwargs) except Exception, e: s = py.code.ExceptionInfo().exconly() name = getattr(func, '__name__', func) Modified: py/dist/py/test/testing/test_api.py ============================================================================== --- py/dist/py/test/testing/test_api.py (original) +++ py/dist/py/test/testing/test_api.py Mon Jan 17 00:13:28 2005 @@ -9,3 +9,8 @@ "py.test.skip_on_error(f)") print excinfo assert str(excinfo).find("ValueError") != -1 + +def test_skip_on_error_with_no_failure(): + def f(): + return 42 + assert py.test.skip_on_error(f) == 42 From hpk at codespeak.net Mon Jan 17 16:13:19 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 17 Jan 2005 16:13:19 +0100 (MET) Subject: [py-svn] r8332 - in py/dist/py/path: . local/testing Message-ID: <20050117151319.7066827B76@code1.codespeak.net> Author: hpk Date: Mon Jan 17 16:13:19 2005 New Revision: 8332 Modified: py/dist/py/path/common.py py/dist/py/path/local/testing/test_local.py Log: some fixes Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Mon Jan 17 16:13:19 2005 @@ -192,7 +192,7 @@ #__tracebackhide__ = True try: return func(*args) - except (py.error.Error, KeyboardInterrupt, SystemExit): + except py.error.Error: raise except EnvironmentError, e: if not hasattr(e, 'errno'): 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 Mon Jan 17 16:13:19 2005 @@ -114,14 +114,14 @@ def test_ensure_filepath_withoutdir(self): tmpdir = self.tmpdir - newfile = tmpdir.join('test1') + newfile = tmpdir.join('test1file') t = newfile.ensure() assert t == newfile assert newfile.check(file=1) def test_ensure_dirpath(self): tmpdir = self.tmpdir - newfile = tmpdir.join('test1','test2') + newfile = tmpdir.join('test1','test2file') t = newfile.ensure(dir=1) assert t == newfile assert newfile.check(dir=1) From hpk at codespeak.net Tue Jan 18 11:18:12 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 18 Jan 2005 11:18:12 +0100 (MET) Subject: [py-svn] r8369 - py/dist/py Message-ID: <20050118101812.59C4B27BB9@code1.codespeak.net> Author: hpk Date: Tue Jan 18 11:18:11 2005 New Revision: 8369 Modified: py/dist/py/initpkg.py Log: modules at pkg-root level are imported non-lazily but we can only do that if we installed all the lazy hooks because importing the non-lazy module may require the lazy ones ... Modified: py/dist/py/initpkg.py ============================================================================== --- py/dist/py/initpkg.py (original) +++ py/dist/py/initpkg.py Tue Jan 18 11:18:11 2005 @@ -193,6 +193,7 @@ # bootstrap Package object pkg = Package(pkgname, exportdefs) seen = { pkgname : pkg.module } + deferred_imports = [] for pypath, extpy in pkg.exportitems(): pyparts = pypath.split('.') @@ -211,6 +212,8 @@ if not hasattr(mod, '__map__'): assert mod is pkg.module, \ "only root modules are allowed to be non-lazy. " - setattr(mod, pyparts[-1], pkg._resolve(extpy)) + deferred_imports.append((mod, pyparts[-1], extpy)) else: mod.__map__[pyparts[-1]] = extpy + for mod, pypart, extpy in deferred_imports: + setattr(mod, pypart, pkg._resolve(extpy)) From hpk at codespeak.net Tue Jan 18 13:01:01 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 18 Jan 2005 13:01:01 +0100 (MET) Subject: [py-svn] r8376 - in py/dist/py/misc: . testing Message-ID: <20050118120101.4272327BBE@code1.codespeak.net> Author: hpk Date: Tue Jan 18 13:01:01 2005 New Revision: 8376 Modified: py/dist/py/misc/cache.py py/dist/py/misc/testing/test_cache.py Log: fix AgingCache interaction Modified: py/dist/py/misc/cache.py ============================================================================== --- py/dist/py/misc/cache.py (original) +++ py/dist/py/misc/cache.py Tue Jan 18 13:01:01 2005 @@ -43,7 +43,7 @@ class BasicCache(object): def __init__(self, maxentries=128): self.maxentries = maxentries - self.prunenum = maxentries - int(maxentries/8) + self.prunenum = int(maxentries - maxentries/8) self._lock = py.std.threading.RLock() self._dict = {} @@ -150,8 +150,8 @@ class AgingEntry(object): def __init__(self, value, expirationtime): self.value = value - self.expirationtime = expirationtime + self.weight = expirationtime def isexpired(self): t = py.std.time.time() - return t >= self.expirationtime + return t >= self.weight Modified: py/dist/py/misc/testing/test_cache.py ============================================================================== --- py/dist/py/misc/testing/test_cache.py (original) +++ py/dist/py/misc/testing/test_cache.py Tue Jan 18 13:01:01 2005 @@ -51,5 +51,13 @@ def test_cache_eviction(self): self.cache.getorbuild(17, lambda: 17) - py.std.time.sleep(self.maxsecs*1.1) + py.std.time.sleep(self.maxsecs*1.3) assert self.cache.getentry(17) is None + +def test_prune_lowestweight(): + maxsecs = 0.05 + cache = AgingCache(maxentries=10, maxseconds=maxsecs) + for x in range(cache.maxentries): + cache.getorbuild(x, lambda: x) + py.std.time.sleep(maxsecs*1.1) + cache.getorbuild(cache.maxentries+1, lambda: 42) From hpk at codespeak.net Tue Jan 18 13:28:10 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 18 Jan 2005 13:28:10 +0100 (MET) Subject: [py-svn] r8377 - py/dist/py/test/report/text Message-ID: <20050118122810.36A7F27B5A@code1.codespeak.net> Author: hpk Date: Tue Jan 18 13:28:09 2005 New Revision: 8377 Modified: py/dist/py/test/report/text/reporter.py Log: make the default reporter a bit nicer (IMO, feel free to suggest different default behaviour) Modified: py/dist/py/test/report/text/reporter.py ============================================================================== --- py/dist/py/test/report/text/reporter.py (original) +++ py/dist/py/test/report/text/reporter.py Tue Jan 18 13:28:09 2005 @@ -85,31 +85,29 @@ def open_Module(self, collector): verbose = self.option.verbose - if verbose < 1: - return numunits = len(list(collector.iterunits())) if numunits > 0: - #if verbose < 2: - # self.out.write('%s[%d]' % (collector.extpy, - # numunits)) - #else: - #self.out.line("collector.fspy.modpath) - return self.out.line + fspath = collector.extpy.root + if verbose == 0: + parts = fspath.parts() + basename = parts.pop().basename + while parts and parts[-1].basename in ('testing', 'test'): + parts.pop() + base = parts[-1].basename + if len(base) < 13: + base = base + "_" * (13-len(base)) + abbrev_fn = base + "_" + basename + self.out.write('%s[%d] ' % (abbrev_fn, numunits)) + return self.out.line + elif verbose > 0: + #curdir = py.path.local() + #if fspath.check(local=True, relto=curdir): + # fspath = fspath.relto(curdir) + self.out.line() + self.out.line("+ testmodule: %s" % fspath) def open_Directory(self, collector): - if self.option.verbose < 1: - return - l = [] - for x in collector: - l.append(x) - break - if l: - self.out.line('%-13s %s' %('+ directory start ', collector.fspath)) - if self.option.verbose >=1: - def close_directory(): - self.out.line('%-13s %s' %('- directory finish', collector.fspath)) - self.out.line() - return close_directory + return def startitem(self, item): if self.option.collectonly: From hpk at codespeak.net Tue Jan 18 13:43:42 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 18 Jan 2005 13:43:42 +0100 (MET) Subject: [py-svn] r8378 - py/dist/py/path/svn Message-ID: <20050118124342.4C0BD27B5C@code1.codespeak.net> Author: hpk Date: Tue Jan 18 13:43:42 2005 New Revision: 8378 Modified: py/dist/py/path/svn/urlcommand.py py/dist/py/path/svn/wccommand.py Log: be a bit careful with respect to spaces in filenames (but we should start to use .sysexec() here anyway ...) Modified: py/dist/py/path/svn/urlcommand.py ============================================================================== --- py/dist/py/path/svn/urlcommand.py (original) +++ py/dist/py/path/svn/urlcommand.py Tue Jan 18 13:43:42 2005 @@ -38,7 +38,7 @@ l = ['svn %s -r %d' % (cmd, self.rev)] args = map(lambda x: '"%s"' % str(x), args) l.extend(args) - l.append(str(self.strpath)) + l.append(repr(self.strpath)) # fixing the locale because we can't otherwise parse string = svncommon.fixlocale() + " ".join(l) #print "execing", string @@ -49,7 +49,7 @@ l = ['svn %s' % cmd] args = map(lambda x: '"%s"' % str(x), args) l.extend(args) - l.append(str(self.strpath)) + l.append(repr(self.strpath)) # fixing the locale because we can't otherwise parse string = svncommon.fixlocale() + " ".join(l) #print "execing", string Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Tue Jan 18 13:43:42 2005 @@ -57,7 +57,7 @@ l = ['svn %s' % cmd] args = map(lambda x: '"%s"' % x, args) l.extend(args) - l.append(self.strpath) + l.append(repr(self.strpath)) # try fixing the locale because we can't otherwise parse string = svncommon.fixlocale() + " ".join(l) if DEBUG: From hpk at codespeak.net Wed Jan 19 14:19:40 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 19 Jan 2005 14:19:40 +0100 (MET) Subject: [py-svn] r8414 - py/dist/py/test/report/text Message-ID: <20050119131940.A288627B5A@code1.codespeak.net> Author: hpk Date: Wed Jan 19 14:19:40 2005 New Revision: 8414 Modified: py/dist/py/test/report/text/summary.py Log: for tracebacks longer than one entry print the original failing test at the very end of the traceback. (especially useful for long tracebacks i think) Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Wed Jan 19 14:19:40 2005 @@ -86,9 +86,15 @@ if res: self.repr_out_err(res) if entry == last: + if res: + fn, lineno = res.item.extpy.getfilelineno() + if (fn != entry.frame.code.path or + entry.frame.code.firstlineno != lineno): + self.out.line("[test was: %s:%d]" % (fn, lineno)) self.out.sep("_") else: self.out.sep("_ ") + def repr_source(self, entry, marker=">"): try: From hpk at codespeak.net Wed Jan 19 14:39:10 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 19 Jan 2005 14:39:10 +0100 (MET) Subject: [py-svn] r8415 - py/dist/py/path/svn Message-ID: <20050119133910.349BB27B5A@code1.codespeak.net> Author: hpk Date: Wed Jan 19 14:39:10 2005 New Revision: 8415 Modified: py/dist/py/path/svn/urlcommand.py Log: proper url encoding for svnurl's (otherwise spaces don'T work at least with recent svn's) Modified: py/dist/py/path/svn/urlcommand.py ============================================================================== --- py/dist/py/path/svn/urlcommand.py (original) +++ py/dist/py/path/svn/urlcommand.py Wed Jan 19 14:39:10 2005 @@ -38,7 +38,7 @@ l = ['svn %s -r %d' % (cmd, self.rev)] args = map(lambda x: '"%s"' % str(x), args) l.extend(args) - l.append(repr(self.strpath)) + l.append(repr(self._encodedurl())) # fixing the locale because we can't otherwise parse string = svncommon.fixlocale() + " ".join(l) #print "execing", string @@ -49,7 +49,7 @@ l = ['svn %s' % cmd] args = map(lambda x: '"%s"' % str(x), args) l.extend(args) - l.append(repr(self.strpath)) + l.append(repr(self._encodedurl())) # fixing the locale because we can't otherwise parse string = svncommon.fixlocale() + " ".join(l) #print "execing", string @@ -61,6 +61,12 @@ raise return out + def _encodedurl(self): + scheme, rest = self.strpath.split(':', 1) + rest = py.std.urllib.quote(rest) + return "%s:%s" %(scheme, rest) + + def open(self, mode='r'): assert 'w' not in mode and 'a' not in mode, "XXX not implemented for svn cmdline" assert self.check(file=1) # svn cat returns an empty file otherwise From hpk at codespeak.net Wed Jan 19 14:39:22 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 19 Jan 2005 14:39:22 +0100 (MET) Subject: [py-svn] r8416 - py/dist/py/path/svn/testing Message-ID: <20050119133922.86BCD27B5A@code1.codespeak.net> Author: hpk Date: Wed Jan 19 14:39:22 2005 New Revision: 8416 Added: py/dist/py/path/svn/testing/repotest.dump - copied unchanged from r8377, py/dist/py/path/svn/testing/testrepo.dump Removed: py/dist/py/path/svn/testing/testrepo.dump Modified: py/dist/py/path/svn/testing/svntestbase.py Log: rename for better tab completion Modified: py/dist/py/path/svn/testing/svntestbase.py ============================================================================== --- py/dist/py/path/svn/testing/svntestbase.py (original) +++ py/dist/py/path/svn/testing/svntestbase.py Wed Jan 19 14:39:22 2005 @@ -4,7 +4,7 @@ from py.__impl__.path.svn import cache mypath = py.magic.autopath() -repodump = mypath.dirpath('testrepo.dump') +repodump = mypath.dirpath('repotest.dump') # make a wc directory out of a given root url # cache previously obtained wcs! Deleted: /py/dist/py/path/svn/testing/testrepo.dump ============================================================================== --- /py/dist/py/path/svn/testing/testrepo.dump Wed Jan 19 14:39:22 2005 +++ (empty file) @@ -1,228 +0,0 @@ -SVN-fs-dump-format-version: 2 - -UUID: 876a30f4-1eed-0310-aeb7-ae314d1e5934 - -Revision-number: 0 -Prop-content-length: 56 -Content-length: 56 - -K 8 -svn:date -V 27 -2005-01-07T23:55:31.755989Z -PROPS-END - -Revision-number: 1 -Prop-content-length: 118 -Content-length: 118 - -K 7 -svn:log -V 20 -testrepo setup rev 1 -K 10 -svn:author -V 3 -hpk -K 8 -svn:date -V 27 -2005-01-07T23:55:37.815386Z -PROPS-END - -Node-path: execfile -Node-kind: file -Node-action: add -Prop-content-length: 10 -Text-content-length: 4 -Text-content-md5: d4b5bc61e16310f08c5d11866eba0a22 -Content-length: 14 - -PROPS-END -x=42 - -Node-path: otherdir -Node-kind: dir -Node-action: add -Prop-content-length: 10 -Content-length: 10 - -PROPS-END - - -Node-path: otherdir/__init__.py -Node-kind: file -Node-action: add -Prop-content-length: 10 -Text-content-length: 0 -Text-content-md5: d41d8cd98f00b204e9800998ecf8427e -Content-length: 10 - -PROPS-END - - -Node-path: otherdir/a.py -Node-kind: file -Node-action: add -Prop-content-length: 10 -Text-content-length: 30 -Text-content-md5: 247c7daeb2ee5dcab0aba7bd12bad665 -Content-length: 40 - -PROPS-END -from b import stuff as result - - -Node-path: otherdir/b.py -Node-kind: file -Node-action: add -Prop-content-length: 10 -Text-content-length: 15 -Text-content-md5: c1b13503469a7711306d03a4b0721bc6 -Content-length: 25 - -PROPS-END -stuff="got it" - - -Node-path: otherdir/c.py -Node-kind: file -Node-action: add -Prop-content-length: 10 -Text-content-length: 75 -Text-content-md5: 250cdb6b5df68536152c681f48297569 -Content-length: 85 - -PROPS-END -import py; py.magic.autopath() -import otherdir.a -value = otherdir.a.result - - -Node-path: otherdir/d.py -Node-kind: file -Node-action: add -Prop-content-length: 10 -Text-content-length: 72 -Text-content-md5: 940c9c621e7b198e081459642c37f5a7 -Content-length: 82 - -PROPS-END -import py; py.magic.autopath() -from otherdir import a -value2 = a.result - - -Node-path: sampledir -Node-kind: dir -Node-action: add -Prop-content-length: 10 -Content-length: 10 - -PROPS-END - - -Node-path: sampledir/otherfile -Node-kind: file -Node-action: add -Prop-content-length: 10 -Text-content-length: 0 -Text-content-md5: d41d8cd98f00b204e9800998ecf8427e -Content-length: 10 - -PROPS-END - - -Node-path: samplefile -Node-kind: file -Node-action: add -Prop-content-length: 40 -Text-content-length: 11 -Text-content-md5: 9225ac28b32156979ab6482b8bb5fb8c -Content-length: 51 - -K 13 -svn:eol-style -V 6 -native -PROPS-END -samplefile - - -Node-path: samplepickle -Node-kind: file -Node-action: add -Prop-content-length: 10 -Text-content-length: 56 -Text-content-md5: 719d85c1329a33134bb98f56b756c545 -Content-length: 66 - -PROPS-END -(dp1 -S'answer' -p2 -I42 -sI1 -I2 -sS'hello' -p3 -S'world' -p4 -s. - -Revision-number: 2 -Prop-content-length: 108 -Content-length: 108 - -K 7 -svn:log -V 10 -second rev -K 10 -svn:author -V 3 -hpk -K 8 -svn:date -V 27 -2005-01-07T23:55:39.223202Z -PROPS-END - -Node-path: anotherfile -Node-kind: file -Node-action: add -Prop-content-length: 10 -Text-content-length: 5 -Text-content-md5: 5d41402abc4b2a76b9719d911017c592 -Content-length: 15 - -PROPS-END -hello - -Revision-number: 3 -Prop-content-length: 106 -Content-length: 106 - -K 7 -svn:log -V 9 -third rev -K 10 -svn:author -V 3 -hpk -K 8 -svn:date -V 27 -2005-01-07T23:55:41.556642Z -PROPS-END - -Node-path: anotherfile -Node-kind: file -Node-action: change -Text-content-length: 5 -Text-content-md5: 7d793037a0760186574b0282f2f435e7 -Content-length: 5 - -world - From hpk at codespeak.net Wed Jan 19 15:07:23 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 19 Jan 2005 15:07:23 +0100 (MET) Subject: [py-svn] r8417 - py/dist/py/test/report/text Message-ID: <20050119140723.B1CB727B5A@code1.codespeak.net> Author: hpk Date: Wed Jan 19 15:07:23 2005 New Revision: 8417 Modified: py/dist/py/test/report/text/summary.py Log: reporter fix: show more information about what test failed where (and provide the "module path" which can differ from the failing path because of inheritance). with a bit more work the reporter could determine the class a test method is defined on and print that i guess ... well ... :-) Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Wed Jan 19 15:07:23 2005 @@ -87,10 +87,16 @@ self.repr_out_err(res) if entry == last: if res: + root = res.item.extpy.root + modpath = res.item.extpy.modpath fn, lineno = res.item.extpy.getfilelineno() - if (fn != entry.frame.code.path or - entry.frame.code.firstlineno != lineno): - self.out.line("[test was: %s:%d]" % (fn, lineno)) + 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.line("[modulepath: %s]" %(modpath)) + else: + self.out.line("[modulepath: %s %s]" %(root.basename, modpath)) self.out.sep("_") else: self.out.sep("_ ") From hpk at codespeak.net Wed Jan 19 15:16:56 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 19 Jan 2005 15:16:56 +0100 (MET) Subject: [py-svn] r8419 - py/dist/py/test/report/text Message-ID: <20050119141656.89F5127B5B@code1.codespeak.net> Author: hpk Date: Wed Jan 19 15:16:56 2005 New Revision: 8419 Modified: py/dist/py/test/report/text/summary.py Log: prevent double reinterpretation Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Wed Jan 19 15:16:56 2005 @@ -148,7 +148,8 @@ def repr_failure_explanation(self, excinfo, indent): info = None - if not self.option.nomagic: + info = getattr(getattr(excinfo, 'value', ''), 'msg', '') + if not info and not self.option.nomagic: try: info = excinfo.traceback[-1].reinterpret() # very detailed info except KeyboardInterrupt: From hpk at codespeak.net Sat Jan 22 00:08:07 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 22 Jan 2005 00:08:07 +0100 (MET) Subject: [py-svn] r8463 - py/dist/py/test/report/text Message-ID: <20050121230807.2CB4D27B7B@code1.codespeak.net> Author: hpk Date: Sat Jan 22 00:08:06 2005 New Revision: 8463 Modified: py/dist/py/test/report/text/out.py py/dist/py/test/report/text/reporter.py py/dist/py/test/report/text/summary.py Log: small fixes/remove unused code Modified: py/dist/py/test/report/text/out.py ============================================================================== --- py/dist/py/test/report/text/out.py (original) +++ py/dist/py/test/report/text/out.py Sat Jan 22 00:08:06 2005 @@ -65,7 +65,8 @@ self.write(s) def getout(file): - # investigate further into terminal, this is not enough + # XXX investigate further into terminal output, this is not enough + # if False and file.isatty(): return TerminalOut(file) else: Modified: py/dist/py/test/report/text/reporter.py ============================================================================== --- py/dist/py/test/report/text/reporter.py (original) +++ py/dist/py/test/report/text/reporter.py Sat Jan 22 00:08:06 2005 @@ -196,14 +196,6 @@ else: raise TypeError, "not a result instance: %r" % testresult - #def raiseloc(self, excinfo): - # """ return (origin, offendingline) for the given traceback. """ - # tb = excinfo[2] - # origin = misc.getfileloc(tb) - # offendingline = misc.getline(tb) - # return (origin, offendingline) - - def repr_pythonversion(): v = py.std.sys.version_info try: Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Sat Jan 22 00:08:06 2005 @@ -83,8 +83,6 @@ self.out.line("") self.out.line("[%s:%d]" %(entry.frame.code.path, entry.lineno+1)) self.repr_locals(entry) - if res: - self.repr_out_err(res) if entry == last: if res: root = res.item.extpy.root @@ -97,6 +95,8 @@ self.out.line("[modulepath: %s]" %(modpath)) else: self.out.line("[modulepath: %s %s]" %(root.basename, modpath)) + if res: + self.repr_out_err(res) self.out.sep("_") else: self.out.sep("_ ") From hpk at codespeak.net Sat Jan 22 00:11:55 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 22 Jan 2005 00:11:55 +0100 (MET) Subject: [py-svn] r8464 - in py/dist/py/path: . local local/testing svn svn/testing testing Message-ID: <20050121231155.95A6327B80@code1.codespeak.net> Author: hpk Date: Sat Jan 22 00:11:55 2005 New Revision: 8464 Removed: py/dist/py/path/local/api.py Modified: py/dist/py/path/common.py py/dist/py/path/local/local.py py/dist/py/path/local/posix.py py/dist/py/path/local/testing/test_posix.py py/dist/py/path/svn/svncommon.py py/dist/py/path/svn/testing/svntestbase.py py/dist/py/path/svn/urlcommand.py py/dist/py/path/testing/fscommon.py Log: fixed long-standing svn-test-skips (therefore implemented svnurl.ensure() ...) some refactoring of the testing code remove some unused code Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Sat Jan 22 00:11:55 2005 @@ -79,6 +79,9 @@ return False return True +class _dummyclass: + pass + class PathBase(object): """ shared implementation for filesystem path objects.""" Checkers = Checkers @@ -163,33 +166,30 @@ def __repr__(self): return repr(str(self)) - def visit(self, fil=None, rec=None, ignore=None): + def visit(self, fil=None, rec=None, ignore=_dummyclass): if isinstance(fil, str): fil = fnmatch(fil) - if isinstance(rec, str): - rec = fnmatch(fil) - if ignore: + if rec: + if isinstance(rec, str): + rec = fnmatch(fil) + elif not callable(rec): + rec = lambda x: True + reclist = [self] + while reclist: + current = reclist.pop(0) try: - dirlist = self.listdir() + dirlist = current.listdir() except ignore: return - else: - dirlist = self.listdir() - checkdir = py.path.checker(dir=1) - reclist = [] - for p in dirlist: - if fil is None or fil(p): - yield p - if checkdir(p) and (rec is None or rec(p)): - reclist.append(p) - - for p in reclist: - for i in p.visit(fil, rec, ignore=ignore): - yield i + for p in dirlist: + if fil is None or fil(p): + yield p + if p.check(dir=1) and (rec is None or rec(p)): + reclist.append(p) def _callex(self, func, *args): """ call a function and raise errno-exception if applicable. """ - #__tracebackhide__ = True + __tracebackhide__ = True try: return func(*args) except py.error.Error: @@ -197,7 +197,7 @@ except EnvironmentError, e: if not hasattr(e, 'errno'): raise - #__tracebackhide__ = False + __tracebackhide__ = False cls, value, tb = sys.exc_info() errno = e.errno try: @@ -212,7 +212,7 @@ except KeyError: raise cls, value, tb value = cls("%s%r" % (func.__name__, args)) - #__tracebackhide__ = True + __tracebackhide__ = True raise cls, value class fnmatch: @@ -408,3 +408,4 @@ # fall-back __tracebackhide__ = True return old_import_hook(name, glob, loc, fromlist) + Deleted: /py/dist/py/path/local/api.py ============================================================================== --- /py/dist/py/path/local/api.py Sat Jan 22 00:11:55 2005 +++ (empty file) @@ -1,77 +0,0 @@ -""" -Tool functions regarding local filesystem paths -""" -from py import path - -def get_temproot(): - """ return the system's temporary directory (where tempfiles are usually created in)""" - p = mkdtemp() - try: - return p.dirpath() - finally: - p.remove() - -def mkdtemp(): - """ return a Path object pointing to a fresh new temporary directory - (which we created ourself). - """ - import tempfile - tries = 10 - for i in range(tries): - dname = tempfile.mktemp() - dpath = path.local(tempfile.mktemp()) - try: - dpath.mkdir() - except path.FileExists: - continue - return dpath - raise py.error.EAGAIN("could not create tempdir, %d tries" % tries) - -def make_numbered_dir(rootdir=None, base = 'session-', keep=3): - """ return unique directory with a number greater than the current - maximum one. The number is assumed to start directly after base. - if keep is true directories with a number less than (maxnum-keep) - will be removed. - """ - if rootdir is None: - rootdir = get_temproot() - - def parse_num(path): - """ parse the number out of a path (if it matches the base) """ - bn = path.basename - if bn.startswith(base): - try: - return int(bn[len(base):]) - except TypeError: - pass - - # compute the maximum number currently in use with the base - maxnum = -1 - for path in rootdir.listdir(): - num = parse_num(path) - if num is not None: - maxnum = max(maxnum, num) - - # make the new directory - udir = rootdir.mkdir(base + str(maxnum+1)) - - # prune old directories - if keep: - for path in rootdir.listdir(): - num = parse_num(path) - if num is not None and num <= (maxnum - keep): - path.remove(rec=1) - return udir - -def parentdirmatch(dirname, startmodule=None): - if startmodule is None: - fn = path.local() - else: - mod = path.py(startmodule) - fn = mod.getfile() - current = fn.dirpath() - while current != fn: - fn = current - if current.basename == dirname: - return current - current = current.dirpath() Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Sat Jan 22 00:11:55 2005 @@ -411,11 +411,7 @@ """ return the system's temporary directory (where tempfiles are usually created in) """ - p = cls.mkdtemp() - try: - return p.dirpath() - finally: - p.remove() + return py.path.local(py.std.tempfile.gettempdir()) get_temproot = classmethod(get_temproot) def mkdtemp(cls): @@ -475,21 +471,6 @@ return udir make_numbered_dir = classmethod(make_numbered_dir) - #def parentdirmatch(cls, dirname, startmodule=None): - # """ ??? """ - # if startmodule is None: - # fn = path.local() - # else: - # mod = path.py(startmodule) - # fn = mod.getfile() - # current = fn.dirpath() - # while current != fn: - # fn = current - # if current.basename() == dirname: - # return current - # current = current.dirpath() - #parentdirmatch = classmethod(parentdirmatch) - def copychunked(src, dest): chunksize = 524288 # half a meg of bytes fsrc = src.open('rb') Modified: py/dist/py/path/local/posix.py ============================================================================== --- py/dist/py/path/local/posix.py (original) +++ py/dist/py/path/local/posix.py Sat Jan 22 00:11:55 2005 @@ -38,7 +38,7 @@ if not isinstance(mode, int): raise TypeError("mode %r must be an integer" % (mode,)) if rec: - for x in self.visit(): + for x in self.visit(rec=rec): self._callex(os.chmod, str(x), mode) self._callex(os.chmod, str(self), mode) 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 Sat Jan 22 00:11:55 2005 @@ -1,111 +1,85 @@ import py -import sys -from py.__impl__.path.testing.fscommon import setuptestfs -checker = py.path.checker -local = py.path.local class TestPOSIXLocalPath: #root = local(TestLocalPath.root) - disabled = sys.platform == 'win32' + disabled = py.std.sys.platform == 'win32' def setup_class(cls): cls.root = py.test.config.tmpdir / 'TestPosixLocalPath' - cls.root.ensure(dir=1) - setuptestfs(cls.root) + + def setup_method(self, method): + name = method.im_func.func_name + self.tmpdir = self.root.ensure(name, dir=1) def test_hardlink(self): - tmpdir = local(local.mkdtemp()) - try: - linkpath = tmpdir.join('test') - filepath = tmpdir.join('file') - filepath.write("Hello") - linkpath.mklinkto(filepath) - assert filepath.read() == linkpath.read() - finally: - tmpdir.remove(rec=1) + tmpdir = self.tmpdir + linkpath = tmpdir.join('test') + filepath = tmpdir.join('file') + filepath.write("Hello") + nlink = filepath.stat().st_nlink + linkpath.mklinkto(filepath) + assert filepath.stat().st_nlink == nlink + 1 def test_symlink_are_identical(self): - tmpdir = local(local.mkdtemp()) - try: - filepath = tmpdir.join('file') - filepath.write("Hello") - linkpath = tmpdir.join('test') - linkpath.mksymlinkto(filepath) - assert filepath.read() == linkpath.read() - finally: - tmpdir.remove(rec=1) + tmpdir = self.tmpdir + filepath = tmpdir.join('file') + filepath.write("Hello") + linkpath = tmpdir.join('test') + linkpath.mksymlinkto(filepath) + assert linkpath.readlink() == str(filepath) def test_symlink_isfile(self): - tmpdir = local(local.mkdtemp()) - try: - linkpath = tmpdir.join('test') - filepath = tmpdir.join('file') - filepath.write("") - linkpath.mksymlinkto(filepath) - assert linkpath.check(file=1) - assert not linkpath.check(link=0, file=1) - finally: - tmpdir.remove(rec=1) + tmpdir = self.tmpdir + linkpath = tmpdir.join('test') + filepath = tmpdir.join('file') + filepath.write("") + linkpath.mksymlinkto(filepath) + assert linkpath.check(file=1) + assert not linkpath.check(link=0, file=1) def test_symlink_relative(self): - tmpdir = local(local.mkdtemp()) - try: - linkpath = tmpdir.join('test') - filepath = tmpdir.join('file') - filepath.write("Hello") - linkpath.mksymlinkto(filepath, absolute=False) - assert linkpath.readlink() == "file" - assert filepath.read() == linkpath.read() - finally: - tmpdir.remove(rec=1) + tmpdir = self.tmpdir + linkpath = tmpdir.join('test') + filepath = tmpdir.join('file') + filepath.write("Hello") + linkpath.mksymlinkto(filepath, absolute=False) + assert linkpath.readlink() == "file" + assert filepath.read() == linkpath.read() def test_relto_with_root(self): y = self.root.join('x').relto(py.path.local('/')) assert y[0] == str(self.root)[1] def test_visit_recursive_symlink(self): - tmpdir = local.mkdtemp() - try: - linkpath = tmpdir.join('test') - linkpath.mksymlinkto(tmpdir) - visitor = tmpdir.visit(None, checker(link=0)) - assert list(visitor) == [linkpath] - #check.equal(list(tmpdir.visit()), [linkpath]) - finally: - tmpdir.remove(rec=1) + tmpdir = self.tmpdir + linkpath = tmpdir.join('test') + linkpath.mksymlinkto(tmpdir) + visitor = tmpdir.visit(None, py.path.checker(link=0)) + assert list(visitor) == [linkpath] def test_symlink_isdir(self): - tmpdir = local.mkdtemp() - try: - linkpath = tmpdir.join('test') - linkpath.mksymlinkto(tmpdir) - assert linkpath.check(dir=1) - assert not linkpath.check(link=0, dir=1) - finally: - tmpdir.remove(rec=1) + tmpdir = self.tmpdir + linkpath = tmpdir.join('test') + linkpath.mksymlinkto(tmpdir) + assert linkpath.check(dir=1) + assert not linkpath.check(link=0, dir=1) def test_symlink_remove(self): - tmpdir = local.mkdtemp().realpath() - try: - linkpath = tmpdir.join('test') - linkpath.mksymlinkto(linkpath) # point to itself - assert linkpath.check(link=1) - linkpath.remove() - assert not linkpath.check() - finally: - tmpdir.remove(rec=1) + tmpdir = self.tmpdir.realpath() + linkpath = tmpdir.join('test') + linkpath.mksymlinkto(linkpath) # point to itself + assert linkpath.check(link=1) + linkpath.remove() + assert not linkpath.check() def test_realpath_file(self): - tmpdir = local.mkdtemp() - try: - linkpath = tmpdir.join('test') - filepath = tmpdir.join('file') - filepath.write("") - linkpath.mksymlinkto(filepath) - realpath = linkpath.realpath() - assert realpath.basename == 'file' - finally: - tmpdir.remove(rec=1) + tmpdir = self.tmpdir + linkpath = tmpdir.join('test') + filepath = tmpdir.join('file') + filepath.write("") + linkpath.mksymlinkto(filepath) + realpath = linkpath.realpath() + assert realpath.basename == 'file' def test_owner(self): from pwd import getpwuid @@ -126,21 +100,20 @@ path.read(1) assert path.atime() != atime - def testcommondir(self): + def test_commondir(self): # XXX This is here in local until we find a way to implement this # using the subversion command line api. p1 = self.root.join('something') p2 = self.root.join('otherthing') - assert p1.commondir(p2) == self.root - assert p2.commondir(p1) == self.root + assert p1.common(p2) == self.root + assert p2.common(p1) == self.root - def testcommondir_nocommon(self): + def test_commondir_nocommon(self): # XXX This is here in local until we find a way to implement this # using the subversion command line api. p1 = self.root.join('something') - p2 = local(os.sep+'blabla') - assert p1.commondir(p2) is None - + p2 = py.path.local(self.root.sep+'blabla') + assert p1.common(p2) == '/' def test_chmod_simple_int(self): print "self.root is", self.root @@ -155,11 +128,11 @@ def test_chmod_rec_int(self): # XXX fragile test print "self.root is", self.root - recfilter = checker(dotfile=0) + recfilter = py.path.checker(dotfile=0, link=0) oldmodes = {} for x in self.root.visit(rec=recfilter): oldmodes[x] = x.mode() - self.root.chmod(0772, rec=1) + self.root.chmod(0772, rec=recfilter) try: for x in self.root.visit(rec=recfilter): assert x.mode() & 0777 == 0772 Modified: py/dist/py/path/svn/svncommon.py ============================================================================== --- py/dist/py/path/svn/svncommon.py (original) +++ py/dist/py/path/svn/svncommon.py Sat Jan 22 00:11:55 2005 @@ -135,8 +135,8 @@ if len(nameinfo_seq) == 1: name, info = nameinfo_seq[0] if name == self.basename and info.kind == 'file': - if not self.check(dir=1): - raise py.error.ENOTDIR(self) + #if not self.check(dir=1): + raise py.error.ENOTDIR(self) paths = self._make_path_tuple(nameinfo_seq) if fil or sort: Modified: py/dist/py/path/svn/testing/svntestbase.py ============================================================================== --- py/dist/py/path/svn/testing/svntestbase.py (original) +++ py/dist/py/path/svn/testing/svntestbase.py Sat Jan 22 00:11:55 2005 @@ -31,14 +31,38 @@ wc = py.path.svnwc(wcdir) return ("file://%s" % repo, wc) +def save_repowc(): + repo, wc = getrepowc() + repo = py.path.local(repo[len("file://"):]) + assert repo.check() + savedrepo = repo.dirpath('repo_save') + savedwc = wc.dirpath('wc_save') + repo.copy(savedrepo) + wc.localpath.copy(savedwc.localpath) + return savedrepo, savedwc + +def restore_repowc((savedrepo, savedwc)): + repo, wc = getrepowc() + repo = py.path.local(repo[len("file://"):]) + assert repo.check() + repo.remove() + wc.localpath.remove() + savedrepo.move(repo) + savedwc.localpath.move(wc.localpath) + class CommonSvnTests(CommonFSTests): def setup_method(self, meth): bn = meth.func_name for x in 'test_remove', 'test_move': if bn.startswith(x): - py.test.skip( - "tests for modifying svn needs better test state management") + self._savedrepowc = save_repowc() + + def teardown_method(self, meth): + x = getattr(self, '_savedrepowc', None) + if x is not None: + restore_repowc(x) + del self._savedrepowc def test_propget(self): url = self.root.join("samplefile") Modified: py/dist/py/path/svn/urlcommand.py ============================================================================== --- py/dist/py/path/svn/urlcommand.py (original) +++ py/dist/py/path/svn/urlcommand.py Sat Jan 22 00:11:55 2005 @@ -79,6 +79,17 @@ return popen(svncommon.fixlocale() + 'svn cat -r %s "%s"' % (self.rev, self.strpath)) + def dirpath(self, *args, **kwargs): + """ return the directory Path of the current Path joined + with any given path arguments. + """ + l = self.strpath.split(self.sep) + if len(l) < 4: + raise py.error.EINVAL(self, "base is not valid") + elif len(l) == 4: + return self.join(*args, **kwargs) + else: + return self.new(basename='').join(*args, **kwargs) # modifying methods (cache must be invalidated) def mkdir(self, *args, **kwargs): @@ -90,16 +101,57 @@ def copy(self, target, msg='copied by py lib invocation'): if getattr(target, 'rev', None) is not None: - raise py.error.EINVAL(target, "can't copy to revisioned resource") + raise py.error.EINVAL(target, "revisions are immutable") process.cmdexec("svn copy -m %r %s %s" %(msg, str(self), str(target))) self._lsnorevcache.delentry(target.dirpath().strpath) + def rename(self, target, msg="renamed by py lib invocation"): + if getattr(self, 'rev', None) is not None: + raise py.error.EINVAL(self, "revisions are immutable") + py.process.cmdexec("svn move -m %r --force %s %s" %( + msg, str(self), str(target))) + self._lsnorevcache.delentry(self.dirpath().strpath) + self._lsnorevcache.delentry(self.strpath) + def remove(self, rec=1, msg='removed by py lib invocation'): if self.rev is not None: - raise py.error.EINVAL(self, "can't remove revisioned resource") + raise py.error.EINVAL(self, "revisions are immutable") process.cmdexec("svn rm -m %r %s" %(msg, str(self))) self._lsnorevcache.delentry(self.dirpath().strpath) + def ensure(self, *args, **kwargs): + """ ensure that an args-joined path exists (by default as + a file). If you specify a keyword argument 'dir=True' + then the path is forced to be a directory path. + """ + if getattr(self, 'rev', None) is not None: + raise py.error.EINVAL(self, "revisions are immutable") + target = self.join(*args) + dir = kwargs.get('dir', 0) + for x in target.parts(reverse=True): + if x.check(): + break + else: + raise py.error.ENOENT(target, "has not any valid base!") + if x == target: + if not x.check(dir=dir): + raise dir and py.error.ENOTDIR(x) or py.error.EISDIR(x) + return x + tocreate = target.relto(x) + basename = tocreate.split(self.sep, 1)[0] + tempdir = py.path.local.mkdtemp() + try: + tempdir.ensure(tocreate, dir=dir) + cmd = 'svn import -m %r %r %r' % ( + "ensure %s" % tocreate, + str(tempdir.join(basename)), + x.join(basename)._encodedurl()) + process.cmdexec(cmd) + self._lsnorevcache.delentry(x.strpath) # !!! + finally: + tempdir.remove() + return target + # end of modifying methods def _propget(self, name): res = self._svn('propget', name) Modified: py/dist/py/path/testing/fscommon.py ============================================================================== --- py/dist/py/path/testing/fscommon.py (original) +++ py/dist/py/path/testing/fscommon.py Sat Jan 22 00:11:55 2005 @@ -197,20 +197,19 @@ assert tmpdir.join('mktest2') == new def test_move_file(self): - p = self.root.ensure('tomove') - newp = p.new(basename='moved') + p = self.root.join('samplefile') + newp = p.dirpath('samplefile_moved') p.move(newp) assert newp.check(file=1) assert not p.check() def test_move_directory(self): - source = self.root.join('to') - source.ensure('moved', 'somefile').write("42") - dest = source.new(basename='moveddir') + source = self.root.join('sampledir') + dest = self.root.join('moveddir') source.move(dest) assert dest.check(dir=1) - assert dest.join('moved', 'somefile').read() == '42' - assert not source.check() + assert dest.join('otherfile').check(file=1) + assert not source.join('sampledir').check() def test_getpymodule(self): obj = self.root.join('execfile').getpymodule() From hpk at codespeak.net Sat Jan 22 00:13:49 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 22 Jan 2005 00:13:49 +0100 (MET) Subject: [py-svn] r8465 - in py/dist/py/execnet: . testing Message-ID: <20050121231349.3B2E127B80@code1.codespeak.net> Author: hpk Date: Sat Jan 22 00:13:49 2005 New Revision: 8465 Modified: py/dist/py/execnet/channel.py py/dist/py/execnet/gateway.py py/dist/py/execnet/message.py py/dist/py/execnet/register.py py/dist/py/execnet/testing/test_gateway.py Log: cleanup and fix yet more shutdow nissues (now it seems to teardown nicely *tock tock tock*) Modified: py/dist/py/execnet/channel.py ============================================================================== --- py/dist/py/execnet/channel.py (original) +++ py/dist/py/execnet/channel.py Sat Jan 22 00:13:49 2005 @@ -91,6 +91,13 @@ self._items.put(x) raise x return x + + def __iter__(self): + while 1: + try: + yield self.receive() + except EOFError: + raise StopIteration # # helpers Modified: py/dist/py/execnet/gateway.py ============================================================================== --- py/dist/py/execnet/gateway.py (original) +++ py/dist/py/execnet/gateway.py Sat Jan 22 00:13:49 2005 @@ -15,7 +15,7 @@ assert Message and ChannelFactory, "Import/Configuration Error" import os -debug = 0 # or open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') +debug = 0 # or open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') sysex = (KeyboardInterrupt, SystemExit) @@ -74,6 +74,7 @@ RemoteError = RemoteError def __init__(self, io, startcount=2): + self.running = True self.io = io self._execqueue = Queue.Queue() self._outgoing = Queue.Queue() @@ -83,6 +84,7 @@ sender = self.thread_sender) for x in range(self.num_worker_threads): self.pool.start('executor', self.thread_executor) + self.trace("started executor thread") if not _gateways: atexit.register(cleanup_atexit) _gateways.append(self) @@ -95,17 +97,24 @@ R, S, i) def _stopexec(self): - self.pool.prunestopped() - for x in self.pool.getstarted('executor'): + #self.pool.prunestopped() + for x in range(self.num_worker_threads): + self.trace("putting None to execqueue") self._execqueue.put(None) def exit(self): + # note that threads may still be scheduled to start + # during our execution! self._exitlock.acquire() try: - self._stopexec() - if self.pool.getstarted('sender'): - self._outgoing.put(Message.EXIT_GATEWAY()) - #self.join() + if self.running: + self.running = False + self._stopexec() + if self.pool.getstarted('sender'): + self._outgoing.put(Message.EXIT_GATEWAY()) + self.trace("exit procedure triggered, pid %d, gateway %r" % ( + os.getpid(), self)) + _gateways.remove(self) finally: self._exitlock.release() @@ -115,6 +124,7 @@ if x != current: self.trace("joining %s" % x) x.join() + self.trace("joining threads finished, current %r" % current) def trace(self, *args): if debug: @@ -173,6 +183,7 @@ while 1: task = self._execqueue.get() if task is None: + self.trace("executor found none, leaving ...") break channel, source = task try: @@ -231,5 +242,6 @@ if debug: print >>debug, "="*20 + "cleaning up" + "=" * 20 debug.flush() - for x in _gateways: + while _gateways: + x = _gateways[-1] x.exit() Modified: py/dist/py/execnet/message.py ============================================================================== --- py/dist/py/execnet/message.py (original) +++ py/dist/py/execnet/message.py Sat Jan 22 00:13:49 2005 @@ -58,18 +58,18 @@ # bring down the IO and gateway connection # # First an EXIT_GATEWAY message is send which results - # on the other side's receive_handle to send send + # on the other side's receive_handle to send # a STOP_RECEIVING message - # class EXIT_GATEWAY(Message): def received(self, gateway): # executes in receiver thread gateway._stopexec() - gateway._outgoing.put(self.STOP_RECEIVING()) for x in gateway.channelfactory.values(): x._close() + gateway._outgoing.put(self.STOP_RECEIVING()) raise SystemExit def post_sent(self, gateway, excinfo=None): + gateway._stopexec() # executes in sender thread gateway.io.close_write() raise SystemExit Modified: py/dist/py/execnet/register.py ============================================================================== --- py/dist/py/execnet/register.py (original) +++ py/dist/py/execnet/register.py Sat Jan 22 00:13:49 2005 @@ -1,7 +1,7 @@ -from py.magic import autopath ; autopath = autopath() import os, inspect, socket import sys +from py.magic import autopath ; mypath = autopath() import py from py.__impl__.execnet import inputoutput, gateway, channel, message @@ -38,21 +38,20 @@ infile, outfile = os.popen2(cmd) io = inputoutput.Popen2IO(infile, outfile) super(PopenCmdGateway, self).__init__(io=io) - self._pidchannel = self.remote_exec(""" import os channel.send(os.getpid()) """) def exit(self): - if not super(PopenCmdGateway, self).exit(): - return try: self._pidchannel.waitclose(timeout=0.5) pid = self._pidchannel.receive() except IOError: self.trace("could not receive child PID") - else: + pid = None + super(PopenCmdGateway, self).exit() + if pid is not None: self.trace("waiting for pid %s" % pid) try: os.waitpid(pid, 0) @@ -91,6 +90,33 @@ io = inputoutput.SocketIO(sock) InstallableGateway.__init__(self, io=io) + def remote_install(cls, gateway, hostport=None): + """ return a connected socket gateway through the + given gateway. + """ + if hostport is None: + host, port = ('', 0) + else: + host, port = hostport + socketserverbootstrap = py.code.Source( + mypath.dirpath('bin', 'socketserver.py').read(), + """ + import socket + sock = bind_and_listen((%r, %r)) + hostname = socket.gethostname() + channel.send((hostname, sock.getsockname())) + startserver(sock) + """ % (host, port)) + # execute the above socketserverbootstrap on the other side + channel = gateway.remote_exec(socketserverbootstrap) + hostname, (realhost, realport) = channel.receive() + if hostport is None: + realhost = hostname + #gateway.trace("remote_install received" + # "port=%r, hostname = %r" %(realport, hostname)) + return py.execnet.SocketGateway(realhost, realport) + remote_install = classmethod(remote_install) + class SshGateway(PopenCmdGateway): def __init__(self, host, port=None, username=None, remotepython='python'): if port is not None: Modified: py/dist/py/execnet/testing/test_gateway.py ============================================================================== --- py/dist/py/execnet/testing/test_gateway.py (original) +++ py/dist/py/execnet/testing/test_gateway.py Sat Jan 22 00:13:49 2005 @@ -102,6 +102,14 @@ channel._close(gateway.RemoteError("error")) py.test.raises(gateway.RemoteError, channel.waitclose, 0.01) + def test_channel_iter(self): + channel = self.gw.remote_exec(""" + for x in range(3): + channel.send(x) + """) + l = list(channel) + assert l == range(3) + def test_channel_passing_over_channel(self): channel = self.gw.remote_exec(''' c = channel.newchannel() @@ -146,37 +154,12 @@ class SocketGatewaySetup: def setup_class(cls): - cls.port = 7770 - socketserverbootstrap = py.code.Source( - mypath.dirpath().dirpath('bin', 'socketserver.py').read(), - """ - import socket - sock = bind_and_listen(("localhost", %r)) - channel.send("ok") - startserver(sock) - """ % cls.port) # open a gateway to a fresh child process - cls.proxygw = py.execnet.PopenGateway() - - # execute asynchronously the above socketserverbootstrap on the other - channel = cls.proxygw.remote_exec(socketserverbootstrap) - - # the other side should start the socket server now - assert channel.receive() == "ok" - cls.gw = py.execnet.SocketGateway('localhost', cls.port) - print "initialized socket gateway to port", cls.port + cls.proxygw = py.execnet.PopenGateway() + cls.gw = py.execnet.SocketGateway.remote_install(cls.proxygw) def teardown_class(cls): - #print "trying to tear down remote socket gateway" cls.gw.exit() - #if cls.gw.port: - # print "trying to tear down remote socket loop" - # import socket - # sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - # sock.connect(('localhost', cls.gw.port)) - # sock.sendall('"raise KeyboardInterrupt"') - # sock.shutdown(2) - #print "trying to tear proxy gateway" cls.proxygw.exit() class TestSocketGateway(SocketGatewaySetup, BasicRemoteExecution): From hpk at codespeak.net Sat Jan 22 00:37:39 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 22 Jan 2005 00:37:39 +0100 (MET) Subject: [py-svn] r8466 - in py/dist/py: . documentation documentation/example xmlobj xmlobj/testing Message-ID: <20050121233739.1AC9D27B80@code1.codespeak.net> Author: hpk Date: Sat Jan 22 00:37:38 2005 New Revision: 8466 Added: py/dist/py/documentation/example/genhtml.py py/dist/py/documentation/example/genhtmlcss.py py/dist/py/documentation/example/genxml.py py/dist/py/documentation/xml.txt py/dist/py/xmlobj/ (props changed) py/dist/py/xmlobj/__init__.py (contents, props changed) py/dist/py/xmlobj/html.py (contents, props changed) py/dist/py/xmlobj/misc.py (contents, props changed) py/dist/py/xmlobj/testing/ (props changed) py/dist/py/xmlobj/testing/__init__.py (contents, props changed) py/dist/py/xmlobj/testing/test_html.py (contents, props changed) py/dist/py/xmlobj/testing/test_xml.py (contents, props changed) py/dist/py/xmlobj/visit.py (contents, props changed) py/dist/py/xmlobj/xml.py (contents, props changed) Modified: py/dist/py/__init__.py py/dist/py/documentation/execnet.txt py/dist/py/documentation/future.txt py/dist/py/documentation/index.txt Log: another result from my hotel stay in Milano ... new simple, powerful, fast, debuggable html / xml generation code, currently 172 lines of code _including_ clean CSS-styling the python way ... (btw, why do all these "frameworks" out there not care about this?). added documentation (with was moved and extended from the future part of the documentation) added some examples, referenced from the documentation ... see py's website, http://codespeak.net/py for more details. Modified: py/dist/py/__init__.py ============================================================================== --- py/dist/py/__init__.py (original) +++ py/dist/py/__init__.py Sat Jan 22 00:37:38 2005 @@ -54,4 +54,9 @@ 'execnet.SshGateway' : ('./execnet/register.py', 'SshGateway'), 'error' : ('./misc/error.py', 'error'), + + 'xml.html' : ('./xmlobj/html.py', 'html'), + 'xml.Tag' : ('./xmlobj/xml.py', 'Tag'), + 'xml.Namespace' : ('./xmlobj/xml.py', 'Namespace'), + 'xml.escape' : ('./xmlobj/misc.py', 'escape'), }) Added: py/dist/py/documentation/example/genhtml.py ============================================================================== --- (empty file) +++ py/dist/py/documentation/example/genhtml.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1,13 @@ +from py.xml import html + +paras = "First Para", "Second para" + +doc = html.html( + html.head( + html.meta(name="Content-Type", value="text/html; charset=latin1")), + html.body( + [html.p(p) for p in paras])) + +print unicode(doc).encode('latin1') + + Added: py/dist/py/documentation/example/genhtmlcss.py ============================================================================== --- (empty file) +++ py/dist/py/documentation/example/genhtmlcss.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1,23 @@ +import py +html = py.xml.html + +class my: + "a custom style" + class body(html.body): + style = html.Style(font_size = "120%") + + class h2(html.h2): + style = html.Style(background = "grey") + + class p(html.p): + style = html.Style(font_weight="bold") + +doc = html.html( + html.head(), + my.body( + my.h2("hello world"), + my.p("bold as bold can") + ) +) + +print doc.unicode(indent=2) Added: py/dist/py/documentation/example/genxml.py ============================================================================== --- (empty file) +++ py/dist/py/documentation/example/genxml.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1,15 @@ + +import py +ns = py.xml.Namespace() +doc = ns.books( + ns.book( + ns.author("May Day"), + ns.title("python for java programmers"),), + ns.book( + ns.author("why", class_="somecssclass"), + ns.title("Java for Python programmers"),), + publisher="N.N", + ) +print doc.unicode(indent=2).encode('utf8') + + Modified: py/dist/py/documentation/execnet.txt ============================================================================== --- py/dist/py/documentation/execnet.txt (original) +++ py/dist/py/documentation/execnet.txt Sat Jan 22 00:37:38 2005 @@ -101,16 +101,6 @@ Here is the current interface:: # - # attributes API - # - - channel.gateway # the gateway through which this channel operates - - channel.timeout # the default timeout is None, i.e. all operations block - # setting the timeout to a number value indicates the - # timeout in seconds for all operations. - # (not implemented) - # # API for sending and receiving anonymous values # channel.send(item): @@ -133,6 +123,11 @@ reraised as gateway.RemoteError exceptions containing a textual representation of the remote traceback. + channel.close(): + close this channel on both the local and the remote side. + A remote side blocking on receive() on this channel + will get woken up and see an EOFError exception. + A simple and useful Example for Channels ........................................ Modified: py/dist/py/documentation/future.txt ============================================================================== --- py/dist/py/documentation/future.txt (original) +++ py/dist/py/documentation/future.txt Sat Jan 22 00:37:38 2005 @@ -8,8 +8,8 @@ This document tries to describe directions and guiding ideas for the near-future development of the py lib. *Note that all statements within this document - even if they sound factual - -may just express thoughts. They not always refer to real code -so read with some caution. This is not a reference guide +mostly just express thoughts and ideas. They not always refer to +real code so read with some caution. This is not a reference guide (tm).* .. _`general-path`: @@ -26,7 +26,7 @@ But apart from python files there are many other examples of structured content like xml documents or INI-style -config files. While some tasks will only be possible +config files. While some tasks will only be convenient to perform in a domain specific manner (e.g. applying xslt etc.pp) ``py.path`` offers a common behaviour for structured content paths. So far only ``py.path.extpy`` @@ -53,7 +53,7 @@ directories as sections and files as option-names and the content of the file as values. -But it also works (today!) for ``extpy`` paths if you put the following +But it also works (today) for ``extpy`` paths if you put the following python code in a file:: class Section1: @@ -80,7 +80,7 @@ upon read() return the joined content of the text tags possibly as unicode. -Now, to complete the picture, we can make Config-Parser +Now, to complete the picture, we could make Config-Parser *ini-style* config files also available:: [section1] @@ -97,8 +97,7 @@ Of course, the somewhat open question is how to make the transition from a filesystem path to structured content -useful and unified, as much as possible without overdoing it, -of course. +useful and unified, as much as possible without overdoing it. Again, there are tasks that will need fully domain specific solutions (DOM/XSLT/...) but i think the above view warrants @@ -124,7 +123,7 @@ and use it to have a ``extpy`` path living on it:: p = py.path.local(xmlfilename) - xmlp = py.path.xml(p, 'py/magic/exprinfo') + xmlp = py.path.extxml(p, 'py/magic/exprinfo') p = py.path.extpy(xmlp, 'getmsg') assert p.check(func=1, basename='getmsg') @@ -132,13 +131,13 @@ # we now have a *live* getmsg() function taken and compiled from # the above xml fragment -Of course, there could be generic converters which convert between +There could be generic converters which convert between different content formats ... allowing configuration files to e.g. be in XML/Ini/python or filesystem-format with some common way -to check/iterate for values. +to find and iterate values. *After all the unix filesystem and the python namespaces are -two honking great ideas, why not do more of them?* +two honking great ideas, why not do more of them? :-)* .. _importexport: @@ -164,7 +163,8 @@ - it doesn't allow to specify doc-strings - it is a bit hackish (see py/initpkg.py) - it doesn't present a complete and consistent view of the API. -- ``help(constructed_namespace)`` doesn't fully work +- ``help(constructed_namespace)`` doesn't work for the root + package namespace - when the py lib implementation accesses parts of itself it uses the native python import mechanism which is limiting in some respects. Especially for distributed @@ -172,9 +172,9 @@ how the mechanism can nicely integrate to support remote lazy importing. -Discussions have been going on between for a while but it is -still not clear how to best tackle the problem. Personally, i -believe the main missing thing for the first major release +Discussions have been going on for a while but it is +still not clear how to best tackle the problem. Personally, +i believe the main missing thing for the first major release is the docstring one. The current specification of exported names is dictionary based. It would be better to declare it in terms of Objects. @@ -283,8 +283,8 @@ .. _`wrapping techniques PyPy uses`: http://codespeak.net/pypy/index.cgi?doc/wrapping.html .. _`lightweight xml generation`: -Extension of the py.path.local.sysexec() -======================================== +Extension of py.path.local.sysexec() +==================================== The `sysexec mechanism`_ allows to directly execute binaries on your system. Especially after we'll have this @@ -308,117 +308,21 @@ in the neverending `future book`_. .. _`sysexec mechanism`: misc.html#sysexec - - -Lightweight, convenient xml generation -====================================== - -The py lib strives to offer enough functionality to represent -itself and especially its API in html or xml. Moreover, -`py.test`_ wants to run distributedly in order to execute -tests on different processes and platforms. It will need to -`exchange data`_ between its running program fragments. - -For example, test ``results`` could be represented in lightweight -xml or we could export the whole result of the testing process -as xml, anyway, to allow other tools to post-process the output. -The starting point for this, btw, is the `Reporter`_ from the -test module. - -a pythonic object model, please -------------------------------- - -Besides DOM implementations there are some interesting -techniques for marrying XML and python, most notably xist_ -which `uses python class objects`_ to build xml trees. - -However, its implementation seems slightly heavy because it -has additional goals like transformations and supporting -many namespaces. - -Luckily the basic idea is pretty easy to implement, especially -if we don't validate. There already is a basic implementation -with a lot of *py.test-style* tests `under the -xpy tree`_ which was mentioned in Holgers `xpython EuroPython 2004 talk`_ -at EuroPython 2004. However, this is still somewhat entangled with -a different project (see the talk) so it would need some refactoring -before integrating it into the py lib. - -basic example for generating html ---------------------------------- - -Consider this example:: - - import py - html = py.xml.namespace('html') - - paras = "First Para", "Second para" - - doc = html.html( - html.head( - html.meta(name="Content-Type", value="text/html; charset=utf8)) - html.body( - [html.p(p) for p in paras])) - - print unicode(doc).encode('latin1') - -This would print a latin1 representation of the obvious document. -I think the beauty of this is apparent and beats string-concantentation -or DOM-manipulations big time. - -For now, i don't think we should strive to offer much more -than the above. Well, of course, we would like to access a -sane object model for the generated html but this needs some -more experimentations and a comparison with xist_ i guess. - - .. _`compile-on-the-fly`: -Crossing the barriers of compilation -==================================== - -Python developers are very used to the fact -that compilation of python programs happens -automatically. This is unlike Java and C where -you need an explicit compilation step. -With Python, the language does it for you. -With the py lib we extend the **compile-on-the-fly** -notion for other program source than Python. -Well, we start with C-files files but want to make sure -that the mechanism is extensible towards other languages. - -And of course, internally we just reuse `CPython's distutils`_ -which already provides the right abstractions to run the -underlying system compiler. - -development convenience rules ------------------------------ - -As described in the `getting started`_ chapter the main -current method to utilize the py lib is to work from a -subversion checkout. The **compile-on-the-fly** feature -allows us to keep up with this work style. You don't have to -issue any manual ``python setup.py install`` incantations -and you don't have to remember dependency issues. You -can easily add a small C-coded module and make it -seemlessly available through the path object:: - - mod = somepath.getcompiled() - -And you can grab objects from the freshly -compiled C-module. - we need a persistent storage for the py lib ------------------------------------------- A somewhat open question is where to store the underlying -generated object and library files from `CPython's -distutils`_. We probably want to have the possibility of a -*persistent location* in order to avoid runtime-penalties. A -*persistent location* for the py lib would be a good idea -anyway. We could cache some of the expensive test setups, like -the multi-revision subversion repository that is created for -each run of the tests. +generated pyc-files and other files generated on the fly +with `CPython's distutils`_. We want to have a +*persistent location* in order to avoid runtime-penalties +when switching python versions and platforms (think NFS). + +A *persistent location* for the py lib would be a good idea +maybe also for other reasons. We could cache some of the +expensive test setups, like the multi-revision subversion +repository that is created for each run of the tests. .. _`CPython's distutils`: http://www.python.org/dev/doc/devel/lib/module-distutils.html @@ -438,7 +342,6 @@ visions would make the link-checker a snap. It could serve as a nice script in our ``example`` tree. -.. _`exchange data`: execnet.html#exchange-data .. _`getting started`: getting_started.html .. _`restructured text`: http://docutils.sourceforge.net/docs/user/rst/quickref.html .. _`python standard library`: http://www.python.org/doc/2.3.4/lib/lib.html @@ -448,6 +351,3 @@ .. _`PEP-324 subprocess module`: http://www.python.org/peps/pep-0324.html .. _`subprocess implementation`: http://www.lysator.liu.se/~astrand/popen5/ .. _`py.test`: test.html -.. _`Reporter`: test.html#reporter -.. _xist: http://www.livinglogic.de/Python/xist/index.html -.. _`uses python class objects`: http://www.livinglogic.de/Python/xist/Howto.html Modified: py/dist/py/documentation/index.txt ============================================================================== --- py/dist/py/documentation/index.txt (original) +++ py/dist/py/documentation/index.txt Sat Jan 22 00:37:38 2005 @@ -13,7 +13,9 @@ `py.test`_ introduces to the new'n'easy **py.test** utility - `py.execnet`_ offers an innovative way to distribute programs across the net + `py.execnet`_ a (probably uniquely) innovative way to distribute programs across the net + + `py.xml`_ a fast'n'easy way to generate xml/html documents (including CSS-styling) `miscellaneous features`_ describes some more py lib features @@ -29,6 +31,7 @@ .. _`py.execnet`: execnet.html .. _`py.test`: test.html +.. _`py.xml`: xml.html .. _`Why What how py?`: why_py.html .. _`future`: future.html .. _`getting started`: getting_started.html Added: py/dist/py/documentation/xml.txt ============================================================================== --- (empty file) +++ py/dist/py/documentation/xml.txt Sat Jan 22 00:37:38 2005 @@ -0,0 +1,173 @@ +===================================================== +py.xml: Lightweight and powerfull xml/html generation +===================================================== + +.. contents:: +.. sectnum:: + +Motivation +========== + +There are a plethora of frameworks and libraries to generate +xml and html trees. However, many of them are large, have a +steep learning curve and are often hard to debug. Not to +speak of the fact that they are frameworks to begin with. + +The py lib strives to offer enough functionality to represent +itself and especially its API in html or xml. + +.. _xist: http://www.livinglogic.de/Python/xist/index.html +.. _`Reporter`: test.html#reporter +.. _`exchange data`: execnet.html#exchange-data + +a pythonic object model , please +================================ + +The py lib offers a pythonic way to generate xml/html, based on +ideas from xist_ which `uses python class objects`_ to build +xml trees. However, xist_'s implementation is somewhat heavy +because it has additional goals like transformations and +supporting many namespaces. But its basic idea is very easy. + +.. _`uses python class objects`: http://www.livinglogic.de/Python/xist/Howto.html + +generating arbitrary xml structures +----------------------------------- + +With ``py.xml.Namespace()`` you have everything +to generate custom xml-fragments on the fly:: + + ns = py.xml.Namespace() + doc = ns.books( + ns.book( + ns.author("May Day"), + ns.title("python for java programmers"),), + ns.book( + ns.author("why"), + ns.title("Java for Python programmers"),), + publisher="N.N", + ) + print doc.unicode(indent=2).encode('utf8') + +will give you this representation:: + + + + May Day + python for java programmers + + why + Java for Python programmers + +In a sentence: positional arguments are child-tags and +keyword-arguments are attributes. + +On a side note, you'll see that the unicode-serializer +supports a nice indentation style which keep your generated +html readable, basically through emulating python's white +space significance by putting closing-tags rightmost and +almost invisible at first glance :-) + +basic example for generating html +--------------------------------- + +Consider this example:: + + from py.xml import html + + paras = "First Para", "Second para" + + doc = html.html( + html.head( + html.meta(name="Content-Type", value="text/html; charset=utf8)) + html.body( + [html.p(p) for p in paras])) + + print unicode(doc).encode('latin1') + +Again, tags are objects which contain tags and have attributes. +More exactly, Tags inherit from the list type and thus can be +manipulated as list objects. They additionally support a default +way to represent themselves as a serialized unicode object. + +If you happen to look at the py.xml implementation you'll +note that the tag/namespace implementation consumes some 50 lines +with another 50 lines for the unicode serialization code. + + +CSS-styling your html Tags +-------------------------- + +One aspect where many of the huge python xml/html generation +frameworks utterly fail is a clean and convenient integration +of CSS styling. Often, developers are left alone with keeping +CSS style definitions in sync with some style files +represented as strings (often in a separate .css file). Not +only is this hard to debug but the missing abstractions make +it hard to modify the styling of your tags or to choose custom +style representations (inline, html.head or external). Add the +Browers usual tolerance of messyness and errors in Style +references and welcome to hell, known as the domain of +developing web applications :-) + +By contrast, consider this CSS styling example:: + + class my: + "my initial custom style" + class body(html.body): + style = html.Style(font_size = "120%") + + class h2(html.h2): + style = html.Style(background = "grey") + + class p(html.p): + style = html.Style(font_weight="bold") + + doc = html.html( + html.head(), + my.body( + my.h2("hello world"), + my.p("bold as bold can") + ) + ) + + print doc.unicode(indent=2) + +This will give you a small'n mean self contained +represenation by default:: + + + + +

hello world

+

bold as bold can

+ +Most importantly, note that the inline-styling is just an +implementation detail of the unicode serialization code. +You can easily modify the serialization to put your styling into the +``html.head`` or in a separate file and autogenerate CSS-class +names or ids. + +Hey, you could even write tests that you are using correct +styles suitable for specific browser requirements. Did i mention +that the ability to easily write tests for your generated +html and its serialization could help to develop _stable_ user +interfaces? + +More to come ... +---------------- + +For now, i don't think we should strive to offer much more +than the above. However, it is probably not hard to offer +*partial serialization* to allow generating maybe hundreds of +complex html documents per second. Basically we would allow +putting callables both as Tag content and as values of +attributes. A slightly more advanced Serialization would then +produce a list of unicode objects intermingled with callables. +At HTTP-Request time the callables would get called to +complete the probably request-specific serialization of +your Tags. Hum, it's probably harder to explain this than to +actually code it :-) + +.. _Nevow: http://www.divmod.org/Home/Projects/Nevow/ +.. _`py.test`: test.html Added: py/dist/py/xmlobj/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/xmlobj/__init__.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1 @@ +# Added: py/dist/py/xmlobj/html.py ============================================================================== --- (empty file) +++ py/dist/py/xmlobj/html.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1,22 @@ +""" + + +""" +from py.xml import Namespace + +# exported plain html namespace +class Html(Namespace): + __tagspec__ = dict([(x,1) for x in ( + "h1,h2,h3,h5,h6,p,b,i,a,div,span,code," + "html,head,title,style,table,tr,tt," + "td,th,link,img,meta,body,pre,br,ul," + "ol,li,em,form,input,select,option" + ).split(',') if x]) + + class Style(object): + def __init__(self, **kw): + for x, y in kw.items(): + x = x.replace('_', '-') + setattr(self, x, y) + +html = Html(stickyname=True) Added: py/dist/py/xmlobj/misc.py ============================================================================== --- (empty file) +++ py/dist/py/xmlobj/misc.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1,17 @@ +import re +class _escape: + def __init__(self): + self.escape = { + u'"' : u'"', u'<' : u'<', u'>' : u'>', + u'&' : u'&', u"'" : u''', + } + self.charef_rex = re.compile(u"|".join(self.escape.keys())) + + def _replacer(self, match): + return self.escape[match.group(0)] + + def __call__(self, ustring): + """ xml-escape the given unicode string. """ + return self.charef_rex.sub(self._replacer, ustring) + +escape = _escape() Added: py/dist/py/xmlobj/testing/__init__.py ============================================================================== --- (empty file) +++ py/dist/py/xmlobj/testing/__init__.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1 @@ +# Added: py/dist/py/xmlobj/testing/test_html.py ============================================================================== --- (empty file) +++ py/dist/py/xmlobj/testing/test_html.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1,36 @@ +from py.xml import html + +def test_html_name_stickyness(): + class my(html.p): + pass + x = my("hello") + assert unicode(x) == '

hello

' + +def test_stylenames(): + class my: + class body(html.body): + style = html.Style(font_size = "12pt") + u = unicode(my.body()) + assert u == '' + +def test_alternating_style(): + alternating = ( + html.Style(background="white"), + html.Style(background="grey"), + ) + class my: + class li(html.li): + def style(self): + i = self.parent.index(self) + return alternating[i%2] + style = property(style) + + x = html.ul( + my.li("hello"), + my.li("world"), + my.li("42")) + u = unicode(x) + assert u == ('
  • hello
  • ' + '
  • world
  • ' + '
  • 42
  • ' + '
') Added: py/dist/py/xmlobj/testing/test_xml.py ============================================================================== --- (empty file) +++ py/dist/py/xmlobj/testing/test_xml.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1,39 @@ + +import py + +ns = py.xml.Namespace() + +def test_tag_with_text(): + x = ns.hello("world") + u = unicode(x) + assert u == "world" + +def test_class_identity(): + assert ns.hello is ns.hello + +def test_tag_with_text_and_attributes(): + x = ns.some(name="hello", value="world") + assert x.attr.name == 'hello' + assert x.attr.value == 'world' + u = unicode(x) + assert u == '' + +def test_tag_with_subclassed_attr_simple(): + class my(ns.hello): + class Attr(ns.hello.Attr): + hello="world" + x = my() + assert x.attr.hello == 'world' + assert unicode(x) == '' + +def test_tag_nested(): + x = ns.hello(ns.world()) + assert x[0].parent is x + u = unicode(x) + assert u == '' + +def test_tag_xmlname(): + class my(ns.hello): + xmlname = 'world' + u = unicode(my()) + assert u == '' Added: py/dist/py/xmlobj/visit.py ============================================================================== --- (empty file) +++ py/dist/py/xmlobj/visit.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1,79 @@ +# +# a generic conversion serializer +# + +from py.xml import escape + +class SimpleUnicodeVisitor(object): + """ recursive visitor to write unicode. """ + def __init__(self, write, indent=0, curindent=0): + self.write = write + self.cache = {} + self.visited = {} # for detection of recursion + self.indent = indent + self.curindent = curindent + + def visit(self, node): + """ dispatcher on node's class/bases name. """ + cls = node.__class__ + try: + visitmethod = self.cache[cls] + except KeyError: + for subclass in cls.__mro__: + visitmethod = getattr(self, subclass.__name__, None) + if visitmethod is not None: + break + else: + visitmethod = self.object + self.cache[cls] = visitmethod + visitmethod(node) + + def object(self, obj): + #self.write(obj) + self.write(unicode(obj)) + + def list(self, obj): + assert id(obj) not in self.visited + self.visited[id(obj)] = 1 + map(self.visit, obj) + + def Tag(self, tag): + assert id(tag) not in self.visited + self.visited[id(tag)] = 1 + tagname = getattr(tag, 'xmlname', tag.__class__.__name__) + if self.curindent: + self.write("\n" + u' ' * self.curindent) + if tag: + self.curindent += self.indent + self.write(u'<%s%s>' % (tagname, self.attributes(tag))) + map(self.visit, tag) + self.write(u'' % tagname) + self.curindent -= self.indent + else: + self.write(u'<%s%s/>' % (tagname, self.attributes(tag))) + + def attributes(self, tag): + # serialize attributes + attrlist = dir(tag.attr) + attrlist.sort() + l = [] + for name in attrlist: + if name[0] != '_': + value = getattr(tag.attr, name) + if name.endswith('_'): + name = name[:-1] + l.append(u' %s="%s"' % (name, escape(unicode(value)))) + l.extend(self.getstyle(tag)) + return u"".join(l) + + def getstyle(self, tag): + """ return attribute list suitable for styling. """ + try: + styledict = tag.style.__dict__ + except AttributeError: + return [] + else: + stylelist = [x+': ' + y for x,y in styledict.items()] + return [u' style="%s"' % u'; '.join(stylelist)] + + Added: py/dist/py/xmlobj/xml.py ============================================================================== --- (empty file) +++ py/dist/py/xmlobj/xml.py Sat Jan 22 00:37:38 2005 @@ -0,0 +1,53 @@ +""" +generic (and pythonic :-) xml tag and namespace objects +""" + +class Tag(list): + class Attr(object): + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + def __init__(self, *args, **kwargs): + super(Tag, self).__init__(args) + self.attr = self.Attr(**kwargs) + for x in args: + try: + setattr(x, 'parent', self) + except AttributeError: + pass + + def __unicode__(self): + return self.unicode(indent=0) + + def unicode(self, indent=2): + from py.__impl__.xmlobj.visit import SimpleUnicodeVisitor + l = [] + SimpleUnicodeVisitor(l.append, indent).visit(self) + return u"".join(l) + + def __repr__(self): + name = self.__class__.__name__ + return "<%r tag object %d>" % (name, id(self)) + +# the generic xml namespace +# provides Tag classes on the fly optionally checking for +# a tagspecification + +class Namespace(object): + __tagspec__ = None + def __init__(self, tagclass=Tag, stickyname=False): + self.__tagclass__ = tagclass + self.__stickyname__ = stickyname + + def __getattr__(self, name): + if name[:1] == '_': + raise AttributeError(name) + tagspec = self.__tagspec__ + if tagspec is not None and name not in tagspec: + raise AttributeError(name) + classattr = {} + if self.__stickyname__: + classattr['xmlname'] = name + cls = type(name, (self.__tagclass__,), classattr) + setattr(self, name, cls) + return cls From hpk at codespeak.net Sat Jan 22 17:02:20 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 22 Jan 2005 17:02:20 +0100 (MET) Subject: [py-svn] r8470 - in py/dist/py: documentation documentation/example xmlobj xmlobj/testing Message-ID: <20050122160220.4FF0927B56@code1.codespeak.net> Author: hpk Date: Sat Jan 22 17:02:20 2005 New Revision: 8470 Modified: py/dist/py/documentation/example/genhtmlcss.py py/dist/py/documentation/example/genxml.py py/dist/py/documentation/xml.txt py/dist/py/xmlobj/html.py py/dist/py/xmlobj/testing/test_html.py py/dist/py/xmlobj/testing/test_xml.py py/dist/py/xmlobj/xml.py Log: changed the mechanics of the basic py.xml.Namespace slightly and adjusted the documentation and examples accordingly. Modified: py/dist/py/documentation/example/genhtmlcss.py ============================================================================== --- py/dist/py/documentation/example/genhtmlcss.py (original) +++ py/dist/py/documentation/example/genhtmlcss.py Sat Jan 22 17:02:20 2005 @@ -1,9 +1,9 @@ import py html = py.xml.html -class my: +class my(html): "a custom style" - class body(html.body): + class body(html.body): style = html.Style(font_size = "120%") class h2(html.h2): @@ -12,8 +12,8 @@ class p(html.p): style = html.Style(font_weight="bold") -doc = html.html( - html.head(), +doc = my.html( + my.head(), my.body( my.h2("hello world"), my.p("bold as bold can") Modified: py/dist/py/documentation/example/genxml.py ============================================================================== --- py/dist/py/documentation/example/genxml.py (original) +++ py/dist/py/documentation/example/genxml.py Sat Jan 22 17:02:20 2005 @@ -1,6 +1,8 @@ import py -ns = py.xml.Namespace() +class ns(py.xml.Namespace): + pass + doc = ns.books( ns.book( ns.author("May Day"), Modified: py/dist/py/documentation/xml.txt ============================================================================== --- py/dist/py/documentation/xml.txt (original) +++ py/dist/py/documentation/xml.txt Sat Jan 22 17:02:20 2005 @@ -1,6 +1,6 @@ -===================================================== -py.xml: Lightweight and powerfull xml/html generation -===================================================== +==================================================== +py.xml: Lightweight and flexible xml/html generation +==================================================== .. contents:: .. sectnum:: @@ -34,10 +34,11 @@ generating arbitrary xml structures ----------------------------------- -With ``py.xml.Namespace()`` you have everything +With ``py.xml.Namespace`` you have the basis to generate custom xml-fragments on the fly:: - ns = py.xml.Namespace() + class ns(py.xml.Namespace): + "my custom xml namespace" doc = ns.books( ns.book( ns.author("May Day"), @@ -73,17 +74,17 @@ Consider this example:: - from py.xml import html + from py.xml import html # html namespace - paras = "First Para", "Second para" + paras = "First Para", "Second para" - doc = html.html( + doc = html.html( html.head( - html.meta(name="Content-Type", value="text/html; charset=utf8)) + html.meta(name="Content-Type", value="text/html; charset=latin1")), html.body( [html.p(p) for p in paras])) - print unicode(doc).encode('latin1') + print unicode(doc).encode('latin1') Again, tags are objects which contain tags and have attributes. More exactly, Tags inherit from the list type and thus can be @@ -94,7 +95,6 @@ note that the tag/namespace implementation consumes some 50 lines with another 50 lines for the unicode serialization code. - CSS-styling your html Tags -------------------------- @@ -112,7 +112,7 @@ By contrast, consider this CSS styling example:: - class my: + class my(html): "my initial custom style" class body(html.body): style = html.Style(font_size = "120%") @@ -123,8 +123,8 @@ class p(html.p): style = html.Style(font_weight="bold") - doc = html.html( - html.head(), + doc = my.html( + my.head(), my.body( my.h2("hello world"), my.p("bold as bold can") Modified: py/dist/py/xmlobj/html.py ============================================================================== --- py/dist/py/xmlobj/html.py (original) +++ py/dist/py/xmlobj/html.py Sat Jan 22 17:02:20 2005 @@ -5,7 +5,8 @@ from py.xml import Namespace # exported plain html namespace -class Html(Namespace): +class html(Namespace): + __stickyname__ = True __tagspec__ = dict([(x,1) for x in ( "h1,h2,h3,h5,h6,p,b,i,a,div,span,code," "html,head,title,style,table,tr,tt," @@ -19,4 +20,3 @@ x = x.replace('_', '-') setattr(self, x, y) -html = Html(stickyname=True) Modified: py/dist/py/xmlobj/testing/test_html.py ============================================================================== --- py/dist/py/xmlobj/testing/test_html.py (original) +++ py/dist/py/xmlobj/testing/test_html.py Sat Jan 22 17:02:20 2005 @@ -18,14 +18,14 @@ html.Style(background="white"), html.Style(background="grey"), ) - class my: + class my(html): class li(html.li): def style(self): i = self.parent.index(self) return alternating[i%2] style = property(style) - x = html.ul( + x = my.ul( my.li("hello"), my.li("world"), my.li("42")) Modified: py/dist/py/xmlobj/testing/test_xml.py ============================================================================== --- py/dist/py/xmlobj/testing/test_xml.py (original) +++ py/dist/py/xmlobj/testing/test_xml.py Sat Jan 22 17:02:20 2005 @@ -1,7 +1,8 @@ import py -ns = py.xml.Namespace() +class ns(py.xml.Namespace): + pass def test_tag_with_text(): x = ns.hello("world") Modified: py/dist/py/xmlobj/xml.py ============================================================================== --- py/dist/py/xmlobj/xml.py (original) +++ py/dist/py/xmlobj/xml.py Sat Jan 22 17:02:20 2005 @@ -33,15 +33,12 @@ # provides Tag classes on the fly optionally checking for # a tagspecification -class Namespace(object): - __tagspec__ = None - def __init__(self, tagclass=Tag, stickyname=False): - self.__tagclass__ = tagclass - self.__stickyname__ = stickyname - - def __getattr__(self, name): +class NamespaceMetaclass(type): + def __getattr__(self, name): if name[:1] == '_': raise AttributeError(name) + if self == Namespace: + raise ValueError("Namespace class is abstract") tagspec = self.__tagspec__ if tagspec is not None and name not in tagspec: raise AttributeError(name) @@ -51,3 +48,10 @@ cls = type(name, (self.__tagclass__,), classattr) setattr(self, name, cls) return cls + +class Namespace(object): + __tagspec__ = None + __tagclass__ = Tag + __metaclass__ = NamespaceMetaclass + __stickyname__ = False + From hpk at codespeak.net Sun Jan 23 10:39:11 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 23 Jan 2005 10:39:11 +0100 (MET) Subject: [py-svn] r8473 - in py/dist/py: path test/testing Message-ID: <20050123093911.BAFD227B49@code1.codespeak.net> Author: hpk Date: Sun Jan 23 10:39:11 2005 New Revision: 8473 Modified: py/dist/py/path/common.py py/dist/py/test/testing/test_collect.py Log: use python2.4 behaviour for failing imports: if an import fails (other than with a syntax error) then remove the module from sys.modules. Modified: py/dist/py/path/common.py ============================================================================== --- py/dist/py/path/common.py (original) +++ py/dist/py/path/common.py Sun Jan 23 10:39:11 2005 @@ -338,7 +338,11 @@ if self.basename == '__init__.py': mod.__path__ = [str(self.dirpath())] sys.modules[modname] = mod - exec co in mod.__dict__ + try: + exec co in mod.__dict__ + except: + del sys.modules[modname] + raise return mod def getpycodeobj(self): Modified: py/dist/py/test/testing/test_collect.py ============================================================================== --- py/dist/py/test/testing/test_collect.py (original) +++ py/dist/py/test/testing/test_collect.py Sun Jan 23 10:39:11 2005 @@ -9,10 +9,14 @@ def test_failing_import_execfile(): fn = datadir / 'failingimport.py' - l = list(collect.Module(py.path.extpy(fn))) - assert l - ex, = l - assert issubclass(ex.excinfo.type, ImportError) + col = collect.Module(py.path.extpy(fn)) + def _import(): + l = list(col) + assert l + ex, = l + assert issubclass(ex.excinfo.type, ImportError) + _import() + _import() def test_failing_import_directory(): class MyDirectory(collect.Directory): @@ -35,7 +39,8 @@ def test_syntax_error_in_module(): modpath = py.path.extpy(datadir.join('syntax_error.py')) - l2 = list(collect.Module(modpath)) + col = collect.Module(modpath) + l2 = list(col) assert len(l2) == 1 assert isinstance(l2[0], collect.Error) assert issubclass(l2[0].excinfo.type, SyntaxError) From hpk at codespeak.net Sun Jan 23 18:58:37 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 23 Jan 2005 18:58:37 +0100 (MET) Subject: [py-svn] r8505 - py/dist/py/bin Message-ID: <20050123175837.177E827B45@code1.codespeak.net> Author: hpk Date: Sun Jan 23 18:58:36 2005 New Revision: 8505 Added: py/dist/py/bin/pytest.bat Log: Added Matthew Scott's version of having a py.test script on windows (named pytest without the dot to not confuse windows) Added: py/dist/py/bin/pytest.bat ============================================================================== --- (empty file) +++ py/dist/py/bin/pytest.bat Sun Jan 23 18:58:36 2005 @@ -0,0 +1,3 @@ + at echo off +python %~dp0\py.test %* + From hpk at codespeak.net Sun Jan 23 19:03:25 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 23 Jan 2005 19:03:25 +0100 (MET) Subject: [py-svn] r8506 - py/dist/py/bin Message-ID: <20050123180325.1EEEB27B45@code1.codespeak.net> Author: hpk Date: Sun Jan 23 19:03:24 2005 New Revision: 8506 Added: py/dist/py/bin/pytest.cmd - copied unchanged from r8505, py/dist/py/bin/pytest.bat Removed: py/dist/py/bin/pytest.bat Log: hum, i think it needs to be a .cmd actually Deleted: /py/dist/py/bin/pytest.bat ============================================================================== --- /py/dist/py/bin/pytest.bat Sun Jan 23 19:03:24 2005 +++ (empty file) @@ -1,3 +0,0 @@ - at echo off -python %~dp0\py.test %* - From pobrien at orbtech.com Sun Jan 23 19:06:04 2005 From: pobrien at orbtech.com (Patrick K. O'Brien) Date: Sun, 23 Jan 2005 12:06:04 -0600 Subject: [py-svn] r8505 - py/dist/py/bin In-Reply-To: <20050123175837.177E827B45@code1.codespeak.net> References: <20050123175837.177E827B45@code1.codespeak.net> Message-ID: <41F3E78C.1050900@orbtech.com> hpk at codespeak.net wrote: > Author: hpk > Date: Sun Jan 23 18:58:36 2005 > New Revision: 8505 > > Added: > py/dist/py/bin/pytest.bat > Log: > Added Matthew Scott's version of having a py.test script > on windows (named pytest without the dot to not confuse > windows) Matt can correct me if I'm wrong, but I believe that version of the code only works in a .cmd file and not in the older .bat file. So you'll need to change the filename from pytest.bat to pytest.cmd. Or have both, since .cmd files don't work on Windows 98. -- Patrick K. O'Brien Orbtech http://www.orbtech.com Schevo http://www.schevo.org Pypersyst http://www.pypersyst.org From arigo at codespeak.net Sun Jan 23 19:31:47 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 23 Jan 2005 19:31:47 +0100 (MET) Subject: [py-svn] r8509 - py/dist/py/test/report/text Message-ID: <20050123183147.4A3A827B45@code1.codespeak.net> Author: arigo Date: Sun Jan 23 19:31:47 2005 New Revision: 8509 Modified: py/dist/py/test/report/text/summary.py Log: Try harder to display the exception. Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Sun Jan 23 19:31:47 2005 @@ -162,7 +162,7 @@ self.out.line("[reinterpretation failed, increase " "verbosity to see details]") indent = " " * indent - if info is None: + if not info: info = str(excinfo) lines = info.split('\n') From arigo at codespeak.net Sun Jan 23 20:00:13 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 23 Jan 2005 20:00:13 +0100 (MET) Subject: [py-svn] r8510 - in py/dist/py/magic: . testing Message-ID: <20050123190013.B809C27B45@code1.codespeak.net> Author: arigo Date: Sun Jan 23 20:00:13 2005 New Revision: 8510 Modified: py/dist/py/magic/exprinfo.py py/dist/py/magic/testing/test_exprinfo.py Log: exprinfo messed up function calls that use keyword arguments. Modified: py/dist/py/magic/exprinfo.py ============================================================================== --- py/dist/py/magic/exprinfo.py (original) +++ py/dist/py/magic/exprinfo.py Sun Jan 23 20:00:13 2005 @@ -235,12 +235,21 @@ vars = {'__exprinfo_fn': node.result} source = '__exprinfo_fn(' for a in self.args: + if isinstance(a, ast.Keyword): + keyword = a.name + a = a.expr + else: + keyword = None a = Interpretable(a) a.eval(frame) argname = '__exprinfo_%d' % len(vars) vars[argname] = a.result - source += argname + ',' - explanations.append(a.explanation) + if keyword is None: + source += argname + ',' + explanations.append(a.explanation) + else: + source += '%s=%s,' % (keyword, argname) + explanations.append('%s=%s' % (keyword, a.explanation)) if self.star_args: star_args = Interpretable(self.star_args) star_args.eval(frame) Modified: py/dist/py/magic/testing/test_exprinfo.py ============================================================================== --- py/dist/py/magic/testing/test_exprinfo.py (original) +++ py/dist/py/magic/testing/test_exprinfo.py Sun Jan 23 20:00:13 2005 @@ -67,8 +67,8 @@ msg = getmsg(excinfo) assert msg.find("must be called with A") != -1 -def global_f(): - return 42 +def global_f(u=6, v=7): + return u*v def test_exprinfo_funccall(): def g(): @@ -77,6 +77,13 @@ msg = getmsg(excinfo) assert msg == 'assert 42 == 43\n + where 42 = global_f()' +def test_exprinfo_funccall_keywords(): + def g(): + assert global_f(v=11) == 67 + excinfo = getexcinfo(AssertionError, g) + msg = getmsg(excinfo) + assert msg == 'assert 66 == 67\n + where 66 = global_f(v=11)' + def test_keyboard_interrupt(): # XXX this test is slightly strange because it is not # clear that "interpret" should execute "raise" statements From mscott at goldenspud.com Sun Jan 23 20:09:13 2005 From: mscott at goldenspud.com (Matthew Scott) Date: Sun, 23 Jan 2005 13:09:13 -0600 Subject: [py-svn] r8505 - py/dist/py/bin In-Reply-To: <41F3E78C.1050900@orbtech.com> References: <20050123175837.177E827B45@code1.codespeak.net> <41F3E78C.1050900@orbtech.com> Message-ID: <41F3F659.8070001@goldenspud.com> Patrick K. O'Brien wrote: > hpk at codespeak.net wrote: > >> Author: hpk >> Date: Sun Jan 23 18:58:36 2005 >> New Revision: 8505 >> >> Added: >> py/dist/py/bin/pytest.bat >> Log: >> Added Matthew Scott's version of having a py.test script >> on windows (named pytest without the dot to not confuse windows) > > > Matt can correct me if I'm wrong, but I believe that version of the code > only works in a .cmd file and not in the older .bat file. So you'll > need to change the filename from pytest.bat to pytest.cmd. Or have > both, since .cmd files don't work on Windows 98. > I have no idea. It might work as a .bat file -- but I haven't tested it as a .bat file on any MSDOS-based Windows, nor have I researched any documentation for such OSs to determine whether or not it would work. :) From hpk at codespeak.net Sun Jan 23 22:46:26 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 23 Jan 2005 22:46:26 +0100 (MET) Subject: [py-svn] r8511 - py/dist/py/code Message-ID: <20050123214626.6C0DD27B45@code1.codespeak.net> Author: hpk Date: Sun Jan 23 22:46:26 2005 New Revision: 8511 Modified: py/dist/py/code/excinfo.py Log: be a bit more careful if someone put msg=None on an exception (apparently Christian got a strange traceback which had this problem, well ...) Modified: py/dist/py/code/excinfo.py ============================================================================== --- py/dist/py/code/excinfo.py (original) +++ py/dist/py/code/excinfo.py Sun Jan 23 22:46:26 2005 @@ -14,7 +14,7 @@ tup = sys.exc_info() if exprinfo is None and isinstance(tup[1], py.magic.AssertionError): exprinfo = tup[1].msg - if exprinfo.startswith('assert '): + if exprinfo and exprinfo.startswith('assert '): strip = 'AssertionError: ' self._excinfo = tup self.type, self.value, tb = self._excinfo From hpk at codespeak.net Thu Jan 27 23:39:29 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 27 Jan 2005 23:39:29 +0100 (MET) Subject: [py-svn] r8646 - py/dist/py/path/local Message-ID: <20050127223929.65E9E27B8A@code1.codespeak.net> Author: hpk Date: Thu Jan 27 23:39:29 2005 New Revision: 8646 Modified: py/dist/py/path/local/local.py Log: formatting crazyness Modified: py/dist/py/path/local/local.py ============================================================================== --- py/dist/py/path/local/local.py (original) +++ py/dist/py/path/local/local.py Thu Jan 27 23:39:29 2005 @@ -376,8 +376,7 @@ ret = proc.wait() if ret != 0: raise py.process.cmdexec.Error(ret, ret, str(self), - stdout, - stderr,) + stdout, stderr,) return stdout def sysfind(self, name, checker=None): From hpk at codespeak.net Fri Jan 28 13:20:22 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 28 Jan 2005 13:20:22 +0100 (MET) Subject: [py-svn] r8660 - in py/dist/py/path/svn: . testing Message-ID: <20050128122022.0215C27B95@code1.codespeak.net> Author: hpk Date: Fri Jan 28 13:20:22 2005 New Revision: 8660 Modified: py/dist/py/path/svn/testing/test_wccommand.py py/dist/py/path/svn/wccommand.py Log: sanitize the .svn versioned() checks (it seems subversion changed somehow its output) Modified: py/dist/py/path/svn/testing/test_wccommand.py ============================================================================== --- py/dist/py/path/svn/testing/test_wccommand.py (original) +++ py/dist/py/path/svn/testing/test_wccommand.py Fri Jan 28 13:20:22 2005 @@ -98,6 +98,7 @@ def test_versioned(self): assert self.root.check(versioned=1) + assert self.root.join('.svn').check(versioned=0) assert self.root.join('samplefile').check(versioned=1) assert not self.root.join('notexisting').check(versioned=1) notexisting = self.root.join('hello').localpath Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Fri Jan 28 13:20:22 2005 @@ -310,9 +310,12 @@ if e.err.find('Path is not a working copy directory') != -1: raise py.error.ENOENT(self, e.err) raise - if output.find('Not a versioned resource') != -1: + output = output.lower() + if output.find('not a versioned resource') != -1: raise py.error.ENOENT(self, output) - info = InfoSvnWCCommand(path.local(self.strpath), output) + info = InfoSvnWCCommand(output) + if info.path != self.localpath: + raise py.error.ENOENT(self, "not a versioned resource") cache.info[self] = info self.rev = info.rev return info @@ -327,7 +330,7 @@ fil = common.fnmatch(fil) # XXX unify argument naming with LocalPath.listdir def notsvn(path): - return not path.get('basename') == '.svn' + return path.basename != '.svn' paths = [] for localpath in self.localpath.listdir(notsvn): @@ -355,13 +358,15 @@ self.path = path.localpath def versioned(self): try: - s = self.svnwcpath.status() + s = self.svnwcpath.info() + except py.error.ENOENT: + return False except py.process.cmdexec.Error, e: if e.err.find('is not a working copy')!=-1: return False raise else: - return self.svnwcpath in s.allpath(ignored=0,unknown=0, deleted=0) + return True def log(self, rev_start=None, rev_end=1, verbose=False): from py.__impl__.path.svn.command import _Head, LogEntry @@ -424,7 +429,7 @@ return l class InfoSvnWCCommand: - def __init__(self, path, output): + def __init__(self, output): # Path: test # URL: http://codespeak.net/svn/std.path/trunk/dist/std.path/test # Repository UUID: fd0d7bf2-dfb6-0310-8d31-b7ecfe96aada @@ -450,7 +455,8 @@ raise ValueError, "Not a versioned resource %r" % path self.kind = d['nodekind'] == 'directory' and 'dir' or d['nodekind'] self.rev = int(d['revision']) - self.size = path.size() + self.path = py.path.local(d['path']) + self.size = self.path.size() if 'lastchangedrev' in d: self.created_rev = int(d['lastchangedrev']) self.last_author = d['lastchangedauthor'] From hpk at codespeak.net Fri Jan 28 19:03:10 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 28 Jan 2005 19:03:10 +0100 (MET) Subject: [py-svn] r8676 - py/dist/py/path/svn Message-ID: <20050128180310.5223327B96@code1.codespeak.net> Author: hpk Date: Fri Jan 28 19:03:10 2005 New Revision: 8676 Modified: py/dist/py/path/svn/wccommand.py Log: yet another try to fix versioned-checks ... Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Fri Jan 28 19:03:10 2005 @@ -310,8 +310,7 @@ if e.err.find('Path is not a working copy directory') != -1: raise py.error.ENOENT(self, e.err) raise - output = output.lower() - if output.find('not a versioned resource') != -1: + if output.lower().find('not a versioned resource') != -1: raise py.error.ENOENT(self, output) info = InfoSvnWCCommand(output) if info.path != self.localpath: From hpk at codespeak.net Sat Jan 29 13:03:38 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 29 Jan 2005 13:03:38 +0100 (MET) Subject: [py-svn] r8698 - py/dist/py/path/svn Message-ID: <20050129120338.500F927B8A@code1.codespeak.net> Author: hpk Date: Sat Jan 29 13:03:38 2005 New Revision: 8698 Modified: py/dist/py/path/svn/wccommand.py Log: experiment fix to correctly pass on arguments to the underlying system (this really needs to be done more systematically and also tested) Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Sat Jan 29 13:03:38 2005 @@ -57,7 +57,7 @@ l = ['svn %s' % cmd] args = map(lambda x: '"%s"' % x, args) l.extend(args) - l.append(repr(self.strpath)) + l.append("%s" % self.strpath) # try fixing the locale because we can't otherwise parse string = svncommon.fixlocale() + " ".join(l) if DEBUG: From hpk at codespeak.net Sat Jan 29 14:27:54 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 29 Jan 2005 14:27:54 +0100 (MET) Subject: [py-svn] r8711 - py/dist/py/path/svn Message-ID: <20050129132754.A2EF927B62@code1.codespeak.net> Author: hpk Date: Sat Jan 29 14:27:54 2005 New Revision: 8711 Modified: py/dist/py/path/svn/wccommand.py Log: always write propset's value to a file and reference it with "svn propset NAME --file ..." this is neccessary on windows and doesn't really hurt too much on linux (where we could get quoting issues if you have large binary values for properties ...) Modified: py/dist/py/path/svn/wccommand.py ============================================================================== --- py/dist/py/path/svn/wccommand.py (original) +++ py/dist/py/path/svn/wccommand.py Sat Jan 29 14:27:54 2005 @@ -257,7 +257,13 @@ pass def propset(self, propname, value, *args): - self._svn('propset', propname, value, *args) + d = py.path.local.mkdtemp() + try: + p = d.join('value') + p.write(value) + self._svn('propset', propname, '--file', str(p), *args) + finally: + d.remove() def propget(self, name): res = self._svn('propget', name) From hpk at codespeak.net Sat Jan 29 17:26:43 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 29 Jan 2005 17:26:43 +0100 (MET) Subject: [py-svn] r8730 - py/dist/py/test/report/text Message-ID: <20050129162643.CDE6C27B66@code1.codespeak.net> Author: hpk Date: Sat Jan 29 17:26:43 2005 New Revision: 8730 Modified: py/dist/py/test/report/text/summary.py Log: for the time being, special case SyntaxErrors when reporting Collector Errors. They are just way too ugly. Modified: py/dist/py/test/report/text/summary.py ============================================================================== --- py/dist/py/test/report/text/summary.py (original) +++ py/dist/py/test/report/text/summary.py Sat Jan 29 17:26:43 2005 @@ -19,7 +19,16 @@ self.out.sep("_") self.out.sep("_", "Collect Error") self.out.line() - self.repr_failure(error.excinfo) + if isinstance(error.excinfo.value, SyntaxError): + self.repr_syntaxerror(error.excinfo) + else: + self.repr_failure(error.excinfo) + + def repr_syntaxerror(self, excinfo): + err = excinfo.value + self.out.line(err.text) + self.out.line("SyntaxError: %s" %(err.msg)) + self.out.line("[%s:%d]" % (err.filename, err.lineno)) def summary_collect_errors(self): for error in self.getlist(py.test.collect.Error): From hpk at codespeak.net Sat Jan 29 17:57:26 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 29 Jan 2005 17:57:26 +0100 (MET) Subject: [py-svn] r8733 - py/dist/py/test Message-ID: <20050129165726.BDAB327B5C@code1.codespeak.net> Author: hpk Date: Sat Jan 29 17:57:26 2005 New Revision: 8733 Modified: py/dist/py/test/drive.py Log: accept None from (possibly custom) Collectors Modified: py/dist/py/test/drive.py ============================================================================== --- py/dist/py/test/drive.py (original) +++ py/dist/py/test/drive.py Sat Jan 29 17:57:26 2005 @@ -73,6 +73,8 @@ raise self.Exit if self.option.exitfirstproblem: raise self.Exit() + elif obj is None: + pass # ok, we allow None to mean skip this item/collector else: raise TypeError("%r is not a Item or Collector instance" % obj)