From commits-noreply at bitbucket.org Tue Sep 1 11:40:10 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 01 Sep 2009 09:40:10 -0000 Subject: [py-svn] commit/py-trunk: hpk: * refactor gateway code and tests to live in fewer files, remove some lock usage Message-ID: <20090901094010.5606.49521@domU-12-31-39-00-95-01.compute-1.internal> 1 new changeset in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/33bdc923d0c7/ changeset: r1361:33bdc923d0c7 user: hpk date: 2009-09-01 11:39:27 summary: * refactor gateway code and tests to live in fewer files, remove some lock usage * move text files to a new "hacking" directory affected #: 20 files (8.2 KB) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Sep 1 16:11:39 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 01 Sep 2009 14:11:39 -0000 Subject: [py-svn] commit/py-trunk: hpk: * use py.builtin._getimself instead of getattr(..., '*self*') everywhere Message-ID: <20090901141139.5606.12246@domU-12-31-39-00-95-01.compute-1.internal> 1 new changeset in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/8759f3fa5022/ changeset: r1362:8759f3fa5022 user: hpk date: 2009-09-01 16:10:21 summary: * use py.builtin._getimself instead of getattr(..., '*self*') everywhere * fix logging to work with 3k, implement buffering manually * fix unicode capturing issue - re-introduce EncodedFile for <3K file writes affected #: 26 files (1.8 KB) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Sep 2 14:32:16 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 02 Sep 2009 12:32:16 -0000 Subject: [py-svn] commit/py-trunk: hpk: * make Gateway interface more asymetric: remote_* methods Message-ID: <20090902123216.5606.54190@domU-12-31-39-00-95-01.compute-1.internal> 1 new changeset in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/a2bf1c47e3fe/ changeset: r1363:a2bf1c47e3fe user: hpk date: 2009-09-02 14:31:48 summary: * make Gateway interface more asymetric: remote_* methods and cleanup/atexit handling now live exclusively with the "InitiatingGateway" * fix some cross-python io related handling affected #: 8 files (11.6 KB) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Sep 2 15:46:36 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 02 Sep 2009 13:46:36 -0000 Subject: [py-svn] commit/py-trunk: hpk: * simplify lock acquiration for received messages, review code Message-ID: <20090902134636.5606.85702@domU-12-31-39-00-95-01.compute-1.internal> 1 new changeset in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/1f14032e7160/ changeset: r1364:1f14032e7160 user: hpk date: 2009-09-02 15:45:59 summary: * simplify lock acquiration for received messages, review code * try to fix seldomly occuring race condition with setcallback/receive and closing of channel affected #: 1 file (25 bytes) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Sep 3 23:38:06 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 03 Sep 2009 21:38:06 -0000 Subject: [py-svn] commit/py-trunk: gutworth: give code objects a filename in the replacement execfile Message-ID: <20090903213806.6287.56291@domU-12-31-39-00-95-01.compute-1.internal> 1 new changeset in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/1e46b08a9d9e/ changeset: r1369:1e46b08a9d9e user: gutworth date: 2009-09-03 23:38:15 summary: give code objects a filename in the replacement execfile affected #: 3 files (337 bytes) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Sep 3 23:48:30 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 03 Sep 2009 21:48:30 -0000 Subject: [py-svn] commit/py-trunk: 2 new changesets Message-ID: <20090903214830.6287.73010@domU-12-31-39-00-95-01.compute-1.internal> 2 new changesets in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/cbdc40bd7995/ changeset: r1370:cbdc40bd7995 user: gutworth date: 2009-09-03 23:45:28 summary: add a helper to get a function's dictionary affected #: 3 files (400 bytes) http://www.bitbucket.org/hpk42/py-trunk/changeset/2ce37c02b9c1/ changeset: r1371:2ce37c02b9c1 user: gutworth date: 2009-09-03 23:47:04 summary: fix xfail affected #: 1 file (18 bytes) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Sep 4 00:14:17 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 03 Sep 2009 22:14:17 -0000 Subject: [py-svn] commit/py-trunk: gutworth: I think this is supposed to be immutable Message-ID: <20090903221417.6287.38749@domU-12-31-39-00-95-01.compute-1.internal> 1 new changeset in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/e3571db1fd78/ changeset: r1372:e3571db1fd78 user: gutworth date: 2009-09-04 00:14:12 summary: I think this is supposed to be immutable affected #: 1 file (2 bytes) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Sep 4 16:33:04 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 04 Sep 2009 14:33:04 -0000 Subject: [py-svn] commit/py-trunk: hpk: remove so-far superflous _getcode and pickle from builtins, some streamlining Message-ID: <20090904143304.14905.21093@domU-12-31-39-00-95-01.compute-1.internal> 1 new changeset in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/4631c9f43541/ changeset: r1373:4631c9f43541 user: hpk date: 2009-09-04 16:32:49 summary: remove so-far superflous _getcode and pickle from builtins, some streamlining affected #: 7 files (463 bytes) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Sep 4 18:20:15 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 04 Sep 2009 16:20:15 -0000 Subject: [py-svn] commit/py-trunk: 3 new changesets Message-ID: <20090904162015.14905.37459@domU-12-31-39-00-95-01.compute-1.internal> 3 new changesets in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/c2233a7e653d/ changeset: r1376:c2233a7e653d user: hpk date: 2009-09-04 18:16:10 summary: reviewing, refactoring, porting xml/html object/tree generation to work with 3k affected #: 8 files (9.2 KB) http://www.bitbucket.org/hpk42/py-trunk/changeset/f321f2cf972c/ changeset: r1374:f321f2cf972c user: hpk date: 2009-09-04 16:51:29 summary: fix remaining execnet 3k issues until all tests pass affected #: 5 files (359 bytes) http://www.bitbucket.org/hpk42/py-trunk/changeset/0ac49e564217/ changeset: r1375:0ac49e564217 user: hpk date: 2009-09-04 18:15:41 summary: various 3k related fixes and cleanups removal of virtually unused py/rest/rst.py helpers affected #: 13 files (516 bytes) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Sep 4 18:31:16 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 04 Sep 2009 16:31:16 -0000 Subject: [py-svn] commit/py-trunk: hpk: make xmlgen a single file + a single file test instead of a whole directory Message-ID: <20090904163116.14905.63781@domU-12-31-39-00-95-01.compute-1.internal> 1 new changeset in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/622317fe7b5b/ changeset: r1377:622317fe7b5b user: hpk date: 2009-09-04 18:30:48 summary: make xmlgen a single file + a single file test instead of a whole directory affected #: 7 files (43 bytes) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Sep 4 19:08:45 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 04 Sep 2009 17:08:45 -0000 Subject: [py-svn] commit/py-trunk: hpk: introduce py.builtin._tryimport to try importing modules in a row, fix a few places Message-ID: <20090904170845.14905.38959@domU-12-31-39-00-95-01.compute-1.internal> 1 new changeset in py-trunk: http://www.bitbucket.org/hpk42/py-trunk/changeset/270ff4410124/ changeset: r1378:270ff4410124 user: hpk date: 2009-09-04 19:08:10 summary: introduce py.builtin._tryimport to try importing modules in a row, fix a few places affected #: 11 files (1002 bytes) Repository URL: http://bitbucket.org/hpk42/py-trunk/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Sep 4 19:08:52 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 4 Sep 2009 17:08:52 +0000 (UTC) Subject: [py-svn] py-trunk commit 270ff4410124: introduce py.builtin._tryimport to try importing modules in a row, fix a few places Message-ID: <20090904170852.7750071108@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252084090 -7200 # Node ID 270ff441012481c31a531c6c169a79790503f2cf # Parent 622317fe7b5be200fd471fde56b59d4321f5d927 introduce py.builtin._tryimport to try importing modules in a row, fix a few places --- a/py/builtin/builtin31.py +++ b/py/builtin/builtin31.py @@ -1,4 +1,4 @@ - +import py import sys if sys.version_info >= (3, 0): @@ -105,3 +105,13 @@ def _reraise(cls, val, tb): def exec2(obj, globals, locals): exec obj in globals, locals """) + +def _tryimport(*names): + """ return the first successfully imported module. """ + assert names + for name in names: + try: + return __import__(name, None, None, '__doc__') + except ImportError: + excinfo = sys.exc_info() + py.builtin._reraise(*excinfo) --- a/py/builtin/testing/test_builtin.py +++ b/py/builtin/testing/test_builtin.py @@ -139,3 +139,10 @@ def test_exec(): d = {} py.builtin.exec_("x=4", d) assert d['x'] == 4 + +def test_tryimport(): + py.test.raises(ImportError, py.builtin._tryimport, 'xqwe123') + x = py.builtin._tryimport('asldkajsdl', 'py') + assert x == py + x = py.builtin._tryimport('asldkajsdl', 'py.path') + assert x == py.path --- a/py/process/cmdexec.py +++ b/py/process/cmdexec.py @@ -12,6 +12,7 @@ Current list: import os, sys import py +from subprocess import Popen, PIPE #----------------------------------------------------------- # posix external command execution @@ -24,15 +25,10 @@ def posix_exec_cmd(cmd): the error-output from the command. """ #__tracebackhide__ = True - try: - from subprocess import Popen, PIPE - except ImportError: - from py.__.compat.subprocess import Popen, PIPE import errno - child = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, - close_fds=True) + child = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=True) stdin, stdout, stderr = child.stdin, child.stdout, child.stderr # XXX sometimes we get a blocked r.read() call (see below) --- a/py/__init__.py +++ b/py/__init__.py @@ -146,6 +146,7 @@ initpkg(__name__, 'builtin.GeneratorExit' : ('./builtin/builtin25.py', 'GeneratorExit'), 'builtin.print_' : ('./builtin/builtin31.py', 'print_'), 'builtin._reraise' : ('./builtin/builtin31.py', '_reraise'), + 'builtin._tryimport' : ('./builtin/builtin31.py', '_tryimport'), 'builtin.exec_' : ('./builtin/builtin31.py', 'exec_'), 'builtin._basestring' : ('./builtin/builtin31.py', '_basestring'), 'builtin._totext' : ('./builtin/builtin31.py', '_totext'), --- a/py/test/dist/dsession.py +++ b/py/test/dist/dsession.py @@ -8,10 +8,7 @@ import py from py.__.test.session import Session from py.__.test import outcome from py.__.test.dist.nodemanage import NodeManager -try: - import queue -except ImportError: - import Queue as queue +queue = py.builtin._tryimport('queue', 'Queue') debug_file = None # open('/tmp/loop.log', 'w') def debug(*args): --- a/py/code/testing/test_excinfo.py +++ b/py/code/testing/test_excinfo.py @@ -1,10 +1,7 @@ -try: - import Queue as queue -except ImportError: - import queue import py from py.__.code.code import FormattedExcinfo, ReprExceptionInfo +queue = py.builtin._tryimport('queue', 'Queue') class TWMock: def __init__(self): --- a/py/code/code.py +++ b/py/code/code.py @@ -2,11 +2,8 @@ import py import sys builtin_repr = repr -try: - import repr -except ImportError: - import reprlib as repr +repr = py.builtin._tryimport('repr', 'reprlib') class Code(object): """ wrapper around Python code objects """ --- a/py/thread/pool.py +++ b/py/thread/pool.py @@ -2,10 +2,8 @@ import threading import time import sys import py -try: - import queue -except ImportError: - import Queue as queue + +queue = py.builtin._tryimport('queue', 'Queue') ERRORMARKER = object() --- a/py/test/dist/testing/test_txnode.py +++ b/py/test/dist/testing/test_txnode.py @@ -1,11 +1,12 @@ import py from py.__.test.dist.txnode import TXNode +Queue = py.builtin._tryimport("queue.Queue", "Queue.Queue") class EventQueue: def __init__(self, registry, queue=None): if queue is None: - queue = py.std.Queue.Queue() + queue = Queue() self.queue = queue registry.register(self) @@ -43,7 +44,7 @@ class MySetup: if config is None: config = py.test.config._reparse([]) self.config = config - self.queue = py.std.Queue.Queue() + self.queue = Queue() self.xspec = py.execnet.XSpec("popen") self.gateway = py.execnet.makegateway(self.xspec) self.id += 1 --- a/py/path/testing/test_local.py +++ b/py/path/testing/test_local.py @@ -39,12 +39,8 @@ class TestLocalPath(common.CommonFSTests assert p == tmpdir def test_gethash(self, tmpdir): - try: - from md5 import md5 - from sha import sha - except ImportError: - from hashlib import md5 as md5 - from hashlib import sha1 as sha + md5 = py.builtin._tryimport('md5.md5', 'hashlib.md5') + sha = py.builtin._tryimport('sha.sha', 'hashlib.sha1') fn = tmpdir.join("testhashfile") data = 'hello'.encode('ascii') fn.write(data, mode="wb") --- a/py/execnet/rsync.py +++ b/py/execnet/rsync.py @@ -1,12 +1,7 @@ import py, os, stat -try: - from hashlib import md5 -except ImportError: - from md5 import md5 -try: - from queue import Queue -except ImportError: - from Queue import Queue + +md5 = py.builtin._tryimport('hashlib.md5', 'md5.md5') +queue = py.builtin._tryimport('queue.Queue', 'Queue.Queue') class RSync(object): """ This class allows to send a directory structure (recursively) From commits-noreply at bitbucket.org Fri Sep 4 22:00:50 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 4 Sep 2009 20:00:50 +0000 (UTC) Subject: [py-svn] py-trunk commit 06265cf3c537: * fixing lots of remaining 3k compatibility issues, mostly with py.test itself. Message-ID: <20090904200050.2AB2171114@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252093669 -7200 # Node ID 06265cf3c5376736c04df6f6ec3880d0d41ff6ee # Parent 270ff441012481c31a531c6c169a79790503f2cf * fixing lots of remaining 3k compatibility issues, mostly with py.test itself. * removing very old import-tests that IIRC relate to a time when there was a custom import hook in use. * basically py.test internal tests pass now except py3/py2 distributed testing tests --- a/py/test/dist/testing/test_txnode.py +++ b/py/test/dist/testing/test_txnode.py @@ -1,7 +1,8 @@ import py from py.__.test.dist.txnode import TXNode -Queue = py.builtin._tryimport("queue.Queue", "Queue.Queue") +queue = py.builtin._tryimport("queue", "Queue") +Queue = queue.Queue class EventQueue: def __init__(self, registry, queue=None): @@ -15,7 +16,7 @@ class EventQueue: while 1: try: eventcall = self.queue.get(timeout=timeout) - except py.std.Queue.Empty: + except queue.Empty: #print "node channel", self.node.channel #print "remoteerror", self.node.channel._getremoteerror() py.builtin.print_("seen events", events) --- a/py/test/dist/mypickle.py +++ b/py/test/dist/mypickle.py @@ -12,12 +12,22 @@ """ -from pickle import Pickler, Unpickler import py from py.__.execnet.gateway_base import Channel -import os +import sys, os #debug = open("log-mypickle-%d" % os.getpid(), 'w') +if sys.version_info >= (3,0): + makekey = lambda x: x + fromkey = lambda x: x + from pickle import _Pickler as Pickler + from pickle import _Unpickler as Unpickler +else: + makekey = str + fromkey = int + from pickle import Pickler, Unpickler + + class MyPickler(Pickler): """ Pickler with a custom memoize() to take care of unique ID creation. @@ -86,11 +96,11 @@ class ImmutablePickler: def _updatepicklememo(self): for x, obj in self._unpicklememo.items(): - self._picklememo[id(obj)] = (int(x), obj) + self._picklememo[id(obj)] = (fromkey(x), obj) def _updateunpicklememo(self): for key,obj in self._picklememo.values(): - key = str(key) + key = makekey(key) if key in self._unpicklememo: assert self._unpicklememo[key] is obj self._unpicklememo[key] = obj --- a/py/test/plugin/pytest_restdoc.py +++ b/py/test/plugin/pytest_restdoc.py @@ -426,7 +426,7 @@ class TestDoctest: >>> assert abspath >>> i=3 - >>> print i + >>> print (i) 3 yes yes @@ -450,7 +450,7 @@ class TestDoctest: def test_doctest_indentation(self, testdir): footxt = testdir.maketxtfile(foo= - '..\n >>> print "foo\\n bar"\n foo\n bar\n') + '..\n >>> print ("foo\\n bar")\n foo\n bar\n') reprec = testdir.inline_run(footxt) passed, skipped, failed = reprec.countoutcomes() assert failed == 0 --- a/py/path/testing/test_local.py +++ b/py/path/testing/test_local.py @@ -39,8 +39,9 @@ class TestLocalPath(common.CommonFSTests assert p == tmpdir def test_gethash(self, tmpdir): - md5 = py.builtin._tryimport('md5.md5', 'hashlib.md5') - sha = py.builtin._tryimport('sha.sha', 'hashlib.sha1') + md5 = py.builtin._tryimport('md5', 'hashlib').md5 + lib = py.builtin._tryimport('sha', 'hashlib') + sha = getattr(lib, 'sha1', getattr(lib, 'sha', None)) fn = tmpdir.join("testhashfile") data = 'hello'.encode('ascii') fn.write(data, mode="wb") --- a/py/execnet/rsync.py +++ b/py/execnet/rsync.py @@ -1,7 +1,7 @@ import py, os, stat -md5 = py.builtin._tryimport('hashlib.md5', 'md5.md5') -queue = py.builtin._tryimport('queue.Queue', 'Queue.Queue') +md5 = py.builtin._tryimport('hashlib', 'md5').md5 +Queue = py.builtin._tryimport('queue', 'Queue').Queue class RSync(object): """ This class allows to send a directory structure (recursively) --- a/py/test/dist/testing/acceptance_test.py +++ b/py/test/dist/testing/acceptance_test.py @@ -6,24 +6,28 @@ class TestDistribution: p1.dirpath("__init__.py").write("") p1.dirpath("conftest.py").write(py.code.Source(""" import py - py.builtin.print_("importing conftest", __file__) + from py.builtin import print_ + print_("importing conftest", __file__) Option = py.test.config.Option option = py.test.config.addoptions("someopt", - Option('--someopt', action="store_true", dest="someopt", default=False)) + Option('--someopt', action="store_true", + dest="someopt", default=False)) dist_rsync_roots = ['../dir'] - py.builtin.print_("added options", option) - py.builtin.print_("config file seen from conftest", py.test.config) + print_("added options", option) + print_("config file seen from conftest", py.test.config) """)) p1.write(py.code.Source(""" - import py, conftest + import py + from %s import conftest + from py.builtin import print_ def test_1(): - py.builtin.print_("config from test_1", py.test.config) - py.builtin.print_("conftest from test_1", conftest.__file__) - py.builtin.print_("test_1: py.test.config.option.someopt", py.test.config.option.someopt) - py.builtin.print_("test_1: conftest", conftest) - py.builtin.print_("test_1: conftest.option.someopt", conftest.option.someopt) + print_("config from test_1", py.test.config) + print_("conftest from test_1", conftest.__file__) + print_("test_1: py.test.config.option.someopt", py.test.config.option.someopt) + print_("test_1: conftest", conftest) + print_("test_1: conftest.option.someopt", conftest.option.someopt) assert conftest.option.someopt - """)) + """ % p1.dirpath().purebasename )) result = testdir.runpytest('-d', '--tx=popen', p1, '--someopt') assert result.ret == 0 extra = result.stdout.fnmatch_lines([ --- a/py/test/plugin/pytest_execnetcleanup.py +++ b/py/test/plugin/pytest_execnetcleanup.py @@ -48,7 +48,7 @@ def test_execnetplugin(testdir): sys._gw = py.execnet.PopenGateway() def test_world(): assert hasattr(sys, '_gw') - py.test.raises(KeyError, "sys._gw.exit()") # already closed + assert sys._gw not in sys._gw._cleanup._activegateways """, "-s", "--debug") reprec.assertoutcome(passed=2) --- a/py/test/dist/testing/test_mypickle.py +++ b/py/test/dist/testing/test_mypickle.py @@ -1,8 +1,11 @@ import py +import sys + +Queue = py.builtin._tryimport('queue', 'Queue').Queue + from py.__.test.dist.mypickle import ImmutablePickler, PickleChannel -from py.__.test.dist.mypickle import UnpickleError - +from py.__.test.dist.mypickle import UnpickleError, makekey # first let's test some basic functionality def pytest_generate_tests(metafunc): @@ -24,8 +27,8 @@ def pytest_generate_tests(metafunc): metafunc.addcall(funcargs=dict(obj=obj, proto=proto)) def test_underlying_basic_pickling_mechanisms(picklemod): - f1 = py.io.TextIO() - f2 = py.io.TextIO() + f1 = py.io.BytesIO() + f2 = py.io.BytesIO() pickler1 = picklemod.Pickler(f1) unpickler1 = picklemod.Unpickler(f2) @@ -48,8 +51,9 @@ def test_underlying_basic_pickling_mecha pickler2.dump(d_other) f2.seek(0) - - unpickler1.memo = dict([(str(x), y) for x, y in pickler1.memo.values()]) + + unpickler1.memo = dict([(makekey(x), y) + for x, y in pickler1.memo.values()]) d_back = unpickler1.load() assert d is d_back @@ -177,7 +181,7 @@ class TestPickleChannelFunctional: channel.send(a2 is a1) """) channel = PickleChannel(channel) - queue = py.std.Queue.Queue() + queue = Queue() channel.setcallback(queue.put) a_received = queue.get(timeout=TESTTIMEOUT) assert isinstance(a_received, A) @@ -198,7 +202,7 @@ class TestPickleChannelFunctional: channel.send(a2 is a1) """) channel = PickleChannel(channel) - queue = py.std.Queue.Queue() + queue = Queue() channel.setcallback(queue.put, endmarker=-1) a_received = queue.get(timeout=TESTTIMEOUT) @@ -220,7 +224,7 @@ class TestPickleChannelFunctional: channel.send(a1) """) channel = PickleChannel(channel) - queue = py.std.Queue.Queue() + queue = Queue() a = channel.receive() channel._ipickle._unpicklememo.clear() channel.setcallback(queue.put, endmarker=-1) --- a/py/test/plugin/pytest_capture.py +++ b/py/test/plugin/pytest_capture.py @@ -67,8 +67,8 @@ per-test capturing. Here is an example .. sourcecode:: python def test_myoutput(capsys): - print "hello" - print >>sys.stderr, "world" + print ("hello") + sys.stderr.write("world\n") out, err = capsys.readouterr() assert out == "hello\\n" assert err == "world\\n" --- a/py/test/plugin/pytest_helpconfig.py +++ b/py/test/plugin/pytest_helpconfig.py @@ -30,7 +30,7 @@ def pytest_configure(__multicall__, conf tw.sep("-") options = [opt for opt in options if opt._long_opts] - options.sort(lambda x, y: cmp(x._long_opts, y._long_opts)) + options.sort(key=lambda x: x._long_opts) for opt in options: if not opt._long_opts: continue --- a/py/test/testing/import_test/package/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/test/plugin/pytest_pytester.py +++ b/py/test/plugin/pytest_pytester.py @@ -379,7 +379,7 @@ class ReportRecorder(object): return passed, skipped, failed def countoutcomes(self): - return map(len, self.listoutcomes()) + return [len(x) for x in self.listoutcomes()] def assertoutcome(self, passed=0, skipped=0, failed=0): realpassed, realskipped, realfailed = self.listoutcomes() --- a/py/test/plugin/pytest_pastebin.py +++ b/py/test/plugin/pytest_pastebin.py @@ -37,7 +37,7 @@ def pytest_configure(__multicall__, conf import tempfile __multicall__.execute() if config.option.pastebin == "all": - config._pastebinfile = tempfile.TemporaryFile() + config._pastebinfile = tempfile.TemporaryFile('w+') tr = config.pluginmanager.impname2plugin['terminalreporter'] oldwrite = tr._tw.write def tee_write(s, **kwargs): @@ -53,7 +53,7 @@ def pytest_unconfigure(config): del config._pastebinfile proxyid = getproxy().newPaste("python", sessionlog) pastebinurl = "%s%s" % (url.show, proxyid) - print >>sys.stderr, "session-log:", pastebinurl + sys.stderr.write("session-log: %s" % pastebinurl) tr = config.pluginmanager.impname2plugin['terminalreporter'] del tr._tw.__dict__['write'] --- a/py/test/testing/test_genitems.py +++ b/py/test/testing/test_genitems.py @@ -26,12 +26,12 @@ class Test_genitems: def test_subdir_conftest_error(self, testdir): tmp = testdir.tmpdir - tmp.ensure("sub", "conftest.py").write("raise SyntaxError()\n") + tmp.ensure("sub", "conftest.py").write("raise SyntaxError('x')\n") items, reprec = testdir.inline_genitems(tmp) collectionfailures = reprec.getfailedcollections() assert len(collectionfailures) == 1 ev = collectionfailures[0] - assert ev.longrepr.reprcrash.message.startswith("SyntaxError") + assert "SyntaxError: x" in ev.longrepr.reprcrash.message def test_example_items1(self, testdir): p = testdir.makepyfile(''' --- a/py/test/plugin/test_pytest_terminal.py +++ b/py/test/plugin/test_pytest_terminal.py @@ -171,7 +171,7 @@ class TestTerminal: def g(): raise IndexError def test_func(): - print 6*7 + print (6*7) g() # --calling-- """) for tbopt in ["long", "short", "no"]: @@ -179,9 +179,9 @@ class TestTerminal: result = testdir.runpytest('--tb=%s' % tbopt) s = result.stdout.str() if tbopt == "long": - assert 'print 6*7' in s + assert 'print (6*7)' in s else: - assert 'print 6*7' not in s + assert 'print (6*7)' not in s if tbopt != "no": assert '--calling--' in s assert 'IndexError' in s @@ -411,7 +411,7 @@ class TestFixtureReporting: def test_setup_fixture_error(self, testdir): p = testdir.makepyfile(""" def setup_function(function): - print "setup func" + print ("setup func") assert 0 def test_nada(): pass @@ -431,7 +431,7 @@ class TestFixtureReporting: def test_nada(): pass def teardown_function(function): - print "teardown func" + print ("teardown func") assert 0 """) result = testdir.runpytest() @@ -450,7 +450,7 @@ class TestFixtureReporting: assert 0, "failingfunc" def teardown_function(function): - print "teardown func" + print ("teardown func") assert False """) result = testdir.runpytest() --- a/py/test/plugin/pytest_hooklog.py +++ b/py/test/plugin/pytest_hooklog.py @@ -8,7 +8,7 @@ def pytest_addoption(parser): def pytest_configure(config): hooklog = config.getvalue("hooklog") if hooklog: - config._hooklogfile = open(hooklog, 'w', 0) + config._hooklogfile = open(hooklog, 'w') config._hooklog_oldperformcall = config.hook._performcall config.hook._performcall = (lambda name, multicall: logged_call(name=name, multicall=multicall, config=config)) --- a/py/test/testing/import_test/package/module_that_imports_shared_lib.py +++ /dev/null @@ -1,1 +0,0 @@ -import shared_lib --- a/py/test/outcome.py +++ b/py/test/outcome.py @@ -25,7 +25,9 @@ class Passed(OutcomeException): pass class Skipped(OutcomeException): - pass + # XXX slighly hackish: on 3k we fake to live in the builtins + # in order to have Skipped exception printing shorter/nicer + __module__ = 'builtins' class Failed(OutcomeException): pass --- a/py/test/looponfail/remote.py +++ b/py/test/looponfail/remote.py @@ -10,6 +10,7 @@ from __future__ import generators import py +import sys from py.__.test.session import Session from py.__.test.dist.mypickle import PickleChannel from py.__.test.looponfail import util @@ -70,14 +71,19 @@ class RemoteControl(object): channel = self.gateway.remote_exec(source=""" from py.__.test.dist.mypickle import PickleChannel from py.__.test.looponfail.remote import slave_runsession + outchannel = channel.gateway.newchannel() + channel.send(outchannel) channel = PickleChannel(channel) config, fullwidth, hasmarkup = channel.receive() + import sys + sys.stdout = sys.stderr = outchannel.makefile('w') slave_runsession(channel, config, fullwidth, hasmarkup) - """, stdout=out, stderr=out) - channel = PickleChannel(channel) + """) + remote_outchannel = channel.receive() + remote_outchannel.setcallback(out._file.write) + channel = self.channel = PickleChannel(channel) channel.send((self.config, out.fullwidth, out.hasmarkup)) self.trace("set up of slave session complete") - self.channel = channel def ensure_teardown(self): if hasattr(self, 'channel'): --- a/py/test/testing/test_pickling.py +++ b/py/test/testing/test_pickling.py @@ -1,4 +1,5 @@ import py +import pickle def setglobals(request): oldconfig = py.test.config @@ -129,44 +130,41 @@ class TestConfigPickling: assert option.gdest == 11 def test_config_picklability(self, testdir): - import cPickle config = testdir.parseconfig() - s = cPickle.dumps(config) - newconfig = cPickle.loads(s) + s = pickle.dumps(config) + newconfig = pickle.loads(s) assert hasattr(newconfig, "topdir") assert newconfig.topdir == py.path.local() def test_collector_implicit_config_pickling(self, testdir): - from cPickle import Pickler, Unpickler tmpdir = testdir.tmpdir testdir.chdir() testdir.makepyfile(hello="def test_x(): pass") config = testdir.parseconfig(tmpdir) col = config.getfsnode(config.topdir) - io = py.io.TextIO() - pickler = Pickler(io) + io = py.io.BytesIO() + pickler = pickle.Pickler(io) pickler.dump(col) io.seek(0) - unpickler = Unpickler(io) + unpickler = pickle.Unpickler(io) col2 = unpickler.load() assert col2.name == col.name assert col2.listnames() == col.listnames() def test_config_and_collector_pickling(self, testdir): - from pickle import Pickler, Unpickler tmpdir = testdir.tmpdir dir1 = tmpdir.ensure("somedir", dir=1) config = testdir.parseconfig() col = config.getfsnode(config.topdir) col1 = col.join(dir1.basename) assert col1.parent is col - io = py.io.TextIO() - pickler = Pickler(io) + io = py.io.BytesIO() + pickler = pickle.Pickler(io) pickler.dump(col) pickler.dump(col1) pickler.dump(col) io.seek(0) - unpickler = Unpickler(io) + unpickler = pickle.Unpickler(io) topdir = tmpdir.ensure("newtopdir", dir=1) topdir.ensure("somedir", dir=1) old = topdir.chdir() --- a/py/test/testing/import_test/package/shared_lib.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -Just a dummy module -""" --- a/py/test/plugin/test_pytest_runner_xunit.py +++ b/py/test/plugin/test_pytest_runner_xunit.py @@ -99,22 +99,22 @@ def test_func_generator_setup(testdir): import sys def setup_module(mod): - print "setup_module" + print ("setup_module") mod.x = [] def setup_function(fun): - print "setup_function" + print ("setup_function") x.append(1) def teardown_function(fun): - print "teardown_function" + print ("teardown_function") x.pop() def test_one(): assert x == [1] def check(): - print "check" - print >>sys.stderr, "e" + print ("check") + sys.stderr.write("e\\n") assert x == [1] yield check assert x == [1] --- a/py/test/testing/test_outcome.py +++ b/py/test/testing/test_outcome.py @@ -1,6 +1,6 @@ import py -import marshal +import sys class TestRaises: def test_raises(self): @@ -42,3 +42,10 @@ def test_pytest_exit(): excinfo = py.code.ExceptionInfo() assert excinfo.errisinstance(KeyboardInterrupt) +def test_exception_printing_skip(): + try: + py.test.skip("hello") + except Exception: + excinfo = py.code.ExceptionInfo() + s = excinfo.exconly(tryshort=True) + assert s.startswith("Skipped") --- a/py/test/testing/import_test/package/absolute_import_shared_lib.py +++ /dev/null @@ -1,1 +0,0 @@ -from package import shared_lib --- a/py/test/testing/import_test/package/test_import.py +++ /dev/null @@ -1,53 +0,0 @@ -import sys -import os -import py - -def setup_module(mod=None): - if mod is None: - f = __file__ - else: - f = mod.__file__ - sys.path.append(os.path.dirname(os.path.dirname(f))) - -def teardown_module(mod=None): - if mod is None: - f = __file__ - else: - f = mod.__file__ - sys.path.remove(os.path.dirname(os.path.dirname(f))) - -def test_import(): - global shared_lib, module_that_imports_shared_lib - import shared_lib - from package import shared_lib as shared_lib2 - import module_that_imports_shared_lib - import absolute_import_shared_lib - all_modules = [ - ('shared_lib', shared_lib), - ('shared_lib2', shared_lib2), - ('module_that_imports_shared_lib', - module_that_imports_shared_lib.shared_lib), - ('absolute_import_shared_lib', - absolute_import_shared_lib.shared_lib), - ] - bad_matches = [] - while all_modules: - name1, mod1 = all_modules[0] - all_modules = all_modules[1:] - for name2, mod2 in all_modules: - if mod1 is not mod2: - bad_matches.append((name1, mod1, name2, mod2)) - for name1, mod1, name2, mod2 in bad_matches: - print("These modules should be identical:") - print(" %s:" % name1) - print(" ", mod1) - print(" %s:" % name2) - print(" ", mod2) - py.builtin.print_() - if bad_matches: - assert False - -if __name__ == "__main__": - setup_module() - test_import - teardown_module() From commits-noreply at bitbucket.org Sun Sep 6 13:39:24 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 6 Sep 2009 11:39:24 +0000 (UTC) Subject: [py-svn] py-trunk commit 4ffc38abb51a: execnet cleanup/refinements: avoid creating a shell for each subprocess Message-ID: <20090906113924.09AC771101@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252237101 -7200 # Node ID 4ffc38abb51a2f09dcdfabe07ff8bb382caaf209 # Parent 9e5882132194ec4b070d7f42801f0de5b4c90142 execnet cleanup/refinements: avoid creating a shell for each subprocess * introduce HostNotFound, raised for Socket and SshGateways * factored out basic tests, cleaned up existing tests * removed sshgateway identity argument which was deprecated in 1.0 --- a/py/execnet/testing/test_gateway.py +++ b/py/execnet/testing/test_gateway.py @@ -1,191 +1,13 @@ from __future__ import generators -import os, sys, time, signal +import os, sys, time import py -from py.__.execnet.gateway_base import Message, Channel, ChannelFactory -from py.__.execnet.gateway_base import ExecnetAPI, queue, Popen2IO from py.__.execnet import gateway_base, gateway +queue = py.builtin._tryimport('queue', 'Queue') -from py.__.execnet.gateway import startup_modules, getsource pytest_plugins = "pytester" TESTTIMEOUT = 10.0 # seconds -def pytest_generate_tests(metafunc): - if 'pythonpath' in metafunc.funcargnames: - for name in 'python2.4', 'python2.5', 'python2.6', 'python3.1': - metafunc.addcall(id=name, param=name) - -def pytest_funcarg__pythonpath(request): - name = request.param - executable = py.path.local.sysfind(name) - if executable is None: - py.test.skip("no %s found" % (name,)) - return executable - -def test_io_message(pythonpath, tmpdir): - check = tmpdir.join("check.py") - check.write(py.code.Source(gateway_base, """ - try: - from io import BytesIO - except ImportError: - from StringIO import StringIO as BytesIO - import tempfile - temp_out = BytesIO() - temp_in = BytesIO() - io = Popen2IO(temp_out, temp_in) - for i, msg_cls in Message._types.items(): - print ("checking %s %s" %(i, msg_cls)) - for data in "hello", "hello".encode('ascii'): - msg1 = msg_cls(i, data) - msg1.writeto(io) - x = io.outfile.getvalue() - io.outfile.truncate(0) - io.outfile.seek(0) - io.infile.seek(0) - io.infile.write(x) - io.infile.seek(0) - msg2 = Message.readfrom(io) - assert msg1.channelid == msg2.channelid, (msg1, msg2) - assert msg1.data == msg2.data - print ("all passed") - """)) - #out = py.process.cmdexec("%s %s" %(executable,check)) - out = pythonpath.sysexec(check) - print (out) - assert "all passed" in out - -def test_popen_io(pythonpath, tmpdir): - check = tmpdir.join("check.py") - check.write(py.code.Source(gateway_base, """ - do_exec(Popen2IO.server_stmt, globals()) - io.write("hello".encode('ascii')) - s = io.read(1) - assert s == "x".encode('ascii') - """)) - from subprocess import Popen, PIPE - args = [str(pythonpath), str(check)] - proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) - proc.stdin.write("x".encode('ascii')) - stdout, stderr = proc.communicate() - print (stderr) - ret = proc.wait() - assert "hello".encode('ascii') in stdout - -def test_rinfo_source(pythonpath, tmpdir): - check = tmpdir.join("check.py") - check.write(py.code.Source(""" - class Channel: - def send(self, data): - assert eval(repr(data), {}) == data - channel = Channel() - """, gateway.rinfo_source, """ - print ('all passed') - """)) - out = pythonpath.sysexec(check) - print (out) - assert "all passed" in out - -def test_geterrortext(pythonpath, tmpdir): - check = tmpdir.join("check.py") - check.write(py.code.Source(gateway_base, """ - class Arg: - pass - errortext = geterrortext((Arg, "1", 4)) - assert "Arg" in errortext - import sys - try: - raise ValueError("17") - except ValueError: - excinfo = sys.exc_info() - s = geterrortext(excinfo) - assert "17" in s - print ("all passed") - """)) - out = pythonpath.sysexec(check) - print (out) - assert "all passed" in out - -class TestExecnetEvents: - def test_popengateway(self, _pytest): - rec = _pytest.gethookrecorder(ExecnetAPI) - gw = py.execnet.PopenGateway() - call = rec.popcall("pyexecnet_gateway_init") - assert call.gateway == gw - gw.exit() - call = rec.popcall("pyexecnet_gateway_exit") - assert call.gateway == gw - - -def test_getsource_import_modules(): - for dottedname in startup_modules: - yield getsource, dottedname - -def test_getsource_no_colision(): - seen = {} - for dottedname in startup_modules: - mod = __import__(dottedname, None, None, ['__doc__']) - for name, value in vars(mod).items(): - if py.std.inspect.isclass(value): - if name in seen: - olddottedname, oldval = seen[name] - if oldval is not value: - py.test.fail("duplicate class %r in %s and %s" % - (name, dottedname, olddottedname)) - seen[name] = (dottedname, value) - -def test_stdouterrin_setnull(): - cap = py.io.StdCaptureFD() - from py.__.execnet.gateway import stdouterrin_setnull - stdouterrin_setnull() - import os - os.write(1, "hello".encode('ascii')) - if os.name == "nt": - os.write(2, "world") - os.read(0, 1) - out, err = cap.reset() - assert not out - assert not err - - -class TestMessage: - def test_wire_protocol(self): - for cls in Message._types.values(): - one = py.io.BytesIO() - data = '23'.encode('ascii') - cls(42, data).writeto(one) - two = py.io.BytesIO(one.getvalue()) - msg = Message.readfrom(two) - assert isinstance(msg, cls) - assert msg.channelid == 42 - assert msg.data == data - assert isinstance(repr(msg), str) - # == "" %(msg.__class__.__name__, ) - -class TestPureChannel: - def setup_method(self, method): - self.fac = 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._channels[chan1.id] == chan1 - chan2 = self.fac.new() - assert self.fac._channels[chan2.id] == chan2 - - def test_channel_timeouterror(self): - channel = self.fac.new() - py.test.raises(IOError, channel.waitclose, timeout=0.01) - - def test_channel_makefile_incompatmode(self): - channel = self.fac.new() - py.test.raises(ValueError, 'channel.makefile("rw")') - - class PopenGatewayTestSetup: def setup_class(cls): cls.gw = py.execnet.PopenGateway() @@ -648,6 +470,7 @@ class TestPopenGateway(PopenGatewayTestS py.test.raises(EOFError, channel.send, None) py.test.raises(EOFError, channel.receive) + at py.test.mark.xfail def test_endmarker_delivery_on_remote_killterm(): if not hasattr(py.std.os, 'kill'): py.test.skip("no os.kill()") @@ -664,8 +487,8 @@ def test_endmarker_delivery_on_remote_ki err = channel._getremoteerror() finally: gw.exit() - py.test.skip("provide information on causes/signals " - "of dying remote gateways") + assert "killed" in str(err) + assert "15" in str(err) class SocketGatewaySetup: @@ -675,6 +498,10 @@ class SocketGatewaySetup: cls.gw = py.execnet.SocketGateway.new_remote(cls.proxygw, ("127.0.0.1", 0) ) + def test_host_not_found(self): + py.test.raises(py.execnet.HostNotFound, + 'py.execnet.SocketGateway("qowieuqowe", 9000)' + ) ## def teardown_class(cls): ## cls.gw.exit() @@ -695,27 +522,16 @@ class TestSshGateway(BasicRemoteExecutio "Host alias123\n" " HostName %s\n" % self.sshhost) gw = py.execnet.SshGateway("alias123", ssh_config=ssh_config) - assert gw._cmd.find("-F") != -1 - assert gw._cmd.find(str(ssh_config)) != -1 pid = gw.remote_exec("import os ; channel.send(os.getpid())").receive() gw.exit() def test_sshaddress(self): assert self.gw.remoteaddress == self.sshhost - @py.test.mark.xfail # XXX ssh-gateway error handling def test_connexion_failes_on_non_existing_hosts(self): - py.test.raises(IOError, + py.test.raises(py.execnet.HostNotFound, "py.execnet.SshGateway('nowhere.codespeak.net')") - @py.test.mark.xfail # "XXX ssh-gateway error handling" - def test_deprecated_identity(self): - py.test.deprecated_call( - py.test.raises, IOError, - py.execnet.SshGateway, - 'nowhere.codespeak.net', identity='qwe') - - def test_threads(): gw = py.execnet.PopenGateway() gw.remote_init_threads(3) @@ -734,26 +550,17 @@ def test_threads_twice(): gw.remote_init_threads(3) py.test.raises(IOError, gw.remote_init_threads, 3) gw.exit() - + +class TestExecnetEvents: + def test_popengateway(self, _pytest): + rec = _pytest.gethookrecorder(gateway_base.ExecnetAPI) + gw = py.execnet.PopenGateway() + call = rec.popcall("pyexecnet_gateway_init") + assert call.gateway == gw + gw.exit() + call = rec.popcall("pyexecnet_gateway_exit") + assert call.gateway == gw def test_nodebug(): from py.__.execnet import gateway_base assert not gateway_base.debug - -def test_channel_endmarker_remote_killterm(): - gw = py.execnet.PopenGateway() - try: - q = queue.Queue() - channel = gw.remote_exec(''' - import os - os.kill(os.getpid(), 15) - ''') - channel.setcallback(q.put, endmarker=999) - val = q.get(TESTTIMEOUT) - assert val == 999 - err = channel._getremoteerror() - finally: - gw.exit() - py.test.skip("provide information on causes/signals " - "of dying remote gateways") - --- a/py/execnet/gateway.py +++ b/py/execnet/gateway.py @@ -195,11 +195,8 @@ channel.send(dict( """ class PopenCmdGateway(InitiatingGateway): - def __init__(self, cmd): - # on win close_fds=True does not work, not sure it'd needed - #p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, close_fds=True) - self._popen = p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE) - self._cmd = cmd + def __init__(self, args): + self._popen = p = Popen(args, stdin=PIPE, stdout=PIPE) io = Popen2IO(p.stdin, p.stdout) super(PopenCmdGateway, self).__init__(io=io) @@ -207,6 +204,7 @@ class PopenCmdGateway(InitiatingGateway) super(PopenCmdGateway, self).exit() self._popen.poll() +popen_bootstrapline = "import sys ; exec(eval(sys.stdin.readline()))" class PopenGateway(PopenCmdGateway): """ This Gateway provides interaction with a newly started python subprocess. @@ -217,9 +215,8 @@ class PopenGateway(PopenCmdGateway): """ if not python: python = sys.executable - cmd = ('%s -u -c "import sys ; ' - 'exec(eval(sys.stdin.readline()))"' % python) - super(PopenGateway, self).__init__(cmd) + args = [str(python), '-c', popen_bootstrapline] + super(PopenGateway, self).__init__(args) def _remote_bootstrap_gateway(self, io, extra=''): # have the subprocess use the same PYTHONPATH and py lib @@ -250,7 +247,10 @@ class SocketGateway(InitiatingGateway): self.port = port = int(port) self.remoteaddress = '%s:%d' % (self.host, self.port) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect((host, port)) + try: + sock.connect((host, port)) + except socket.gaierror: + raise HostNotFound(str(sys.exc_info()[1])) io = SocketIO(sock) super(SocketGateway, self).__init__(io=io) @@ -280,36 +280,29 @@ class SocketGateway(InitiatingGateway): return py.execnet.SocketGateway(host, realport) new_remote = classmethod(new_remote) +class HostNotFound(Exception): + pass class SshGateway(PopenCmdGateway): """ This Gateway provides interaction with a remote Python process, established via the 'ssh' command line binary. The remote side needs to have a Python interpreter executable. """ - def __init__(self, sshaddress, remotepython=None, - identity=None, ssh_config=None): + + def __init__(self, sshaddress, remotepython=None, ssh_config=None): """ instantiate a remote ssh process with the given 'sshaddress' and remotepython version. you may specify an ssh_config file. - DEPRECATED: you may specify an 'identity' filepath. """ self.remoteaddress = sshaddress if remotepython is None: remotepython = "python" - remotecmd = '%s -u -c "exec input()"' % (remotepython,) - cmdline = [sshaddress, remotecmd] - # XXX Unix style quoting - for i in range(len(cmdline)): - cmdline[i] = "'" + cmdline[i].replace("'", "'\\''") + "'" - cmd = 'ssh -C' - if identity is not None: - py.log._apiwarn("1.0", "pass in 'ssh_config' file instead of identity") - cmd += ' -i %s' % (identity,) + args = ['ssh', '-C' ] if ssh_config is not None: - cmd += ' -F %s' % (ssh_config) - cmdline.insert(0, cmd) - cmd = ' '.join(cmdline) - super(SshGateway, self).__init__(cmd) + args.extend(['-F', str(ssh_config)]) + remotecmd = '%s -c "%s"' %(remotepython, popen_bootstrapline) + args.extend([sshaddress, remotecmd]) + super(SshGateway, self).__init__(args) def _remote_bootstrap_gateway(self, io, s=""): extra = "\n".join([ @@ -317,8 +310,12 @@ class SshGateway(PopenCmdGateway): "stdouterrin_setnull()", s, ]) - super(SshGateway, self)._remote_bootstrap_gateway(io, extra) - + try: + super(SshGateway, self)._remote_bootstrap_gateway(io, extra) + except EOFError: + ret = self._popen.wait() + if ret == 255: + raise HostNotFound(self.remoteaddress) def stdouterrin_setnull(): """ redirect file descriptors 0 and 1 (and possibly 2) to /dev/null. --- /dev/null +++ b/py/execnet/testing/test_basics.py @@ -0,0 +1,215 @@ + +import py +import sys, os, subprocess, inspect +from py.__.execnet import gateway_base, gateway +from py.__.execnet.gateway_base import Message, Channel, ChannelFactory + +def test_subprocess_interaction(anypython): + line = gateway.popen_bootstrapline + compile(line, 'xyz', 'exec') + args = [str(anypython), '-c', line] + popen = subprocess.Popen(args, bufsize=0, stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, stdout=subprocess.PIPE) + def send(line): + popen.stdin.write(line.encode('ascii')) + if sys.version_info > (3,0): # 3k still buffers + popen.stdin.flush() + def receive(): + return popen.stdout.readline().decode('ascii') + + try: + source = py.code.Source(read_write_loop, "read_write_loop()") + repr_source = repr(str(source)) + "\n" + sendline = repr_source + send(sendline) + s = receive() + assert s == "ok\n" + send("hello\n") + s = receive() + assert s == "received: hello\n" + send("world\n") + s = receive() + assert s == "received: world\n" + finally: + popen.stdin.close() + popen.stdout.close() + popen.wait() + +def read_write_loop(): + import os, sys + sys.stdout.write("ok\n") + sys.stdout.flush() + while 1: + try: + line = sys.stdin.readline() + sys.stdout.write("received: %s" % line) + sys.stdout.flush() + except (IOError, EOFError): + break + +def pytest_generate_tests(metafunc): + if 'anypython' in metafunc.funcargnames: + for name in 'python3.1', 'python2.4', 'python2.5', 'python2.6': + metafunc.addcall(id=name, param=name) + +def pytest_funcarg__anypython(request): + name = request.param + executable = py.path.local.sysfind(name) + if executable is None: + py.test.skip("no %s found" % (name,)) + return executable + +def test_io_message(anypython, tmpdir): + check = tmpdir.join("check.py") + check.write(py.code.Source(gateway_base, """ + try: + from io import BytesIO + except ImportError: + from StringIO import StringIO as BytesIO + import tempfile + temp_out = BytesIO() + temp_in = BytesIO() + io = Popen2IO(temp_out, temp_in) + for i, msg_cls in Message._types.items(): + print ("checking %s %s" %(i, msg_cls)) + for data in "hello", "hello".encode('ascii'): + msg1 = msg_cls(i, data) + msg1.writeto(io) + x = io.outfile.getvalue() + io.outfile.truncate(0) + io.outfile.seek(0) + io.infile.seek(0) + io.infile.write(x) + io.infile.seek(0) + msg2 = Message.readfrom(io) + assert msg1.channelid == msg2.channelid, (msg1, msg2) + assert msg1.data == msg2.data + print ("all passed") + """)) + #out = py.process.cmdexec("%s %s" %(executable,check)) + out = anypython.sysexec(check) + print (out) + assert "all passed" in out + +def test_popen_io(anypython, tmpdir): + check = tmpdir.join("check.py") + check.write(py.code.Source(gateway_base, """ + do_exec(Popen2IO.server_stmt, globals()) + io.write("hello".encode('ascii')) + s = io.read(1) + assert s == "x".encode('ascii') + """)) + from subprocess import Popen, PIPE + args = [str(anypython), str(check)] + proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + proc.stdin.write("x".encode('ascii')) + stdout, stderr = proc.communicate() + print (stderr) + ret = proc.wait() + assert "hello".encode('ascii') in stdout + + +def test_rinfo_source(anypython, tmpdir): + check = tmpdir.join("check.py") + check.write(py.code.Source(""" + class Channel: + def send(self, data): + assert eval(repr(data), {}) == data + channel = Channel() + """, gateway.rinfo_source, """ + print ('all passed') + """)) + out = anypython.sysexec(check) + print (out) + assert "all passed" in out + +def test_geterrortext(anypython, tmpdir): + check = tmpdir.join("check.py") + check.write(py.code.Source(gateway_base, """ + class Arg: + pass + errortext = geterrortext((Arg, "1", 4)) + assert "Arg" in errortext + import sys + try: + raise ValueError("17") + except ValueError: + excinfo = sys.exc_info() + s = geterrortext(excinfo) + assert "17" in s + print ("all passed") + """)) + out = anypython.sysexec(check) + print (out) + assert "all passed" in out + +def test_getsource_import_modules(): + for dottedname in gateway.startup_modules: + yield gateway.getsource, dottedname + +def test_getsource_no_colision(): + seen = {} + for dottedname in gateway.startup_modules: + mod = __import__(dottedname, None, None, ['__doc__']) + for name, value in vars(mod).items(): + if py.std.inspect.isclass(value): + if name in seen: + olddottedname, oldval = seen[name] + if oldval is not value: + py.test.fail("duplicate class %r in %s and %s" % + (name, dottedname, olddottedname)) + seen[name] = (dottedname, value) + +def test_stdouterrin_setnull(): + cap = py.io.StdCaptureFD() + from py.__.execnet.gateway import stdouterrin_setnull + stdouterrin_setnull() + import os + os.write(1, "hello".encode('ascii')) + if os.name == "nt": + os.write(2, "world") + os.read(0, 1) + out, err = cap.reset() + assert not out + assert not err + + +class TestMessage: + def test_wire_protocol(self): + for cls in Message._types.values(): + one = py.io.BytesIO() + data = '23'.encode('ascii') + cls(42, data).writeto(one) + two = py.io.BytesIO(one.getvalue()) + msg = Message.readfrom(two) + assert isinstance(msg, cls) + assert msg.channelid == 42 + assert msg.data == data + assert isinstance(repr(msg), str) + # == "" %(msg.__class__.__name__, ) + +class TestPureChannel: + def setup_method(self, method): + self.fac = 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._channels[chan1.id] == chan1 + chan2 = self.fac.new() + assert self.fac._channels[chan2.id] == chan2 + + def test_channel_timeouterror(self): + channel = self.fac.new() + py.test.raises(IOError, channel.waitclose, timeout=0.01) + + def test_channel_makefile_incompatmode(self): + channel = self.fac.new() + py.test.raises(ValueError, 'channel.makefile("rw")') + + --- a/py/__init__.py +++ b/py/__init__.py @@ -165,6 +165,7 @@ initpkg(__name__, 'execnet.SocketGateway' : ('./execnet/gateway.py', 'SocketGateway'), 'execnet.PopenGateway' : ('./execnet/gateway.py', 'PopenGateway'), 'execnet.SshGateway' : ('./execnet/gateway.py', 'SshGateway'), + 'execnet.HostNotFound' : ('./execnet/gateway.py', 'HostNotFound'), 'execnet.XSpec' : ('./execnet/xspec.py', 'XSpec'), 'execnet.makegateway' : ('./execnet/xspec.py', 'makegateway'), 'execnet.MultiGateway' : ('./execnet/multi.py', 'MultiGateway'), From commits-noreply at bitbucket.org Sun Sep 6 13:39:32 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 6 Sep 2009 11:39:32 +0000 (UTC) Subject: [py-svn] py-trunk commit 687b208efc07: * refactor some setup/teardown/ensuretemp usages to use funcargs Message-ID: <20090906113932.85D2971111@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252185718 -7200 # Node ID 687b208efc077843d12f69a9bdcce6c1813facc1 # Parent 8f764e29e5e9f13d1a3accef0e39f522b03da22a * refactor some setup/teardown/ensuretemp usages to use funcargs * introduce monkeypatch.syspath_prepend for safe monkey patching of module import path * fix monkeypatch naming --- a/py/test/plugin/test_pytest_capture.py +++ b/py/test/plugin/test_pytest_capture.py @@ -10,7 +10,7 @@ class TestCaptureManager: try: assert capman._getmethod(config, None) == "sys" finally: - monkeypatch.finalize() + monkeypatch.undo() def test_configure_per_fspath(self, testdir): config = testdir.parseconfig(testdir.tmpdir) --- a/py/execnet/testing/test_rsync.py +++ b/py/execnet/testing/test_rsync.py @@ -2,38 +2,37 @@ import py from py.execnet import RSync -def setup_module(mod): - mod.gw = py.execnet.PopenGateway() - mod.gw2 = py.execnet.PopenGateway() +def pytest_funcarg__gw1(request): + return request.cached_setup( + setup=py.execnet.PopenGateway, + teardown=lambda val: val.exit(), + scope="module" + ) +pytest_funcarg__gw2 = pytest_funcarg__gw1 -def teardown_module(mod): - mod.gw.exit() - mod.gw2.exit() +def pytest_funcarg__dirs(request): + t = request.getfuncargvalue('tmpdir') + class dirs: + source = t.join("source") + dest1 = t.join("dest1") + dest2 = t.join("dest2") + return dirs - -class DirSetup: - def setup_method(self, method): - name = "%s.%s" %(self.__class__.__name__, method.__name__) - self.tmpdir = t = py.test.ensuretemp(name) - self.source = t.join("source") - self.dest1 = t.join("dest1") - self.dest2 = t.join("dest2") - -class TestRSync(DirSetup): - def test_notargets(self): - rsync = RSync(self.source) +class TestRSync: + def test_notargets(self, dirs): + rsync = RSync(dirs.source) py.test.raises(IOError, "rsync.send()") assert rsync.send(raises=False) is None - def test_dirsync(self): - dest = self.dest1 - dest2 = self.dest2 - source = self.source + def test_dirsync(self, dirs, gw1, gw2): + dest = dirs.dest1 + dest2 = dirs.dest2 + source = dirs.source for s in ('content1', 'content2', 'content2-a-bit-longer'): source.ensure('subdir', 'file1').write(s) - rsync = RSync(self.source) - rsync.add_target(gw, dest) + rsync = RSync(dirs.source) + rsync.add_target(gw1, dest) rsync.add_target(gw2, dest2) rsync.send() assert dest.join('subdir').check(dir=1) @@ -49,76 +48,70 @@ class TestRSync(DirSetup): source.join('subdir').remove('file1') rsync = RSync(source) rsync.add_target(gw2, dest2) - rsync.add_target(gw, dest) + rsync.add_target(gw1, dest) rsync.send() assert dest.join('subdir', 'file1').check(file=1) assert dest2.join('subdir', 'file1').check(file=1) rsync = RSync(source) - rsync.add_target(gw, dest, delete=True) + rsync.add_target(gw1, dest, delete=True) rsync.add_target(gw2, dest2) rsync.send() assert not dest.join('subdir', 'file1').check() assert dest2.join('subdir', 'file1').check() - def test_dirsync_twice(self): - source = self.source + def test_dirsync_twice(self, dirs, gw1, gw2): + source = dirs.source source.ensure("hello") rsync = RSync(source) - rsync.add_target(gw, self.dest1) + rsync.add_target(gw1, dirs.dest1) rsync.send() - assert self.dest1.join('hello').check() + assert dirs.dest1.join('hello').check() py.test.raises(IOError, "rsync.send()") assert rsync.send(raises=False) is None - rsync.add_target(gw, self.dest2) + rsync.add_target(gw1, dirs.dest2) rsync.send() - assert self.dest2.join('hello').check() + assert dirs.dest2.join('hello').check() py.test.raises(IOError, "rsync.send()") assert rsync.send(raises=False) is None - def test_rsync_default_reporting(self): - source = self.source + def test_rsync_default_reporting(self, capsys, dirs, gw1): + source = dirs.source source.ensure("hello") - cap = py.io.StdCapture() - try: - rsync = RSync(source) - rsync.add_target(gw, self.dest1) - rsync.send() - finally: - out, err = cap.reset() + rsync = RSync(source) + rsync.add_target(gw1, dirs.dest1) + rsync.send() + out, err = capsys.readouterr() assert out.find("hello") != -1 - def test_rsync_non_verbose(self): - source = self.source + def test_rsync_non_verbose(self, capsys, dirs, gw1): + source = dirs.source source.ensure("hello") - cap = py.io.StdCapture() - try: - rsync = RSync(source, verbose=False) - rsync.add_target(gw, self.dest1) - rsync.send() - finally: - out, err = cap.reset() + rsync = RSync(source, verbose=False) + rsync.add_target(gw1, dirs.dest1) + rsync.send() + out, err = capsys.readouterr() assert not out assert not err - def test_symlink_rsync(self): + def test_symlink_rsync(self, dirs, gw1): if py.std.sys.platform == 'win32': py.test.skip("symlinks are unsupported on Windows.") - source = self.source - dest = self.dest1 - self.source.ensure("existant") + source = dirs.source + dest = dirs.dest1 + dirs.source.ensure("existant") source.join("rellink").mksymlinkto(source.join("existant"), absolute=0) source.join('abslink').mksymlinkto(source.join("existant")) rsync = RSync(source) - rsync.add_target(gw, dest) + rsync.add_target(gw1, dest) rsync.send() assert dest.join('rellink').readlink() == dest.join("existant") assert dest.join('abslink').readlink() == dest.join("existant") - def test_callback(self): - dest = self.dest1 - source = self.source + def test_callback(self, dirs, gw1): + dest = dirs.dest1 + source = dirs.source source.ensure("existant").write("a" * 100) source.ensure("existant2").write("a" * 10) total = {} @@ -127,14 +120,14 @@ class TestRSync(DirSetup): rsync = RSync(source, callback=callback) #rsync = RSync() - rsync.add_target(gw, dest) + rsync.add_target(gw1, dest) rsync.send() assert total == {("list", 110):True, ("ack", 100):True, ("ack", 10):True} - def test_file_disappearing(self): - dest = self.dest1 - source = self.source + def test_file_disappearing(self, dirs, gw1): + dest = dirs.dest1 + source = dirs.source source.ensure("ex").write("a" * 100) source.ensure("ex2").write("a" * 100) @@ -147,7 +140,7 @@ class TestRSync(DirSetup): return True rsync = DRsync(source) - rsync.add_target(gw, dest) + rsync.add_target(gw1, dest) rsync.send() assert rsync.x == 1 assert len(dest.listdir()) == 1 --- a/py/path/testing/test_local.py +++ b/py/path/testing/test_local.py @@ -325,9 +325,8 @@ class TestImport: from xxxpackage import module1 assert module1 is mod1 -def test_pypkgdir(): - datadir = py.test.ensuretemp("pypkgdir") - pkg = datadir.ensure('pkg1', dir=1) +def test_pypkgdir(tmpdir): + pkg = tmpdir.ensure('pkg1', dir=1) pkg.ensure("__init__.py") pkg.ensure("subdir/__init__.py") assert pkg.pypkgpath() == pkg --- a/py/execnet/testing/test_gwmanage.py +++ b/py/execnet/testing/test_gwmanage.py @@ -6,6 +6,7 @@ """ import py +import os from py.__.execnet.gwmanage import GatewayManager, HostRSync class TestGatewayManagerPopen: @@ -75,7 +76,6 @@ class TestGatewayManagerPopen: call = rec.popcall("pyexecnet_gwmanage_rsyncfinish") def test_multi_chdir_popen_with_path(self, testdir): - import os hm = GatewayManager(["popen//chdir=hello"] * 2) testdir.tmpdir.chdir() hellopath = testdir.tmpdir.mkdir("hello").realpath() @@ -117,7 +117,7 @@ class TestGatewayManagerPopen: class pytest_funcarg__mysetup: def __init__(self, request): - tmp = request.config.mktemp(request.function.__name__, numbered=True) + tmp = request.getfuncargvalue('tmpdir') self.source = tmp.mkdir("source") self.dest = tmp.mkdir("dest") request.getfuncargvalue("_pytest") # to have patching of py._com.comregistry --- a/py/execnet/testing/test_gateway.py +++ b/py/execnet/testing/test_gateway.py @@ -689,8 +689,7 @@ class TestSshGateway(BasicRemoteExecutio cls.sshhost = getspecssh().ssh cls.gw = py.execnet.SshGateway(cls.sshhost) - def test_sshconfig_functional(self): - tmpdir = py.test.ensuretemp("test_sshconfig") + def test_sshconfig_functional(self, tmpdir): ssh_config = tmpdir.join("ssh_config") ssh_config.write( "Host alias123\n" --- a/py/test/plugin/pytest_monkeypatch.py +++ b/py/test/plugin/pytest_monkeypatch.py @@ -48,7 +48,7 @@ object, however. .. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ """ -import py, os +import py, os, sys def pytest_funcarg__monkeypatch(request): """The returned ``monkeypatch`` funcarg provides these @@ -60,6 +60,7 @@ def pytest_funcarg__monkeypatch(request) monkeypatch.delitem(obj, name, raising=True) monkeypatch.setenv(name, value, prepend=False) monkeypatch.delenv(name, value, raising=True) + monkeypatch.syspath_prepend(path) All modifications will be undone when the requesting test function finished its execution. For the ``del`` @@ -111,6 +112,11 @@ class MonkeyPatch: def delenv(self, name, raising=True): self.delitem(os.environ, name, raising=raising) + def syspath_prepend(self, path): + if not hasattr(self, '_savesyspath'): + self._savesyspath = sys.path[:] + sys.path.insert(0, str(path)) + def undo(self): for obj, name, value in self._setattr: if value is not notset: @@ -124,7 +130,8 @@ class MonkeyPatch: else: dictionary[name] = value self._setitem[:] = [] - + if hasattr(self, '_savesyspath'): + sys.path[:] = self._savesyspath def test_setattr(): class A: @@ -242,4 +249,20 @@ def test_monkeypatch_plugin(testdir): """) res = reprec.countoutcomes() assert tuple(res) == (1, 0, 0), res - + +def test_syspath_prepend(): + old = list(sys.path) + try: + monkeypatch = MonkeyPatch() + monkeypatch.syspath_prepend('world') + monkeypatch.syspath_prepend('hello') + assert sys.path[0] == "hello" + assert sys.path[1] == "world" + monkeypatch.undo() + assert sys.path == old + monkeypatch.undo() + assert sys.path == old + finally: + sys.path[:] = old + + --- a/py/_testing/test_initpkg.py +++ b/py/_testing/test_initpkg.py @@ -48,7 +48,7 @@ def test_virtual_module_identity(): def test_importall(): base = py.path.local(py.__file__).dirpath() - nodirs = ( + nodirs = [ base.join('test', 'testing', 'data'), base.join('test', 'web'), base.join('path', 'gateway',), @@ -57,10 +57,14 @@ def test_importall(): base.join('test', 'testing', 'import_test'), base.join('bin'), base.join('code', 'oldmagic.py'), - base.join('code', '_assertionold.py'), base.join('execnet', 'script'), base.join('compat', 'testing'), - ) + ] + if sys.version_info >= (3,0): + nodirs.append(base.join('code', '_assertionold.py')) + else: + nodirs.append(base.join('code', '_assertionnew.py')) + def recurse(p): return p.check(dotfile=0) and p.basename != "attic" --- a/py/path/testing/conftest.py +++ b/py/path/testing/conftest.py @@ -10,8 +10,9 @@ def pytest_funcarg__repowc1(request): py.test.skip("svn binary not found") modname = request.module.__name__ + tmpdir = request.getfuncargvalue("tmpdir") repo, wc = request.cached_setup( - setup=lambda: getrepowc("repo-"+modname, "wc-" + modname), + setup=lambda: getrepowc(tmpdir, "repo-"+modname, "wc-" + modname), scope="module", ) for x in ('test_remove', 'test_move', 'test_status_deleted'): @@ -21,8 +22,9 @@ def pytest_funcarg__repowc1(request): return repo, wc def pytest_funcarg__repowc2(request): + tmpdir = request.getfuncargvalue("tmpdir") name = request.function.__name__ - return getrepowc("%s-repo-2" % name, "%s-wc-2" % name) + return getrepowc(tmpdir, "%s-repo-2" % name, "%s-wc-2" % name) def getsvnbin(): if svnbin is None: @@ -32,9 +34,9 @@ def getsvnbin(): # make a wc directory out of a given root url # cache previously obtained wcs! # -def getrepowc(reponame='basetestrepo', wcname='wc'): - repo = py.test.ensuretemp(reponame) - wcdir = py.test.ensuretemp(wcname) +def getrepowc(tmpdir, reponame='basetestrepo', wcname='wc'): + repo = tmpdir.mkdir(reponame) + wcdir = tmpdir.mkdir(wcname) repo.ensure(dir=1) py.process.cmdexec('svnadmin create "%s"' % svncommon._escape_helper(repo)) From commits-noreply at bitbucket.org Sun Sep 6 13:39:39 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 6 Sep 2009 11:39:39 +0000 (UTC) Subject: [py-svn] py-trunk commit 9e5882132194: seems like compile is way slower than just parser.suite so Message-ID: <20090906113939.88A4C7111D@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252233352 -7200 # Node ID 9e5882132194ec4b070d7f42801f0de5b4c90142 # Parent 687b208efc077843d12f69a9bdcce6c1813facc1 seems like compile is way slower than just parser.suite so we try to see if it's available (only jython doesn't have it) --- a/py/code/source.py +++ b/py/code/source.py @@ -157,12 +157,20 @@ class Source(object): """ return True if source is parseable, heuristically deindenting it by default. """ + try: + import parser + except ImportError: + syntax_checker = lambda x: compile(x, 'asd', 'exec') + else: + syntax_checker = parser.suite + if deindent: source = str(self.deindent()) else: source = str(self) try: - compile(source+'\n', "x", "exec") + #compile(source+'\n', "x", "exec") + syntax_checker(source+'\n') except SyntaxError: return False else: From commits-noreply at bitbucket.org Sun Sep 6 17:10:10 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sun, 6 Sep 2009 15:10:10 +0000 (UTC) Subject: [py-svn] py-trunk commit b4b8bc6f1076: move test files out of py lib proper Message-ID: <20090906151010.E440A7110A@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252249179 -7200 # Node ID b4b8bc6f107612f700a4585b7a9a7ebde7895871 # Parent 4ffc38abb51a2f09dcdfabe07ff8bb382caaf209 move test files out of py lib proper * separate all tests from plugins * simplify implicit inclusion of plugins under test * have test_initpkg perform direct checks instead of yielding tests * fix example tests for 3k --- a/py/_testing/test_oldmagic.py +++ /dev/null @@ -1,174 +0,0 @@ -import py -import sys, os - -def check_assertion(): - excinfo = py.test.raises(AssertionError, "assert 1 == 2") - s = excinfo.exconly(tryshort=True) - if not s == "assert 1 == 2": - raise ValueError("assertion not enabled: got %s" % s) - -def test_invoke_assertion(recwarn, monkeypatch): - monkeypatch.setattr(py.builtin.builtins, 'AssertionError', None) - py.magic.invoke(assertion=True) - try: - check_assertion() - finally: - py.magic.revoke(assertion=True) - recwarn.pop(DeprecationWarning) - -def test_invoke_compile(recwarn, monkeypatch): - monkeypatch.setattr(py.builtin.builtins, 'compile', None) - py.magic.invoke(compile=True) - try: - co = compile("""if 1: - def f(): - return 1 - \n""", '', 'exec') - d = {} - py.builtin.exec_(co, d) - assert py.code.Source(d['f']) - finally: - py.magic.revoke(compile=True) - recwarn.pop(DeprecationWarning) - -def test_patch_revert(recwarn): - class a: - pass - py.test.raises(AttributeError, "py.magic.patch(a, 'i', 42)") - - a.i = 42 - py.magic.patch(a, 'i', 23) - assert a.i == 23 - recwarn.pop(DeprecationWarning) - py.magic.revert(a, 'i') - assert a.i == 42 - recwarn.pop(DeprecationWarning) - -def test_double_patch(recwarn): - class a: - i = 42 - assert py.magic.patch(a, 'i', 2) == 42 - recwarn.pop(DeprecationWarning) - assert py.magic.patch(a, 'i', 3) == 2 - assert a.i == 3 - assert py.magic.revert(a, 'i') == 3 - recwarn.pop(DeprecationWarning) - assert a.i == 2 - assert py.magic.revert(a, 'i') == 2 - assert a.i == 42 - -def test_valueerror(recwarn): - class a: - i = 2 - pass - py.test.raises(ValueError, "py.magic.revert(a, 'i')") - recwarn.pop(DeprecationWarning) - -def test_AssertionError(testdir): - testdir.makepyfile(""" - import py - def test_hello(recwarn): - err = py.magic.AssertionError - recwarn.pop(DeprecationWarning) - assert err is py.code._AssertionError - """) - result = testdir.runpytest() - assert "1 passed" in result.stdout.str() - -def test_autopath_deprecation(testdir): - testdir.makepyfile(""" - import py - def test_hello(recwarn): - p = py.magic.autopath() - recwarn.pop(DeprecationWarning) - assert py.path.local(__file__).dirpath() == p.dirpath() - """) - result = testdir.runpytest() - assert "1 passed" in result.stdout.str() - -class Testautopath: - getauto = "from py.magic import autopath ; autopath = autopath()" - def setup_class(cls): - cls.root = py.test.ensuretemp(cls.__name__) - cls.initdir = cls.root.ensure('pkgdir', dir=1) - cls.initdir.ensure('__init__.py') - cls.initdir2 = cls.initdir.ensure('initdir2', dir=1) - cls.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: - py.builtin.exec_(self.getauto, d) - conf = d['autopath'] - assert conf.dirpath() == self.initdir2 - assert conf.pkgdir == self.initdir - assert str(self.root) in sys.path - py.builtin.exec_(self.getauto, 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: - py.builtin.exec_(self.getauto, d) - conf = d['autopath'] - assert conf == self.initdir2.join('autoconfiguretest.py') - assert conf.pkgdir == self.initdir - assert str(self.root) in sys.path - py.builtin.exec_(self.getauto, 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: - py.builtin.exec_(self.getauto, d) - conf = d['autopath'] - assert conf.dirpath() == self.root - assert conf.pkgdir == self.root - syspath = sys.path[:] - assert str(self.root) in syspath - py.builtin.exec_(self.getauto, 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 = {} - py.builtin.exec_(self.getauto, 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 = {} - py.builtin.exec_(self.getauto, d) - ''') - finally: - sys.path[:] = oldsyspath - sys.argv = sys.argv --- a/py/cmdline/testing/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/_testing/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/execnet/testing/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/log/testing/test_warning.py +++ /dev/null @@ -1,66 +0,0 @@ -import py -mypath = py.path.local(__file__).new(ext=".py") - -def test_forwarding_to_warnings_module(): - py.test.deprecated_call(py.log._apiwarn, "1.3", "..") - -def test_apiwarn_functional(): - capture = py.io.StdCapture() - py.log._apiwarn("x.y.z", "something") - out, err = capture.reset() - py.builtin.print_("out", out) - py.builtin.print_("err", err) - assert err.find("x.y.z") != -1 - lno = py.code.getrawcode(test_apiwarn_functional).co_firstlineno + 2 - exp = "%s:%s" % (mypath, lno) - assert err.find(exp) != -1 - -def test_stacklevel(): - def f(): - py.log._apiwarn("x", "some", stacklevel=2) - # 3 - # 4 - capture = py.io.StdCapture() - f() - out, err = capture.reset() - lno = py.code.getrawcode(test_stacklevel).co_firstlineno + 6 - warning = str(err) - assert warning.find(":%s" % lno) != -1 - -def test_stacklevel_initpkg_with_resolve(testdir): - mod = testdir.makepyfile(initpkg=""" - import py - def __getattr__(): - f() - def f(): - py.log._apiwarn("x", "some", stacklevel="initpkg") - """).pyimport() - capture = py.io.StdCapture() - mod.__getattr__() - out, err = capture.reset() - lno = py.code.getrawcode(test_stacklevel_initpkg_with_resolve).co_firstlineno + 9 - warning = str(err) - assert warning.find(":%s" % lno) != -1 - -def test_stacklevel_initpkg_no_resolve(): - def f(): - py.log._apiwarn("x", "some", stacklevel="initpkg") - capture = py.io.StdCapture() - f() - out, err = capture.reset() - lno = py.code.getrawcode(test_stacklevel_initpkg_no_resolve).co_firstlineno + 2 - warning = str(err) - assert warning.find(":%s" % lno) != -1 - - -def test_function(): - capture = py.io.StdCapture() - py.log._apiwarn("x.y.z", "something", function=test_function) - out, err = capture.reset() - py.builtin.print_("out", out) - py.builtin.print_("err", err) - assert err.find("x.y.z") != -1 - lno = py.code.getrawcode(test_function).co_firstlineno - exp = "%s:%s" % (mypath, lno) - assert err.find(exp) != -1 - --- a/py/log/testing/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/log/testing/test_log.py +++ /dev/null @@ -1,191 +0,0 @@ -import py -import sys - -from py.__.log.log import default_keywordmapper - -callcapture = py.io.StdCapture.call - -def setup_module(mod): - mod.tempdir = py.test.ensuretemp("py.log-test") - mod._oldstate = default_keywordmapper.getstate() - -def teardown_module(mod): - default_keywordmapper.setstate(mod._oldstate) - -class TestLogProducer: - def setup_method(self, meth): - default_keywordmapper.setstate(_oldstate) - - def test_getstate_setstate(self): - state = py.log._getstate() - py.log.setconsumer("hello", [].append) - state2 = py.log._getstate() - assert state2 != state - py.log._setstate(state) - state3 = py.log._getstate() - assert state3 == state - - def test_producer_repr(self): - d = py.log.Producer("default") - assert repr(d).find('default') != -1 - - def test_produce_one_keyword(self): - l = [] - py.log.setconsumer('s1', l.append) - py.log.Producer('s1')("hello world") - assert len(l) == 1 - msg = l[0] - assert msg.content().startswith('hello world') - assert msg.prefix() == '[s1] ' - assert str(msg) == "[s1] hello world" - - def test_producer_class(self): - p = py.log.Producer('x1') - l = [] - py.log.setconsumer(p._keywords, l.append) - p("hello") - assert len(l) == 1 - assert len(l[0].keywords) == 1 - assert 'x1' == l[0].keywords[0] - - def test_producer_caching(self): - p = py.log.Producer('x1') - x2 = p.x2 - assert x2 is p.x2 - -class TestLogConsumer: - def setup_method(self, meth): - default_keywordmapper.setstate(_oldstate) - def test_log_none(self): - log = py.log.Producer("XXX") - l = [] - py.log.setconsumer('XXX', l.append) - log("1") - assert l - l[:] = [] - py.log.setconsumer('XXX', None) - log("2") - assert not l - - def test_log_default_stderr(self): - res, out, err = callcapture(py.log.Producer("default"), "hello") - assert err.strip() == "[default] hello" - - def test_simple_consumer_match(self): - l = [] - py.log.setconsumer("x1", l.append) - p = py.log.Producer("x1 x2") - p("hello") - assert l - assert l[0].content() == "hello" - - def test_simple_consumer_match_2(self): - l = [] - p = py.log.Producer("x1 x2") - py.log.setconsumer(p._keywords, l.append) - p("42") - assert l - assert l[0].content() == "42" - - def test_no_auto_producer(self): - p = py.log.Producer('x') - py.test.raises(AttributeError, "p._x") - py.test.raises(AttributeError, "p.x_y") - - def test_setconsumer_with_producer(self): - l = [] - p = py.log.Producer("hello") - py.log.setconsumer(p, l.append) - p("world") - assert str(l[0]) == "[hello] world" - - def test_multi_consumer(self): - l = [] - py.log.setconsumer("x1", l.append) - py.log.setconsumer("x1 x2", None) - p = py.log.Producer("x1 x2") - p("hello") - assert not l - py.log.Producer("x1")("hello") - assert l - assert l[0].content() == "hello" - - def test_log_stderr(self): - py.log.setconsumer("xyz", py.log.STDOUT) - res, out, err = callcapture(py.log.Producer("xyz"), "hello") - assert not err - assert out.strip() == '[xyz] hello' - - def test_log_file(self): - customlog = tempdir.join('log.out') - py.log.setconsumer("default", open(str(customlog), 'w', buffering=1)) - py.log.Producer("default")("hello world #1") - assert customlog.readlines() == ['[default] hello world #1\n'] - - py.log.setconsumer("default", py.log.Path(customlog, buffering=False)) - py.log.Producer("default")("hello world #2") - res = customlog.readlines() - assert res == ['[default] hello world #2\n'] # no append by default! - - def test_log_file_append_mode(self): - logfilefn = tempdir.join('log_append.out') - - # The append mode is on by default, so we don't need to specify it for File - py.log.setconsumer("default", py.log.Path(logfilefn, append=True, - buffering=0)) - assert logfilefn.check() - py.log.Producer("default")("hello world #1") - lines = logfilefn.readlines() - assert lines == ['[default] hello world #1\n'] - py.log.setconsumer("default", py.log.Path(logfilefn, append=True, - buffering=0)) - py.log.Producer("default")("hello world #1") - lines = logfilefn.readlines() - assert lines == ['[default] hello world #1\n', - '[default] hello world #1\n'] - - def test_log_file_delayed_create(self): - logfilefn = tempdir.join('log_create.out') - - py.log.setconsumer("default", py.log.Path(logfilefn, - delayed_create=True, buffering=0)) - assert not logfilefn.check() - py.log.Producer("default")("hello world #1") - lines = logfilefn.readlines() - assert lines == ['[default] hello world #1\n'] - - def test_keyword_based_log_files(self): - logfiles = [] - keywords = 'k1 k2 k3'.split() - for key in keywords: - path = tempdir.join(key) - py.log.setconsumer(key, py.log.Path(path, buffering=0)) - - py.log.Producer('k1')('1') - py.log.Producer('k2')('2') - py.log.Producer('k3')('3') - - for key in keywords: - path = tempdir.join(key) - assert path.read().strip() == '[%s] %s' % (key, key[-1]) - - # disabled for now; the syslog log file can usually be read only by root - # I manually inspected /var/log/messages and the entries were there - def no_test_log_syslog(self): - py.log.setconsumer("default", py.log.Syslog()) - py.log.default("hello world #1") - - # disabled for now until I figure out how to read entries in the - # Event Logs on Windows - # I manually inspected the Application Log and the entries were there - def no_test_log_winevent(self): - py.log.setconsumer("default", py.log.WinEvent()) - py.log.default("hello world #1") - - # disabled for now until I figure out how to properly pass the parameters - def no_test_log_email(self): - py.log.setconsumer("default", py.log.Email(mailhost="gheorghiu.net", - fromaddr="grig", - toaddrs="grig", - subject = "py.log email")) - py.log.default("hello world #1") --- a/py/execnet/testing/test_basics.py +++ /dev/null @@ -1,215 +0,0 @@ - -import py -import sys, os, subprocess, inspect -from py.__.execnet import gateway_base, gateway -from py.__.execnet.gateway_base import Message, Channel, ChannelFactory - -def test_subprocess_interaction(anypython): - line = gateway.popen_bootstrapline - compile(line, 'xyz', 'exec') - args = [str(anypython), '-c', line] - popen = subprocess.Popen(args, bufsize=0, stderr=subprocess.STDOUT, - stdin=subprocess.PIPE, stdout=subprocess.PIPE) - def send(line): - popen.stdin.write(line.encode('ascii')) - if sys.version_info > (3,0): # 3k still buffers - popen.stdin.flush() - def receive(): - return popen.stdout.readline().decode('ascii') - - try: - source = py.code.Source(read_write_loop, "read_write_loop()") - repr_source = repr(str(source)) + "\n" - sendline = repr_source - send(sendline) - s = receive() - assert s == "ok\n" - send("hello\n") - s = receive() - assert s == "received: hello\n" - send("world\n") - s = receive() - assert s == "received: world\n" - finally: - popen.stdin.close() - popen.stdout.close() - popen.wait() - -def read_write_loop(): - import os, sys - sys.stdout.write("ok\n") - sys.stdout.flush() - while 1: - try: - line = sys.stdin.readline() - sys.stdout.write("received: %s" % line) - sys.stdout.flush() - except (IOError, EOFError): - break - -def pytest_generate_tests(metafunc): - if 'anypython' in metafunc.funcargnames: - for name in 'python3.1', 'python2.4', 'python2.5', 'python2.6': - metafunc.addcall(id=name, param=name) - -def pytest_funcarg__anypython(request): - name = request.param - executable = py.path.local.sysfind(name) - if executable is None: - py.test.skip("no %s found" % (name,)) - return executable - -def test_io_message(anypython, tmpdir): - check = tmpdir.join("check.py") - check.write(py.code.Source(gateway_base, """ - try: - from io import BytesIO - except ImportError: - from StringIO import StringIO as BytesIO - import tempfile - temp_out = BytesIO() - temp_in = BytesIO() - io = Popen2IO(temp_out, temp_in) - for i, msg_cls in Message._types.items(): - print ("checking %s %s" %(i, msg_cls)) - for data in "hello", "hello".encode('ascii'): - msg1 = msg_cls(i, data) - msg1.writeto(io) - x = io.outfile.getvalue() - io.outfile.truncate(0) - io.outfile.seek(0) - io.infile.seek(0) - io.infile.write(x) - io.infile.seek(0) - msg2 = Message.readfrom(io) - assert msg1.channelid == msg2.channelid, (msg1, msg2) - assert msg1.data == msg2.data - print ("all passed") - """)) - #out = py.process.cmdexec("%s %s" %(executable,check)) - out = anypython.sysexec(check) - print (out) - assert "all passed" in out - -def test_popen_io(anypython, tmpdir): - check = tmpdir.join("check.py") - check.write(py.code.Source(gateway_base, """ - do_exec(Popen2IO.server_stmt, globals()) - io.write("hello".encode('ascii')) - s = io.read(1) - assert s == "x".encode('ascii') - """)) - from subprocess import Popen, PIPE - args = [str(anypython), str(check)] - proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) - proc.stdin.write("x".encode('ascii')) - stdout, stderr = proc.communicate() - print (stderr) - ret = proc.wait() - assert "hello".encode('ascii') in stdout - - -def test_rinfo_source(anypython, tmpdir): - check = tmpdir.join("check.py") - check.write(py.code.Source(""" - class Channel: - def send(self, data): - assert eval(repr(data), {}) == data - channel = Channel() - """, gateway.rinfo_source, """ - print ('all passed') - """)) - out = anypython.sysexec(check) - print (out) - assert "all passed" in out - -def test_geterrortext(anypython, tmpdir): - check = tmpdir.join("check.py") - check.write(py.code.Source(gateway_base, """ - class Arg: - pass - errortext = geterrortext((Arg, "1", 4)) - assert "Arg" in errortext - import sys - try: - raise ValueError("17") - except ValueError: - excinfo = sys.exc_info() - s = geterrortext(excinfo) - assert "17" in s - print ("all passed") - """)) - out = anypython.sysexec(check) - print (out) - assert "all passed" in out - -def test_getsource_import_modules(): - for dottedname in gateway.startup_modules: - yield gateway.getsource, dottedname - -def test_getsource_no_colision(): - seen = {} - for dottedname in gateway.startup_modules: - mod = __import__(dottedname, None, None, ['__doc__']) - for name, value in vars(mod).items(): - if py.std.inspect.isclass(value): - if name in seen: - olddottedname, oldval = seen[name] - if oldval is not value: - py.test.fail("duplicate class %r in %s and %s" % - (name, dottedname, olddottedname)) - seen[name] = (dottedname, value) - -def test_stdouterrin_setnull(): - cap = py.io.StdCaptureFD() - from py.__.execnet.gateway import stdouterrin_setnull - stdouterrin_setnull() - import os - os.write(1, "hello".encode('ascii')) - if os.name == "nt": - os.write(2, "world") - os.read(0, 1) - out, err = cap.reset() - assert not out - assert not err - - -class TestMessage: - def test_wire_protocol(self): - for cls in Message._types.values(): - one = py.io.BytesIO() - data = '23'.encode('ascii') - cls(42, data).writeto(one) - two = py.io.BytesIO(one.getvalue()) - msg = Message.readfrom(two) - assert isinstance(msg, cls) - assert msg.channelid == 42 - assert msg.data == data - assert isinstance(repr(msg), str) - # == "" %(msg.__class__.__name__, ) - -class TestPureChannel: - def setup_method(self, method): - self.fac = 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._channels[chan1.id] == chan1 - chan2 = self.fac.new() - assert self.fac._channels[chan2.id] == chan2 - - def test_channel_timeouterror(self): - channel = self.fac.new() - py.test.raises(IOError, channel.waitclose, timeout=0.01) - - def test_channel_makefile_incompatmode(self): - channel = self.fac.new() - py.test.raises(ValueError, 'channel.makefile("rw")') - - --- a/py/_testing/test_com.py +++ /dev/null @@ -1,193 +0,0 @@ - -import py -import os -from py.__._com import Registry, MultiCall, HookRelay, varnames - -def test_varnames(): - def f(x): - pass - class A: - def f(self, y): - pass - assert varnames(f) == ("x",) - assert varnames(A().f) == ('y',) - -class TestMultiCall: - def test_uses_copy_of_methods(self): - l = [lambda: 42] - mc = MultiCall(l, {}) - repr(mc) - l[:] = [] - res = mc.execute() - return res == 42 - - def test_call_passing(self): - class P1: - def m(self, __multicall__, x): - assert len(__multicall__.results) == 1 - assert not __multicall__.methods - return 17 - - class P2: - def m(self, __multicall__, x): - assert __multicall__.results == [] - assert __multicall__.methods - return 23 - - p1 = P1() - p2 = P2() - multicall = MultiCall([p1.m, p2.m], {'x': 23}) - assert "23" in repr(multicall) - reslist = multicall.execute() - assert len(reslist) == 2 - # ensure reversed order - assert reslist == [23, 17] - - def test_keyword_args(self): - def f(x): - return x + 1 - class A: - def f(self, x, y): - return x + y - multicall = MultiCall([f, A().f], dict(x=23, y=24)) - assert "'x': 23" in repr(multicall) - assert "'y': 24" in repr(multicall) - reslist = multicall.execute() - assert reslist == [24+23, 24] - assert "2 results" in repr(multicall) - - def test_keywords_call_error(self): - multicall = MultiCall([lambda x: x], {}) - py.test.raises(TypeError, "multicall.execute()") - - def test_call_subexecute(self): - def m(__multicall__): - subresult = __multicall__.execute() - return subresult + 1 - - def n(): - return 1 - - call = MultiCall([n, m], {}, firstresult=True) - res = call.execute() - assert res == 2 - - def test_call_none_is_no_result(self): - def m1(): - return 1 - def m2(): - return None - res = MultiCall([m1, m2], {}, firstresult=True).execute() - assert res == 1 - res = MultiCall([m1, m2], {}).execute() - assert res == [1] - -class TestRegistry: - - def test_register(self): - registry = Registry() - class MyPlugin: - pass - my = MyPlugin() - registry.register(my) - assert list(registry) == [my] - my2 = MyPlugin() - registry.register(my2) - assert list(registry) == [my, my2] - - assert registry.isregistered(my) - assert registry.isregistered(my2) - registry.unregister(my) - assert not registry.isregistered(my) - assert list(registry) == [my2] - - def test_listattr(self): - plugins = Registry() - class api1: - x = 41 - class api2: - x = 42 - class api3: - x = 43 - plugins.register(api1()) - plugins.register(api2()) - plugins.register(api3()) - l = list(plugins.listattr('x')) - assert l == [41, 42, 43] - l = list(plugins.listattr('x', reverse=True)) - assert l == [43, 42, 41] - - class api4: - x = 44 - l = list(plugins.listattr('x', extra=(api4,))) - assert l == [41,42,43,44] - assert len(list(plugins)) == 3 # otherwise extra added - -def test_api_and_defaults(): - assert isinstance(py._com.comregistry, Registry) - -class TestHookRelay: - def test_happypath(self): - registry = Registry() - class Api: - def hello(self, arg): - pass - - mcm = HookRelay(hookspecs=Api, registry=registry) - assert hasattr(mcm, 'hello') - assert repr(mcm.hello).find("hello") != -1 - class Plugin: - def hello(self, arg): - return arg + 1 - registry.register(Plugin()) - l = mcm.hello(arg=3) - assert l == [4] - assert not hasattr(mcm, 'world') - - def test_only_kwargs(self): - registry = Registry() - class Api: - def hello(self, arg): - pass - mcm = HookRelay(hookspecs=Api, registry=registry) - py.test.raises(TypeError, "mcm.hello(3)") - - def test_firstresult_definition(self): - registry = Registry() - class Api: - def hello(self, arg): pass - hello.firstresult = True - - mcm = HookRelay(hookspecs=Api, registry=registry) - class Plugin: - def hello(self, arg): - return arg + 1 - registry.register(Plugin()) - res = mcm.hello(arg=3) - assert res == 4 - - def test_default_plugins(self): - class Api: pass - mcm = HookRelay(hookspecs=Api, registry=py._com.comregistry) - assert mcm._registry == py._com.comregistry - - def test_hooks_extra_plugins(self): - registry = Registry() - class Api: - def hello(self, arg): - pass - hookrelay = HookRelay(hookspecs=Api, registry=registry) - hook_hello = hookrelay.hello - class Plugin: - def hello(self, arg): - return arg + 1 - registry.register(Plugin()) - class Plugin2: - def hello(self, arg): - return arg + 2 - newhook = hookrelay._makecall("hello", extralookup=Plugin2()) - l = newhook(arg=3) - assert l == [5, 4] - l2 = hook_hello(arg=3) - assert l2 == [4] - --- a/py/code/testing/test_code.py +++ /dev/null @@ -1,188 +0,0 @@ -from __future__ import generators -import py -import sys -from py.__.code.code import safe_repr - -def test_newcode(): - source = "i = 3" - co = compile(source, '', 'exec') - code = py.code.Code(co) - newco = code.new() - assert co == newco - -def test_ne(): - code1 = py.code.Code(compile('foo = "bar"', '', 'exec')) - assert code1 == code1 - code2 = py.code.Code(compile('foo = "baz"', '', 'exec')) - assert code2 != code1 - -def test_newcode_unknown_args(): - code = py.code.Code(compile("", '', 'exec')) - py.test.raises(TypeError, 'code.new(filename="hello")') - -def test_newcode_withfilename(): - source = py.code.Source(""" - def f(): - def g(): - pass - """) - co = compile(str(source)+'\n', 'nada', 'exec') - obj = 'hello' - newco = py.code.Code(co).new(rec=True, co_filename=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 - -def test_newcode_with_filename(): - source = "i = 3" - co = compile(source, '', 'exec') - code = py.code.Code(co) - class MyStr(str): - pass - filename = MyStr("hello") - filename.__source__ = py.code.Source(source) - newco = code.new(rec=True, co_filename=filename) - assert newco.co_filename is filename - s = py.code.Source(newco) - assert str(s) == source - - -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) - args = [ - 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 - ] - if sys.version_info > (3,0): - args.insert(1, co.co_kwonlyargcount) - c2 = py.std.types.CodeType(*args) - assert c2.co_filename is filename - -def test_code_gives_back_name_for_not_existing_file(): - name = 'abc-123' - co_code = compile("pass\n", name, 'exec') - assert co_code.co_filename == name - code = py.code.Code(co_code) - assert str(code.path) == name - assert code.fullsource is None - -def test_code_with_class(): - class A: - pass - py.test.raises(TypeError, "py.code.Code(A)") - -if True: - def x(): - pass - -def test_code_fullsource(): - code = py.code.Code(x) - full = code.fullsource - assert 'test_code_fullsource()' in str(full) - -def test_code_source(): - code = py.code.Code(x) - src = code.source() - expected = """def x(): - pass""" - assert str(src) == expected - -def test_frame_getsourcelineno_myself(): - def func(): - return sys._getframe(0) - f = func() - f = py.code.Frame(f) - source, lineno = f.code.fullsource, f.lineno - assert source[lineno].startswith(" return sys._getframe(0)") - -def test_getstatement_empty_fullsource(): - def func(): - return sys._getframe(0) - f = func() - f = py.code.Frame(f) - prop = f.code.__class__.fullsource - try: - f.code.__class__.fullsource = None - assert f.statement == py.code.Source("") - finally: - f.code.__class__.fullsource = prop - -def test_code_from_func(): - co = py.code.Code(test_frame_getsourcelineno_myself) - assert co.firstlineno - assert co.path - - - -class TestSafeRepr: - def test_simple_repr(self): - assert safe_repr(1) == '1' - assert safe_repr(None) == 'None' - - def test_exceptions(self): - class BrokenRepr: - def __init__(self, ex): - self.ex = ex - foo = 0 - def __repr__(self): - raise self.ex - class BrokenReprException(Exception): - __str__ = None - __repr__ = None - assert 'Exception' in safe_repr(BrokenRepr(Exception("broken"))) - s = safe_repr(BrokenReprException("really broken")) - assert 'TypeError' in s - if py.std.sys.version_info < (2,6): - assert 'unknown' in safe_repr(BrokenRepr("string")) - else: - assert 'TypeError' in safe_repr(BrokenRepr("string")) - - def test_big_repr(self): - from py.__.code.code import SafeRepr - assert len(safe_repr(range(1000))) <= \ - len('[' + SafeRepr().maxlist * "1000" + ']') - - def test_repr_on_newstyle(self): - class Function(object): - def __repr__(self): - return "<%s>" %(self.name) - try: - s = safe_repr(Function()) - except Exception: - py.test.fail("saferepr failed for newstyle class") - -def test_builtin_patch_unpatch(monkeypatch): - cpy_builtin = py.builtin.builtins - comp = cpy_builtin.compile - def mycompile(*args, **kwargs): - return comp(*args, **kwargs) - class Sub(AssertionError): - pass - monkeypatch.setattr(cpy_builtin, 'AssertionError', Sub) - monkeypatch.setattr(cpy_builtin, 'compile', mycompile) - py.code.patch_builtins() - assert cpy_builtin.AssertionError != Sub - assert cpy_builtin.compile != mycompile - py.code.unpatch_builtins() - assert cpy_builtin.AssertionError is Sub - assert cpy_builtin.compile == mycompile - --- a/py/path/testing/test_local.py +++ /dev/null @@ -1,558 +0,0 @@ -import py -import sys -from py.path import local -from py.__.path.testing import common - -def pytest_funcarg__path1(request): - def setup(): - path1 = request.config.mktemp("path1") - common.setuptestfs(path1) - return path1 - def teardown(path1): - # post check - assert path1.join("samplefile").check() - return request.cached_setup(setup, teardown, scope="session") - -def pytest_funcarg__tmpdir(request): - basedir = request.config.getbasetemp() - if request.cls: - try: - basedir = basedir.mkdir(request.cls.__name__) - except py.error.EEXIST: - pass - for i in range(1000): - name = request.function.__name__ - if i > 0: - name += str(i) - try: - return basedir.mkdir(name) - except py.error.EEXIST: - continue - raise ValueError("could not create tempdir") - -class TestLocalPath(common.CommonFSTests): - def test_join_normpath(self, tmpdir): - assert tmpdir.join(".") == tmpdir - p = tmpdir.join("../%s" % tmpdir.basename) - assert p == tmpdir - p = tmpdir.join("..//%s/" % tmpdir.basename) - assert p == tmpdir - - def test_gethash(self, tmpdir): - md5 = py.builtin._tryimport('md5', 'hashlib').md5 - lib = py.builtin._tryimport('sha', 'hashlib') - sha = getattr(lib, 'sha1', getattr(lib, 'sha', None)) - fn = tmpdir.join("testhashfile") - data = 'hello'.encode('ascii') - fn.write(data, mode="wb") - assert fn.computehash("md5") == md5(data).hexdigest() - assert fn.computehash("sha1") == sha(data).hexdigest() - py.test.raises(ValueError, fn.computehash, "asdasd") - - def test_remove_removes_readonly_file(self, tmpdir): - readonly_file = tmpdir.join('readonly').ensure() - readonly_file.chmod(0) - readonly_file.remove() - assert not readonly_file.check(exists=1) - - def test_remove_removes_readonly_dir(self, tmpdir): - readonly_dir = tmpdir.join('readonlydir').ensure(dir=1) - readonly_dir.chmod(int("500", 8)) - readonly_dir.remove() - assert not readonly_dir.check(exists=1) - - def test_remove_removes_dir_and_readonly_file(self, tmpdir): - readonly_dir = tmpdir.join('readonlydir').ensure(dir=1) - readonly_file = readonly_dir.join('readonlyfile').ensure() - readonly_file.chmod(0) - readonly_dir.remove() - assert not readonly_dir.check(exists=1) - - def test_initialize_curdir(self): - assert str(local()) == py.std.os.getcwd() - - def test_initialize_reldir(self, path1): - old = path1.chdir() - try: - p = local('samplefile') - assert p.check() - finally: - old.chdir() - - def test_eq_with_strings(self, path1): - path1 = path1.join('sampledir') - path2 = str(path1) - assert path1 == path2 - assert path2 == path1 - path3 = path1.join('samplefile') - assert path3 != path2 - assert path2 != path3 - - @py.test.mark.multi(bin=(False, True)) - def test_dump(self, tmpdir, bin): - path = tmpdir.join("dumpfile%s" % int(bin)) - try: - d = {'answer' : 42} - path.dump(d, bin=bin) - f = path.open('rb+') - dnew = py.std.pickle.load(f) - assert d == dnew - finally: - f.close() - - 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, path1): - new1 = path1.join("/otherdir") - new2 = path1.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): - 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): - newfile = tmpdir.join('test1','test') - newfile.ensure() - assert newfile.check(file=1) - newfile.write("42") - newfile.ensure() - s = newfile.read() - assert s == "42" - - def test_ensure_filepath_withoutdir(self, tmpdir): - newfile = tmpdir.join('test1file') - t = newfile.ensure() - assert t == newfile - assert newfile.check(file=1) - - def test_ensure_dirpath(self, tmpdir): - newfile = tmpdir.join('test1','testfile') - t = newfile.ensure(dir=1) - assert t == newfile - assert newfile.check(dir=1) - - def test_init_from_path(self, tmpdir): - l = local() - l2 = local(l) - assert l2 is l - - wc = py.path.svnwc('.') - l3 = local(wc) - assert l3 is not wc - assert l3.strpath == wc.strpath - assert not hasattr(l3, 'commit') - - def test_long_filenames(self, tmpdir): - if sys.platform == "win32": - py.test.skip("win32: work around needed for path length limit") - # see http://codespeak.net/pipermail/py-dev/2008q2/000922.html - - # testing paths > 260 chars (which is Windows' limitation, but - # depending on how the paths are used), but > 4096 (which is the - # Linux' limitation) - the behaviour of paths with names > 4096 chars - # is undetermined - newfilename = '/test' * 60 - l = tmpdir.join(newfilename) - l.ensure(file=True) - l.write('foo') - l2 = tmpdir.join(newfilename) - assert l2.read() == 'foo' - -class TestExecutionOnWindows: - disabled = py.std.sys.platform != 'win32' - - def test_sysfind(self): - x = py.path.local.sysfind('cmd') - assert x.check(file=1) - assert py.path.local.sysfind('jaksdkasldqwe') is None - -class TestExecution: - disabled = py.std.sys.platform == 'win32' - - def test_sysfind(self): - x = py.path.local.sysfind('test') - assert x.check(file=1) - assert py.path.local.sysfind('jaksdkasldqwe') is None - - def test_sysfind_no_permisson_ignored(self, monkeypatch, tmpdir): - noperm = tmpdir.ensure('noperm', dir=True) - monkeypatch.setenv("PATH", noperm, prepend=":") - noperm.chmod(0) - assert py.path.local.sysfind('jaksdkasldqwe') is None - - def test_sysfind_absolute(self): - x = py.path.local.sysfind('test') - assert x.check(file=1) - y = py.path.local.sysfind(str(x)) - assert y.check(file=1) - assert y == x - - def test_sysfind_multiple(self, tmpdir, monkeypatch): - monkeypatch.setenv('PATH', - "%s:%s" % (tmpdir.ensure('a'), - tmpdir.join('b')), - prepend=":") - tmpdir.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 - assert py.path.local.sysfind('a', checker=checker) is None - - def test_sysexec(self): - x = py.path.local.sysfind('ls') - out = x.sysexec('-a') - for x in py.path.local().listdir(): - assert out.find(x.basename) != -1 - - def test_sysexec_failing(self): - x = py.path.local.sysfind('false') - py.test.raises(py.process.cmdexec.Error, """ - x.sysexec('aksjdkasjd') - """) - - def test_make_numbered_dir(self, tmpdir): - tmpdir.ensure('base.not_an_int', dir=1) - for i in range(10): - numdir = local.make_numbered_dir(prefix='base.', rootdir=tmpdir, - keep=2, lock_timeout=0) - 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_locked_make_numbered_dir(self, tmpdir): - for i in range(10): - numdir = local.make_numbered_dir(prefix='base2.', rootdir=tmpdir, - keep=2) - assert numdir.check() - assert numdir.basename == 'base2.%d' %i - for j in range(i): - assert numdir.new(ext=str(j)).check() - - def test_error_preservation(self, path1): - py.test.raises (EnvironmentError, path1.join('qwoeqiwe').mtime) - py.test.raises (EnvironmentError, path1.join('qwoeqiwe').read) - - #def test_parentdirmatch(self): - # local.parentdirmatch('std', startmodule=__name__) - # - - -class TestImport: - def test_pyimport(self, path1): - obj = path1.join('execfile.py').pyimport() - assert obj.x == 42 - assert obj.__name__ == 'execfile' - - def test_pyimport_execfile_different_name(self, path1): - obj = path1.join('execfile.py').pyimport(modname="0x.y.z") - assert obj.x == 42 - assert obj.__name__ == '0x.y.z' - - def test_pyimport_a(self, path1): - otherdir = path1.join('otherdir') - mod = otherdir.join('a.py').pyimport() - assert mod.result == "got it" - assert mod.__name__ == 'otherdir.a' - - def test_pyimport_b(self, path1): - otherdir = path1.join('otherdir') - mod = otherdir.join('b.py').pyimport() - assert mod.stuff == "got it" - assert mod.__name__ == 'otherdir.b' - - def test_pyimport_c(self, path1): - otherdir = path1.join('otherdir') - mod = otherdir.join('c.py').pyimport() - assert mod.value == "got it" - - def test_pyimport_d(self, path1): - otherdir = path1.join('otherdir') - mod = otherdir.join('d.py').pyimport() - assert mod.value2 == "got it" - - def test_pyimport_and_import(self, tmpdir): - tmpdir.ensure('xxxpackage', '__init__.py') - mod1path = tmpdir.ensure('xxxpackage', 'module1.py') - mod1 = mod1path.pyimport() - assert mod1.__name__ == 'xxxpackage.module1' - from xxxpackage import module1 - assert module1 is mod1 - -def test_pypkgdir(tmpdir): - pkg = tmpdir.ensure('pkg1', dir=1) - pkg.ensure("__init__.py") - pkg.ensure("subdir/__init__.py") - assert pkg.pypkgpath() == pkg - assert pkg.join('subdir', '__init__.py').pypkgpath() == pkg - -def test_homedir(): - homedir = py.path.local._gethomedir() - assert homedir.check(dir=1) - -class TestWINLocalPath: - #root = local(TestLocalPath.root) - disabled = py.std.sys.platform != 'win32' - - def test_owner_group_not_implemented(self): - py.test.raises(NotImplementedError, "path1.stat().owner") - py.test.raises(NotImplementedError, "path1.stat().group") - - def test_chmod_simple_int(self): - py.builtin.print_("path1 is", path1) - mode = path1.stat().mode - # Ensure that we actually change the mode to something different. - path1.chmod(mode == 0 and 1 or 0) - try: - print(path1.stat().mode) - print(mode) - assert path1.stat().mode != mode - finally: - path1.chmod(mode) - assert path1.stat().mode == mode - - def test_path_comparison_lowercase_mixed(self): - t1 = path1.join("a_path") - t2 = path1.join("A_path") - assert t1 == t1 - assert t1 == t2 - - def test_relto_with_mixed_case(self): - t1 = path1.join("a_path", "fiLe") - t2 = path1.join("A_path") - assert t1.relto(t2) == "fiLe" - - def test_allow_unix_style_paths(self): - t1 = path1.join('a_path') - assert t1 == str(path1) + '\\a_path' - t1 = path1.join('a_path/') - assert t1 == str(path1) + '\\a_path' - t1 = path1.join('dir/a_path') - assert t1 == str(path1) + '\\dir\\a_path' - - def test_sysfind_in_currentdir(self): - cmd = py.path.local.sysfind('cmd') - root = cmd.new(dirname='', basename='') # c:\ in most installations - old = root.chdir() - try: - x = py.path.local.sysfind(cmd.relto(root)) - assert x.check(file=1) - finally: - old.chdir() - -class TestPOSIXLocalPath: - disabled = py.std.sys.platform == 'win32' - - def test_samefile(self, tmpdir): - assert tmpdir.samefile(tmpdir) - p = tmpdir.ensure("hello") - assert p.samefile(p) - - def test_hardlink(self, tmpdir): - linkpath = tmpdir.join('test') - filepath = tmpdir.join('file') - filepath.write("Hello") - nlink = filepath.stat().nlink - linkpath.mklinkto(filepath) - assert filepath.stat().nlink == nlink + 1 - - def test_symlink_are_identical(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): - 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): - 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_symlink_not_existing(self, tmpdir): - linkpath = tmpdir.join('testnotexisting') - assert not linkpath.check(link=1) - assert linkpath.check(link=0) - - def test_relto_with_root(self, path1, tmpdir): - y = path1.join('x').relto(py.path.local('/')) - assert y[0] == str(path1)[1] - - def test_visit_recursive_symlink(self, tmpdir): - linkpath = tmpdir.join('test') - linkpath.mksymlinkto(tmpdir) - visitor = tmpdir.visit(None, lambda x: x.check(link=0)) - assert list(visitor) == [linkpath] - - def test_symlink_isdir(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): - 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): - linkpath = tmpdir.join('test') - filepath = tmpdir.join('file') - filepath.write("") - linkpath.mksymlinkto(filepath) - realpath = linkpath.realpath() - assert realpath.basename == 'file' - - def test_owner(self, path1, tmpdir): - from pwd import getpwuid - from grp import getgrgid - stat = path1.stat() - assert stat.path == path1 - - uid = stat.uid - gid = stat.gid - owner = getpwuid(uid)[0] - group = getgrgid(gid)[0] - - assert uid == stat.uid - assert owner == stat.owner - assert gid == stat.gid - assert group == stat.group - - def test_atime(self, tmpdir): - import time - path = tmpdir.ensure('samplefile') - now = time.time() - atime1 = path.atime() - # we could wait here but timer resolution is very - # system dependent - path.read() - atime2 = path.atime() - duration = time.time() - now - assert (atime2-atime1) <= duration - - def test_commondir(self, path1): - # XXX This is here in local until we find a way to implement this - # using the subversion command line api. - p1 = path1.join('something') - p2 = path1.join('otherthing') - assert p1.common(p2) == path1 - assert p2.common(p1) == path1 - - def test_commondir_nocommon(self, path1): - # XXX This is here in local until we find a way to implement this - # using the subversion command line api. - p1 = path1.join('something') - p2 = py.path.local(path1.sep+'blabla') - assert p1.common(p2) == '/' - - def test_join_to_root(self, path1): - root = path1.parts()[0] - assert len(str(root)) == 1 - assert str(root.join('a')) == '/a' - - def test_join_root_to_root_with_no_abs(self, path1): - nroot = path1.join('/') - assert str(path1) == str(nroot) - assert path1 == nroot - - def test_chmod_simple_int(self, path1): - mode = path1.stat().mode - path1.chmod(int(mode/2)) - try: - assert path1.stat().mode != mode - finally: - path1.chmod(mode) - assert path1.stat().mode == mode - - def test_chmod_rec_int(self, path1): - # XXX fragile test - recfilter = lambda x: x.check(dotfile=0, link=0) - oldmodes = {} - for x in path1.visit(rec=recfilter): - oldmodes[x] = x.stat().mode - path1.chmod(int("772", 8), rec=recfilter) - try: - for x in path1.visit(rec=recfilter): - assert x.stat().mode & int("777", 8) == int("772", 8) - finally: - for x,y in oldmodes.items(): - x.chmod(y) - - def test_chown_identity(self, path1): - owner = path1.stat().owner - group = path1.stat().group - path1.chown(owner, group) - - def test_chown_dangling_link(self, path1): - owner = path1.stat().owner - group = path1.stat().group - x = path1.join('hello') - x.mksymlinkto('qlwkejqwlek') - try: - path1.chown(owner, group, rec=1) - finally: - x.remove(rec=0) - - def test_chown_identity_rec_mayfail(self, path1): - owner = path1.stat().owner - group = path1.stat().group - path1.chown(owner, group) --- a/py/cmdline/testing/test_cmdline.py +++ /dev/null @@ -1,18 +0,0 @@ - -pytest_plugins = "pytest_pytester" - -class TestPyLookup: - def test_basic(self, testdir): - p = testdir.makepyfile(hello="def x(): pass") - result = testdir.runpybin("py.lookup", "pass") - result.stdout.fnmatch_lines( - ['%s:*def x(): pass' %(p.basename)] - ) - - def test_search_in_filename(self, testdir): - p = testdir.makepyfile(hello="def x(): pass") - result = testdir.runpybin("py.lookup", "hello") - result.stdout.fnmatch_lines( - ['*%s:*' %(p.basename)] - ) - --- a/py/process/testing/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/path/testing/test_svnauth.py +++ /dev/null @@ -1,443 +0,0 @@ -import py -from py.__.path.testing import svntestbase -from py.path import SvnAuth -import time -import sys - -def make_repo_auth(repo, userdata): - """ write config to repo - - user information in userdata is used for auth - userdata has user names as keys, and a tuple (password, readwrite) as - values, where 'readwrite' is either 'r' or 'rw' - """ - confdir = py.path.local(repo).join('conf') - confdir.join('svnserve.conf').write('''\ -[general] -anon-access = none -password-db = passwd -authz-db = authz -realm = TestRepo -''') - authzdata = '[/]\n' - passwddata = '[users]\n' - for user in userdata: - authzdata += '%s = %s\n' % (user, userdata[user][1]) - passwddata += '%s = %s\n' % (user, userdata[user][0]) - confdir.join('authz').write(authzdata) - confdir.join('passwd').write(passwddata) - -def serve_bg(repopath): - pidfile = py.path.local(repopath).join('pid') - port = 10000 - e = None - while port < 10010: - cmd = 'svnserve -d -T --listen-port=%d --pid-file=%s -r %s' % ( - port, pidfile, repopath) - print(cmd) - try: - py.process.cmdexec(cmd) - except py.process.cmdexec.Error: - e = sys.exc_info()[1] - else: - # XXX we assume here that the pid file gets written somewhere, I - # guess this should be relatively safe... (I hope, at least?) - counter = pid = 0 - while counter < 10: - counter += 1 - try: - pid = pidfile.read() - except py.error.ENOENT: - pass - if pid: - break - time.sleep(0.2) - return port, int(pid) - port += 1 - raise IOError('could not start svnserve: %s' % (e,)) - -class TestSvnAuth(object): - def test_basic(self): - auth = SvnAuth('foo', 'bar') - assert auth.username == 'foo' - assert auth.password == 'bar' - assert str(auth) - - def test_makecmdoptions_uname_pw_makestr(self): - auth = SvnAuth('foo', 'bar') - assert auth.makecmdoptions() == '--username="foo" --password="bar"' - - def test_makecmdoptions_quote_escape(self): - auth = SvnAuth('fo"o', '"ba\'r"') - assert auth.makecmdoptions() == '--username="fo\\"o" --password="\\"ba\'r\\""' - - def test_makecmdoptions_no_cache_auth(self): - auth = SvnAuth('foo', 'bar', cache_auth=False) - assert auth.makecmdoptions() == ('--username="foo" --password="bar" ' - '--no-auth-cache') - - def test_makecmdoptions_no_interactive(self): - auth = SvnAuth('foo', 'bar', interactive=False) - assert auth.makecmdoptions() == ('--username="foo" --password="bar" ' - '--non-interactive') - - def test_makecmdoptions_no_interactive_no_cache_auth(self): - auth = SvnAuth('foo', 'bar', cache_auth=False, - interactive=False) - assert auth.makecmdoptions() == ('--username="foo" --password="bar" ' - '--no-auth-cache --non-interactive') - -class svnwc_no_svn(py.path.svnwc): - def __init__(self, *args, **kwargs): - self.commands = [] - super(svnwc_no_svn, self).__init__(*args, **kwargs) - - def _svn(self, *args): - self.commands.append(args) - -class TestSvnWCAuth(object): - def setup_method(self, meth): - self.auth = SvnAuth('user', 'pass', cache_auth=False) - - def test_checkout(self): - wc = svnwc_no_svn('foo', auth=self.auth) - wc.checkout('url') - assert wc.commands[0][-1] == ('--username="user" --password="pass" ' - '--no-auth-cache') - - def test_commit(self): - wc = svnwc_no_svn('foo', auth=self.auth) - wc.commit('msg') - assert wc.commands[0][-1] == ('--username="user" --password="pass" ' - '--no-auth-cache') - - def test_checkout_no_cache_auth(self): - wc = svnwc_no_svn('foo', auth=self.auth) - wc.checkout('url') - assert wc.commands[0][-1] == ('--username="user" --password="pass" ' - '--no-auth-cache') - - def test_checkout_auth_from_constructor(self): - wc = svnwc_no_svn('foo', auth=self.auth) - wc.checkout('url') - assert wc.commands[0][-1] == ('--username="user" --password="pass" ' - '--no-auth-cache') - -class svnurl_no_svn(py.path.svnurl): - cmdexec_output = 'test' - popen_output = 'test' - def __init__(self, *args, **kwargs): - py.path.svnurl.__init__(self, *args, **kwargs) - self.commands = [] - - def _cmdexec(self, cmd): - self.commands.append(cmd) - return self.cmdexec_output - - def _popen(self, cmd): - self.commands.append(cmd) - return self.popen_output - -class TestSvnURLAuth(object): - def setup_method(self, meth): - self.auth = SvnAuth('foo', 'bar') - - def test_init(self): - u = svnurl_no_svn('http://foo.bar/svn') - assert u.auth is None - - u = svnurl_no_svn('http://foo.bar/svn', auth=self.auth) - assert u.auth is self.auth - - def test_new(self): - u = svnurl_no_svn('http://foo.bar/svn/foo', auth=self.auth) - new = u.new(basename='bar') - assert new.auth is self.auth - assert new.url == 'http://foo.bar/svn/bar' - - def test_join(self): - u = svnurl_no_svn('http://foo.bar/svn', auth=self.auth) - new = u.join('foo') - assert new.auth is self.auth - assert new.url == 'http://foo.bar/svn/foo' - - def test_listdir(self): - u = svnurl_no_svn('http://foo.bar/svn', auth=self.auth) - u.cmdexec_output = '''\ - 1717 johnny 1529 Nov 04 14:32 LICENSE.txt - 1716 johnny 5352 Nov 04 14:28 README.txt -''' - paths = u.listdir() - assert paths[0].auth is self.auth - assert paths[1].auth is self.auth - assert paths[0].basename == 'LICENSE.txt' - - def test_info(self): - u = svnurl_no_svn('http://foo.bar/svn/LICENSE.txt', auth=self.auth) - def dirpath(self): - return self - u.cmdexec_output = '''\ - 1717 johnny 1529 Nov 04 14:32 LICENSE.txt - 1716 johnny 5352 Nov 04 14:28 README.txt -''' - org_dp = u.__class__.dirpath - u.__class__.dirpath = dirpath - try: - info = u.info() - finally: - u.dirpath = org_dp - assert info.size == 1529 - - def test_open(self): - u = svnurl_no_svn('http://foo.bar/svn', auth=self.auth) - foo = u.join('foo') - foo.check = lambda *args, **kwargs: True - ret = foo.open() - assert ret == 'test' - assert '--username="foo" --password="bar"' in foo.commands[0] - - def test_dirpath(self): - u = svnurl_no_svn('http://foo.bar/svn/foo', auth=self.auth) - parent = u.dirpath() - assert parent.auth is self.auth - - def test_mkdir(self): - u = svnurl_no_svn('http://foo.bar/svn/qweqwe', auth=self.auth) - assert not u.commands - u.mkdir(msg='created dir foo') - assert u.commands - assert '--username="foo" --password="bar"' in u.commands[0] - - def test_copy(self): - u = svnurl_no_svn('http://foo.bar/svn', auth=self.auth) - u2 = svnurl_no_svn('http://foo.bar/svn2') - u.copy(u2, 'copied dir') - assert '--username="foo" --password="bar"' in u.commands[0] - - def test_rename(self): - u = svnurl_no_svn('http://foo.bar/svn/foo', auth=self.auth) - u.rename('http://foo.bar/svn/bar', 'moved foo to bar') - assert '--username="foo" --password="bar"' in u.commands[0] - - def test_remove(self): - u = svnurl_no_svn('http://foo.bar/svn/foo', auth=self.auth) - u.remove(msg='removing foo') - assert '--username="foo" --password="bar"' in u.commands[0] - - def test_export(self): - u = svnurl_no_svn('http://foo.bar/svn', auth=self.auth) - target = py.path.local('/foo') - u.export(target) - assert '--username="foo" --password="bar"' in u.commands[0] - - def test_log(self): - u = svnurl_no_svn('http://foo.bar/svn/foo', auth=self.auth) - u.popen_output = py.io.TextIO('''\ - - - -guido -2008-02-11T12:12:18.476481Z -Creating branch to work on auth support for py.path.svn*. - - - -''') - u.check = lambda *args, **kwargs: True - ret = u.log(10, 20, verbose=True) - assert '--username="foo" --password="bar"' in u.commands[0] - assert len(ret) == 1 - assert int(ret[0].rev) == 51381 - assert ret[0].author == 'guido' - - def test_propget(self): - u = svnurl_no_svn('http://foo.bar/svn', auth=self.auth) - u.propget('foo') - assert '--username="foo" --password="bar"' in u.commands[0] - -class pytest_funcarg__setup: - def __init__(self, request): - if not request.config.option.runslowtests: - py.test.skip('use --runslowtests to run these tests') - - tmpdir = request.getfuncargvalue("tmpdir") - repodir = tmpdir.join("repo") - py.process.cmdexec('svnadmin create %s' % repodir) - if sys.platform == 'win32': - repodir = '/' + str(repodir).replace('\\', '/') - self.repo = py.path.svnurl("file://%s" % repodir) - if py.std.sys.platform == 'win32': - # remove trailing slash... - repodir = repodir[1:] - self.repopath = py.path.local(repodir) - self.temppath = tmpdir.mkdir("temppath") - self.auth = SvnAuth('johnny', 'foo', cache_auth=False, - interactive=False) - make_repo_auth(self.repopath, {'johnny': ('foo', 'rw')}) - self.port, self.pid = serve_bg(self.repopath.dirpath()) - # XXX caching is too global - py.path.svnurl._lsnorevcache._dict.clear() - request.addfinalizer(lambda: py.process.kill(self.pid)) - -class TestSvnWCAuthFunctional: - def test_checkout_constructor_arg(self, setup): - wc = py.path.svnwc(setup.temppath, auth=setup.auth) - wc.checkout( - 'svn://localhost:%s/%s' % (setup.port, setup.repopath.basename)) - assert wc.join('.svn').check() - - def test_checkout_function_arg(self, setup): - wc = py.path.svnwc(setup.temppath, auth=setup.auth) - wc.checkout( - 'svn://localhost:%s/%s' % (setup.port, setup.repopath.basename)) - assert wc.join('.svn').check() - - def test_checkout_failing_non_interactive(self, setup): - auth = SvnAuth('johnny', 'bar', cache_auth=False, - interactive=False) - wc = py.path.svnwc(setup.temppath, auth) - py.test.raises(Exception, - ("wc.checkout('svn://localhost:%(port)s/%(repopath)s')" % - setup.__dict__)) - - def test_log(self, setup): - wc = py.path.svnwc(setup.temppath, setup.auth) - wc.checkout( - 'svn://localhost:%s/%s' % (setup.port, setup.repopath.basename)) - foo = wc.ensure('foo.txt') - wc.commit('added foo.txt') - log = foo.log() - assert len(log) == 1 - assert log[0].msg == 'added foo.txt' - - def test_switch(self, setup): - wc = py.path.svnwc(setup.temppath, auth=setup.auth) - svnurl = 'svn://localhost:%s/%s' % (setup.port, setup.repopath.basename) - wc.checkout(svnurl) - wc.ensure('foo', dir=True).ensure('foo.txt').write('foo') - wc.commit('added foo dir with foo.txt file') - wc.ensure('bar', dir=True) - wc.commit('added bar dir') - bar = wc.join('bar') - bar.switch(svnurl + '/foo') - assert bar.join('foo.txt') - - def test_update(self, setup): - wc1 = py.path.svnwc(setup.temppath.ensure('wc1', dir=True), - auth=setup.auth) - wc2 = py.path.svnwc(setup.temppath.ensure('wc2', dir=True), - auth=setup.auth) - wc1.checkout( - 'svn://localhost:%s/%s' % (setup.port, setup.repopath.basename)) - wc2.checkout( - 'svn://localhost:%s/%s' % (setup.port, setup.repopath.basename)) - wc1.ensure('foo', dir=True) - wc1.commit('added foo dir') - wc2.update() - assert wc2.join('foo').check() - - auth = SvnAuth('unknown', 'unknown', interactive=False) - wc2.auth = auth - py.test.raises(Exception, 'wc2.update()') - - def test_lock_unlock_status(self, setup): - port = setup.port - wc = py.path.svnwc(setup.temppath, auth=setup.auth) - wc.checkout( - 'svn://localhost:%s/%s' % (port, setup.repopath.basename,)) - wc.ensure('foo', file=True) - wc.commit('added foo file') - foo = wc.join('foo') - foo.lock() - status = foo.status() - assert status.locked - foo.unlock() - status = foo.status() - assert not status.locked - - auth = SvnAuth('unknown', 'unknown', interactive=False) - foo.auth = auth - py.test.raises(Exception, 'foo.lock()') - py.test.raises(Exception, 'foo.unlock()') - - def test_diff(self, setup): - port = setup.port - wc = py.path.svnwc(setup.temppath, auth=setup.auth) - wc.checkout( - 'svn://localhost:%s/%s' % (port, setup.repopath.basename,)) - wc.ensure('foo', file=True) - wc.commit('added foo file') - wc.update() - rev = int(wc.status().rev) - foo = wc.join('foo') - foo.write('bar') - diff = foo.diff() - assert '\n+bar\n' in diff - foo.commit('added some content') - diff = foo.diff() - assert not diff - diff = foo.diff(rev=rev) - assert '\n+bar\n' in diff - - auth = SvnAuth('unknown', 'unknown', interactive=False) - foo.auth = auth - py.test.raises(Exception, 'foo.diff(rev=rev)') - -class TestSvnURLAuthFunctional: - def test_listdir(self, setup): - port = setup.port - u = py.path.svnurl( - 'svn://localhost:%s/%s' % (port, setup.repopath.basename), - auth=setup.auth) - u.ensure('foo') - paths = u.listdir() - assert len(paths) == 1 - assert paths[0].auth is setup.auth - - auth = SvnAuth('foo', 'bar', interactive=False) - u = py.path.svnurl( - 'svn://localhost:%s/%s' % (port, setup.repopath.basename), - auth=auth) - py.test.raises(Exception, 'u.listdir()') - - def test_copy(self, setup): - port = setup.port - u = py.path.svnurl( - 'svn://localhost:%s/%s' % (port, setup.repopath.basename), - auth=setup.auth) - foo = u.mkdir('foo') - assert foo.check() - bar = u.join('bar') - foo.copy(bar) - assert bar.check() - assert bar.auth is setup.auth - - auth = SvnAuth('foo', 'bar', interactive=False) - u = py.path.svnurl( - 'svn://localhost:%s/%s' % (port, setup.repopath.basename), - auth=auth) - foo = u.join('foo') - bar = u.join('bar') - py.test.raises(Exception, 'foo.copy(bar)') - - def test_write_read(self, setup): - port = setup.port - u = py.path.svnurl( - 'svn://localhost:%s/%s' % (port, setup.repopath.basename), - auth=setup.auth) - foo = u.ensure('foo') - fp = foo.open() - try: - data = fp.read() - finally: - fp.close() - assert data == '' - - auth = SvnAuth('foo', 'bar', interactive=False) - u = py.path.svnurl( - 'svn://localhost:%s/%s' % (port, setup.repopath.basename), - auth=auth) - foo = u.join('foo') - py.test.raises(Exception, 'foo.open()') - - # XXX rinse, repeat... :| --- a/py/io/testing/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/code/testing/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/path/testing/svntestbase.py +++ /dev/null @@ -1,31 +0,0 @@ -import sys -import py -from py.__.path.testing.common import CommonFSTests -from py.__.path import svnwc as svncommon - -class CommonSvnTests(CommonFSTests): - - def test_propget(self, path1): - url = path1.join("samplefile") - value = url.propget('svn:eol-style') - assert value == 'native' - - def test_proplist(self, path1): - url = path1.join("samplefile") - res = url.proplist() - assert res['svn:eol-style'] == 'native' - - def test_info(self, path1): - url = path1.join("samplefile") - res = url.info() - assert res.size > len("samplefile") and res.created_rev >= 0 - - def test_log_simple(self, path1): - url = path1.join("samplefile") - logentries = url.log() - for logentry in logentries: - assert logentry.rev == 1 - assert hasattr(logentry, 'author') - assert hasattr(logentry, 'date') - -#cache.repositories.put(svnrepourl, 1200, 0) --- a/py/code/testing/test_source.py +++ /dev/null @@ -1,392 +0,0 @@ -from py.code import Source -import py -import sys - -def test_source_str_function(): - x = Source("3") - assert str(x) == "3" - - x = Source(" 3") - assert str(x) == "3" - - x = Source(""" - 3 - """, rstrip=False) - assert str(x) == "\n3\n " - - x = Source(""" - 3 - """, rstrip=True) - assert str(x) == "\n3" - -def test_unicode(): - try: - unicode - except NameError: - return - x = Source(unicode("4")) - assert str(x) == "4" - co = py.code.compile(unicode('u"\xc3\xa5"', 'utf8'), mode='eval') - val = eval(co) - assert isinstance(val, unicode) - -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_putaround_simple(): - source = Source("raise ValueError") - source = source.putaround( - "try:", """\ - except ValueError: - x = 42 - else: - x = 23""") - assert str(source)=="""\ -try: - raise ValueError -except ValueError: - x = 42 -else: - x = 23""" - -def test_source_putaround(): - source = Source() - source = source.putaround(""" - if 1: - x=1 - """) - assert str(source).strip() == "if 1:\n x=1" - -def test_source_strips(): - source = Source("") - assert source == Source() - assert str(source) == '' - assert source.strip() == source - -def test_source_strip_multiline(): - source = Source() - source.lines = ["", " hello", " "] - source2 = source.strip() - assert source2.lines == [" hello"] - -def test_syntaxerror_rerepresentation(): - ex = py.test.raises(SyntaxError, py.code.compile, 'x x') - assert ex.value.lineno == 1 - assert ex.value.offset == 3 - assert ex.value.text.strip(), 'x x' - -def test_isparseable(): - 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: - source = Source("""\ - def f(x): - pass - def g(x): - pass - """) - def test_getrange(self): - x = self.source[0:2] - assert x.isparseable() - assert len(x.lines) == 2 - assert str(x) == "def f(x):\n pass" - - def test_getline(self): - 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 TestSourceParsingAndCompiling: - source = Source("""\ - def f(x): - assert (x == - 3 + - 4) - """).strip() - - def test_compile(self): - co = py.code.compile("x=3") - d = {} - exec (co, d) - assert d['x'] == 3 - - def test_compile_and_getsource_simple(self): - co = py.code.compile("x=3") - 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): - #print "trying start in line %r" % self.source[i] - s = self.source.getstatement(i) - #x = s.deindent() - assert str(s) == ass - - def test_getstatementrange_within_constructs(self): - source = Source("""\ - try: - try: - raise ValueError - except SomeThing: - pass - finally: - 42 - """) - assert len(source) == 7 - assert source.getstatementrange(0) == (0, 7) - assert source.getstatementrange(1) == (1, 5) - assert source.getstatementrange(2) == (2, 3) - assert source.getstatementrange(3) == (1, 5) - assert source.getstatementrange(4) == (4, 5) - assert source.getstatementrange(5) == (0, 7) - assert source.getstatementrange(6) == (6, 7) - - def test_getstatementrange_bug(self): - source = Source("""\ - try: - x = ( - y + - z) - except: - pass - """) - assert len(source) == 6 - assert source.getstatementrange(2) == (1, 4) - - @py.test.mark.xfail - def test_getstatementrange_bug2(self): - source = Source("""\ - assert ( - 33 - == - [ - X(3, - b=1, c=2 - ), - ] - ) - """) - assert len(source) == 9 - assert source.getstatementrange(5) == (0, 9) - - def test_compile_to_ast(self): - if sys.version_info < (2, 5): - py.test.skip("requires Python 2.5") - import _ast - source = Source("x = 4") - mod = source.compile(flag=_ast.PyCF_ONLY_AST) - assert isinstance(mod, _ast.Module) - compile(mod, "", "exec") - - def test_compile_and_getsource(self): - co = self.source.compile() - py.builtin.exec_(co, globals()) - f(7) - excinfo = py.test.raises(AssertionError, "f(6)") - frame = excinfo.traceback[-1].frame - stmt = frame.code.fullsource.getstatement(frame.lineno) - #print "block", str(block) - assert str(stmt).strip().startswith('assert') - - def test_compilefuncs_and_path_sanity(self): - def check(comp, name): - co = comp(self.source, name) - if not name: - expected = "" %(mypath, mylineno+2+1) - else: - expected = "" % (name, mypath, mylineno+2+1) - fn = co.co_filename - assert fn == expected - - mycode = py.code.Code(self.test_compilefuncs_and_path_sanity) - mylineno = mycode.firstlineno - mypath = mycode.path - - for comp in py.code.compile, py.code.Source.compile: - for name in '', None, 'my': - yield check, comp, name - - def test_offsetless_synerr(self): - py.test.raises(SyntaxError, py.code.compile, "lambda a,a: 0", mode='eval') - -def test_getstartingblock_singleline(): - class A: - def __init__(self, *args): - frame = sys._getframe(1) - 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 - -def test_getstartingblock_multiline(): - class A: - def __init__(self, *args): - frame = sys._getframe(1) - self.source = py.code.Frame(frame).statement - - x = A('x', - 'y' \ - , - 'z') - - l = [i for i in x.source.lines if i.strip()] - assert len(l) == 4 - -def test_getline_finally(): - #py.test.skip("inner statements cannot be located yet.") - def c(): pass - excinfo = py.test.raises(TypeError, """ - teardown = None - try: - c(1) - finally: - if teardown: - teardown() - """) - source = excinfo.traceback[-1].statement - assert str(source).strip() == 'c(1)' - -def test_getfuncsource_dynamic(): - source = """ - def f(): - raise ValueError - - def g(): pass - """ - co = py.code.compile(source) - py.builtin.exec_(co, globals()) - assert str(py.code.Source(f)).strip() == 'def f():\n raise ValueError' - assert str(py.code.Source(g)).strip() == 'def g(): pass' - - -def test_getfuncsource_with_multine_string(): - def f(): - c = '''while True: - pass -''' - assert str(py.code.Source(f)).strip() == "def f():\n c = '''while True:\n pass\n'''" - - -def test_deindent(): - from py.__.code.source import deindent as deindent - assert deindent(['\tfoo', '\tbar', ]) == ['foo', 'bar'] - - def f(): - c = '''while True: - pass -''' - import inspect - lines = deindent(inspect.getsource(f).splitlines()) - assert lines == ["def f():", " c = '''while True:", " pass", "'''"] - - source = """ - def f(): - def g(): - pass - """ - lines = deindent(source.splitlines()) - assert lines == ['', 'def f():', ' def g():', ' pass', ' '] - - at py.test.mark.xfail -def test_source_of_class_at_eof_without_newline(): - # this test fails because the implicit inspect.getsource(A) below - # does not return the "x = 1" last line. - tmpdir = py.test.ensuretemp("source_write_read") - source = py.code.Source(''' - class A(object): - def method(self): - x = 1 - ''') - path = tmpdir.join("a.py") - path.write(source) - s2 = py.code.Source(tmpdir.join("a.py").pyimport().A) - assert str(source).strip() == str(s2).strip() - -if True: - def x(): - pass - -def test_getsource_fallback(): - from py.__.code.source import getsource - expected = """def x(): - pass""" - src = getsource(x) - assert src == expected - -def test_idem_compile_and_getsource(): - from py.__.code.source import getsource - expected = "def x(): pass" - co = py.code.compile(expected) - src = getsource(co) - assert src == expected - -def test_findsource_fallback(): - from py.__.code.source import findsource - src, lineno = findsource(x) - assert 'test_findsource_simple' in str(src) - assert src[lineno] == ' def x():' - -def test_findsource___source__(): - from py.__.code.source import findsource - co = py.code.compile("""if 1: - def x(): - pass -""") - - src, lineno = findsource(co) - assert 'if 1:' in str(src) - - d = {} - eval(co, d) - src, lineno = findsource(d['x']) - assert 'if 1:' in str(src) - assert src[lineno] == " def x():" - - -def test_getfslineno(): - from py.code import getfslineno - - def f(x): - pass - - fspath, lineno = getfslineno(f) - - fname = __file__ - if fname.lower().endswith('.pyc'): - fname = fname[:-1] - - assert fspath == py.path.local(fname) - assert lineno == py.code.getrawcode(f).co_firstlineno-1 # see findsource - - class A(object): - pass - - fspath, lineno = getfslineno(A) - - _, A_lineno = py.std.inspect.findsource(A) - assert fspath == py.path.local(fname) - assert lineno == A_lineno --- a/py/builtin/testing/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/_testing/test_std.py +++ /dev/null @@ -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__ --- a/py/path/testing/test_svnurl.py +++ /dev/null @@ -1,106 +0,0 @@ -import py -from py.__.path.svnurl import InfoSvnCommand -from py.__.path.testing.svntestbase import CommonSvnTests -import datetime -import time - -def pytest_funcarg__path1(request): - repo, wc = request.getfuncargvalue("repowc1") - return py.path.svnurl(repo) - -class TestSvnURLCommandPath(CommonSvnTests): - @py.test.mark.xfail - def test_load(self, path1): - super(TestSvnURLCommandPath, self).test_load(path1) - - def test_move_file(self, path1): # overrides base class - p = path1.ensure('origfile') - newp = p.dirpath('newfile') - p.move(newp) - assert newp.check(file=1) - newp.remove() - assert not p.check() - - def test_move_dir(self, path1): # overrides base class - p = path1.ensure('origdir', dir=1) - newp = p.dirpath('newdir') - p.move(newp) - assert newp.check(dir=1) - newp.remove() - assert not p.check() - - def test_svnurl_needs_arg(self, path1): - py.test.raises(TypeError, "py.path.svnurl()") - - def test_svnurl_does_not_accept_None_either(self, path1): - py.test.raises(Exception, "py.path.svnurl(None)") - - def test_svnurl_characters_simple(self, path1): - py.path.svnurl("svn+ssh://hello/world") - - def test_svnurl_characters_at_user(self, path1): - py.path.svnurl("http://user at host.com/some/dir") - - def test_svnurl_characters_at_path(self, path1): - py.test.raises(ValueError, 'py.path.svnurl("http://host.com/foo at bar")') - - def test_svnurl_characters_colon_port(self, path1): - py.path.svnurl("http://host.com:8080/some/dir") - - def test_svnurl_characters_tilde_end(self, path1): - py.path.svnurl("http://host.com/some/file~") - - def test_svnurl_characters_colon_path(self, path1): - if py.std.sys.platform == 'win32': - # colons are allowed on win32, because they're part of the drive - # part of an absolute path... however, they shouldn't be allowed in - # other parts, I think - py.test.skip('XXX fixme win32') - py.test.raises(ValueError, 'py.path.svnurl("http://host.com/foo:bar")') - - def test_export(self, path1, tmpdir): - tmpdir = tmpdir.join("empty") - p = path1.export(tmpdir) - assert p == tmpdir # XXX should return None - n1 = [x.basename for x in tmpdir.listdir()] - n2 = [x.basename for x in path1.listdir()] - n1.sort() - n2.sort() - assert n1 == n2 - assert not p.join('.svn').check() - rev = path1.mkdir("newdir") - tmpdir.remove() - assert not tmpdir.check() - path1.new(rev=1).export(tmpdir) - for p in tmpdir.listdir(): - assert p.basename in n2 - -class TestSvnInfoCommand: - - def test_svn_1_2(self): - line = " 2256 hpk 165 Nov 24 17:55 __init__.py" - info = InfoSvnCommand(line) - now = datetime.datetime.now() - assert info.last_author == 'hpk' - assert info.created_rev == 2256 - assert info.kind == 'file' - # we don't check for the year (2006), because that depends - # on the clock correctly being setup - assert time.gmtime(info.mtime)[1:6] == (11, 24, 17, 55, 0) - assert info.size == 165 - assert info.time == info.mtime * 1000000 - - def test_svn_1_3(self): - line =" 4784 hpk 2 Jun 01 2004 __init__.py" - info = InfoSvnCommand(line) - assert info.last_author == 'hpk' - assert info.kind == 'file' - - def test_svn_1_3_b(self): - line =" 74 autoadmi Oct 06 23:59 plonesolutions.com/" - info = InfoSvnCommand(line) - assert info.last_author == 'autoadmi' - assert info.kind == 'dir' - -def test_badchars(): - py.test.raises(ValueError, "py.path.svnurl('http://host/tmp/@@@:')") --- a/py/path/testing/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/code/testing/test_assertion.py +++ /dev/null @@ -1,197 +0,0 @@ -import py - -def exvalue(): - return py.std.sys.exc_info()[1] - -def setup_module(mod): - py.code.patch_builtins(assertion=True, compile=False) - -def teardown_module(mod): - py.code.unpatch_builtins(assertion=True, compile=False) - -def f(): - return 2 - -def test_assert(): - try: - assert f() == 3 - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith('assert 2 == 3\n') - -def test_assert_with_explicit_message(): - try: - assert f() == 3, "hello" - except AssertionError: - e = exvalue() - assert e.msg == 'hello' - -def test_assert_within_finally(): - class A: - def f(): - pass - excinfo = py.test.raises(TypeError, """ - try: - A().f() - finally: - i = 42 - """) - s = excinfo.exconly() - 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 = exvalue() - s = str(e) - assert s.startswith('assert 2 == 3\n') - -def test_assert_multiline_2(): - try: - assert (f() == (4, - 3)[-1]) - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith('assert 2 ==') - -def test_in(): - try: - assert "hi" in [1, 2] - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith("assert 'hi' in") - -def test_is(): - try: - assert 1 is 2 - except AssertionError: - e = exvalue() - s = str(e) - assert s.startswith("assert 1 is 2") - -def test_assert_non_string_message(): - class A: - def __str__(self): - return "hello" - try: - assert 0 == 1, A() - except AssertionError: - e = exvalue() - assert e.msg == "hello" - - -# These tests should both fail, but should fail nicely... -class WeirdRepr: - def __repr__(self): - return '' - -def bug_test_assert_repr(): - v = WeirdRepr() - try: - assert v == 1 - except AssertionError: - e = exvalue() - assert e.msg.find('WeirdRepr') != -1 - assert e.msg.find('second line') != -1 - assert 0 - -def test_assert_non_string(): - try: - assert 0, ['list'] - except AssertionError: - e = exvalue() - assert e.msg.find("list") != -1 - -def test_assert_implicit_multiline(): - try: - x = [1,2,3] - assert x != [1, - 2, 3] - except AssertionError: - e = exvalue() - assert e.msg.find('assert [1, 2, 3] !=') != -1 - - -def test_assert_with_brokenrepr_arg(): - class BrokenRepr: - def __repr__(self): 0 / 0 - e = AssertionError(BrokenRepr()) - if e.msg.find("broken __repr__") == -1: - py.test.fail("broken __repr__ not handle correctly") - - -class TestView: - - def setup_class(cls): - try: - from py.__.code._assertionold import View - except ImportError: - py.test.skip("requires the compile package") - cls.View = View - - def test_class_dispatch(self): - ### Use a custom class hierarchy with existing instances - - class Picklable(self.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_viewtype_class_hierarchy(self): - # 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(self.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"] - --- a/py/execnet/testing/test_gwmanage.py +++ /dev/null @@ -1,151 +0,0 @@ -""" - tests for - - gateway management - - manage rsyncing of hosts - -""" - -import py -import os -from py.__.execnet.gwmanage import GatewayManager, HostRSync - -class TestGatewayManagerPopen: - def test_popen_no_default_chdir(self): - gm = GatewayManager(["popen"]) - assert gm.specs[0].chdir is None - - def test_default_chdir(self): - l = ["ssh=noco", "socket=xyz"] - for spec in GatewayManager(l).specs: - assert spec.chdir == "pyexecnetcache" - for spec in GatewayManager(l, defaultchdir="abc").specs: - assert spec.chdir == "abc" - - def test_popen_makegateway_events(self, _pytest): - rec = _pytest.gethookrecorder(py.execnet._HookSpecs) - hm = GatewayManager(["popen"] * 2) - hm.makegateways() - call = rec.popcall("pyexecnet_gwmanage_newgateway") - assert call.gateway.id == "[1]" - assert call.platinfo.executable == call.gateway._rinfo().executable - call = rec.popcall("pyexecnet_gwmanage_newgateway") - assert call.gateway.id == "[2]" - assert len(hm.gateways) == 2 - hm.exit() - assert not len(hm.gateways) - - def test_popens_rsync(self, mysetup): - source = mysetup.source - hm = GatewayManager(["popen"] * 2) - hm.makegateways() - assert len(hm.gateways) == 2 - for gw in hm.gateways: - gw.remote_exec = None - l = [] - hm.rsync(source, notify=lambda *args: l.append(args)) - assert not l - hm.exit() - assert not len(hm.gateways) - - def test_rsync_popen_with_path(self, mysetup): - source, dest = mysetup.source, mysetup.dest - hm = GatewayManager(["popen//chdir=%s" %dest] * 1) - hm.makegateways() - source.ensure("dir1", "dir2", "hello") - l = [] - hm.rsync(source, notify=lambda *args: l.append(args)) - assert len(l) == 1 - assert l[0] == ("rsyncrootready", hm.gateways[0].spec, source) - hm.exit() - dest = dest.join(source.basename) - assert dest.join("dir1").check() - assert dest.join("dir1", "dir2").check() - assert dest.join("dir1", "dir2", 'hello').check() - - def test_hostmanage_rsync_same_popen_twice(self, mysetup, _pytest): - source, dest = mysetup.source, mysetup.dest - rec = _pytest.gethookrecorder(py.execnet._HookSpecs) - hm = GatewayManager(["popen//chdir=%s" %dest] * 2) - hm.makegateways() - source.ensure("dir1", "dir2", "hello") - hm.rsync(source) - call = rec.popcall("pyexecnet_gwmanage_rsyncstart") - assert call.source == source - assert len(call.gateways) == 1 - assert hm.gateways[0] == call.gateways[0] - call = rec.popcall("pyexecnet_gwmanage_rsyncfinish") - - def test_multi_chdir_popen_with_path(self, testdir): - hm = GatewayManager(["popen//chdir=hello"] * 2) - testdir.tmpdir.chdir() - hellopath = testdir.tmpdir.mkdir("hello").realpath() - hm.makegateways() - l = hm.multi_exec( - "import os ; channel.send(os.getcwd())").receive_each() - paths = [x[1] for x in l] - assert l == [str(hellopath)] * 2 - py.test.raises(hm.RemoteError, - 'hm.multi_chdir("world", inplacelocal=False)') - worldpath = hellopath.mkdir("world") - hm.multi_chdir("world", inplacelocal=False) - l = hm.multi_exec( - "import os ; channel.send(os.getcwd())").receive_each() - assert len(l) == 2 - assert l[0] == l[1] - curwd = os.getcwd() - assert l[0].startswith(curwd) - assert l[0].endswith("world") - - def test_multi_chdir_popen(self, testdir): - import os - hm = GatewayManager(["popen"] * 2) - testdir.tmpdir.chdir() - hellopath = testdir.tmpdir.mkdir("hello") - hm.makegateways() - hm.multi_chdir("hello", inplacelocal=False) - l = hm.multi_exec("import os ; channel.send(os.getcwd())").receive_each() - assert len(l) == 2 - curwd = os.path.realpath(os.getcwd()) - assert l == [curwd] * 2 - - hm.multi_chdir("hello") - l = hm.multi_exec("import os ; channel.send(os.getcwd())").receive_each() - assert len(l) == 2 - assert l[0] == l[1] - assert l[0].startswith(curwd) - assert l[0].endswith("hello") - -class pytest_funcarg__mysetup: - def __init__(self, request): - tmp = request.getfuncargvalue('tmpdir') - self.source = tmp.mkdir("source") - self.dest = tmp.mkdir("dest") - request.getfuncargvalue("_pytest") # to have patching of py._com.comregistry - -class TestHRSync: - def test_hrsync_filter(self, mysetup): - source, dest = mysetup.source, mysetup.dest - source.ensure("dir", "file.txt") - source.ensure(".svn", "entries") - source.ensure(".somedotfile", "moreentries") - source.ensure("somedir", "editfile~") - syncer = HostRSync(source) - l = list(source.visit(rec=syncer.filter, - fil=syncer.filter)) - assert len(l) == 3 - basenames = [x.basename for x in l] - assert 'dir' in basenames - assert 'file.txt' in basenames - assert 'somedir' in basenames - - def test_hrsync_one_host(self, mysetup): - source, dest = mysetup.source, mysetup.dest - gw = py.execnet.makegateway("popen//chdir=%s" % dest) - finished = [] - rsync = HostRSync(source) - rsync.add_target_host(gw, finished=lambda: finished.append(1)) - source.join("hello.py").write("world") - rsync.send() - gw.exit() - assert dest.join(source.basename, "hello.py").check() - assert len(finished) == 1 --- a/py/path/testing/test_svnwc.py +++ /dev/null @@ -1,561 +0,0 @@ -import py -import sys -from py.__.path.testing.svntestbase import CommonSvnTests -from py.__.path.svnwc import InfoSvnWCCommand, XMLWCStatus, parse_wcinfotime -from py.__.path import svnwc as svncommon - -if sys.platform == 'win32': - def normpath(p): - return p -else: - def normpath(p): - p = py.test.importorskip("win32").GetShortPathName(p) - return os.path.normpath(os.path.normcase(p)) - -def test_make_repo(path1, tmpdir): - repo = tmpdir.join("repo") - py.process.cmdexec('svnadmin create %s' % repo) - if sys.platform == 'win32': - repo = '/' + str(repo).replace('\\', '/') - repo = py.path.svnurl("file://%s" % repo) - wc = py.path.svnwc(tmpdir.join("wc")) - wc.checkout(repo) - assert wc.info().rev == 0 - assert len(wc.listdir()) == 0 - p = wc.join("a_file") - p.write("test file") - p.add() - rev = wc.commit("some test") - assert p.info().rev == 1 - assert rev == 1 - rev = wc.commit() - assert rev is None - -def pytest_funcarg__path1(request): - repo, wc = request.getfuncargvalue("repowc1") - return wc - -class TestWCSvnCommandPath(CommonSvnTests): - def test_move_file(self, path1): # overrides base class - try: - super(TestWCSvnCommandPath, self).test_move_file(path1) - finally: - path1.revert(rec=1) - - def test_move_directory(self, path1): # overrides base class - try: - super(TestWCSvnCommandPath, self).test_move_directory(path1) - finally: - path1.revert(rec=1) - - def test_status_attributes_simple(self, path1): - def assert_nochange(p): - s = p.status() - assert not s.modified - assert not s.prop_modified - assert not s.added - assert not s.deleted - assert not s.replaced - - dpath = path1.join('sampledir') - assert_nochange(path1.join('sampledir')) - assert_nochange(path1.join('samplefile')) - - def test_status_added(self, path1): - nf = path1.join('newfile') - nf.write('hello') - nf.add() - try: - s = nf.status() - assert s.added - assert not s.modified - assert not s.prop_modified - assert not s.replaced - finally: - nf.revert() - - def test_status_change(self, path1): - nf = path1.join('samplefile') - try: - nf.write(nf.read() + 'change') - s = nf.status() - assert not s.added - assert s.modified - assert not s.prop_modified - assert not s.replaced - finally: - nf.revert() - - def test_status_added_ondirectory(self, path1): - sampledir = path1.join('sampledir') - try: - t2 = sampledir.mkdir('t2') - t1 = t2.join('t1') - t1.write('test') - t1.add() - s = sampledir.status(rec=1) - # Comparing just the file names, because paths are unpredictable - # on Windows. (long vs. 8.3 paths) - assert t1.basename in [item.basename for item in s.added] - assert t2.basename in [item.basename for item in s.added] - finally: - t2.revert(rec=1) - t2.localpath.remove(rec=1) - - def test_status_unknown(self, path1): - t1 = path1.join('un1') - try: - t1.write('test') - s = path1.status() - # Comparing just the file names, because paths are unpredictable - # on Windows. (long vs. 8.3 paths) - assert t1.basename in [item.basename for item in s.unknown] - finally: - t1.localpath.remove() - - def test_status_unchanged(self, path1): - r = path1 - s = path1.status(rec=1) - # Comparing just the file names, because paths are unpredictable - # on Windows. (long vs. 8.3 paths) - assert r.join('samplefile').basename in [item.basename - for item in s.unchanged] - assert r.join('sampledir').basename in [item.basename - for item in s.unchanged] - assert r.join('sampledir/otherfile').basename in [item.basename - for item in s.unchanged] - - def test_status_update(self, path1): - r = path1 - try: - r.update(rev=1) - s = r.status(updates=1, rec=1) - # Comparing just the file names, because paths are unpredictable - # on Windows. (long vs. 8.3 paths) - assert r.join('anotherfile').basename in [item.basename for - item in s.update_available] - #assert len(s.update_available) == 1 - finally: - r.update() - - def test_status_replaced(self, path1): - p = path1.join("samplefile") - p.remove() - p.ensure(dir=0) - p.add() - try: - s = path1.status() - assert p.basename in [item.basename for item in s.replaced] - finally: - path1.revert(rec=1) - - def test_status_ignored(self, path1): - try: - d = path1.join('sampledir') - p = py.path.local(d).join('ignoredfile') - p.ensure(file=True) - s = d.status() - assert [x.basename for x in s.unknown] == ['ignoredfile'] - assert [x.basename for x in s.ignored] == [] - d.propset('svn:ignore', 'ignoredfile') - s = d.status() - assert [x.basename for x in s.unknown] == [] - assert [x.basename for x in s.ignored] == ['ignoredfile'] - finally: - path1.revert(rec=1) - - def test_status_conflict(self, path1, tmpdir): - wc = path1 - wccopy = py.path.svnwc(tmpdir.join("conflict_copy")) - wccopy.checkout(wc.url) - p = wc.ensure('conflictsamplefile', file=1) - p.write('foo') - wc.commit('added conflictsamplefile') - wccopy.update() - assert wccopy.join('conflictsamplefile').check() - p.write('bar') - wc.commit('wrote some data') - wccopy.join('conflictsamplefile').write('baz') - wccopy.update() - s = wccopy.status() - assert [x.basename for x in s.conflict] == ['conflictsamplefile'] - - def test_status_external(self, path1, repowc2): - otherrepo, otherwc = repowc2 - d = path1.ensure('sampledir', dir=1) - try: - d.remove() - d.add() - d.update() - d.propset('svn:externals', 'otherwc %s' % (otherwc.url,)) - d.update() - s = d.status() - assert [x.basename for x in s.external] == ['otherwc'] - assert 'otherwc' not in [x.basename for x in s.unchanged] - s = d.status(rec=1) - assert [x.basename for x in s.external] == ['otherwc'] - assert 'otherwc' in [x.basename for x in s.unchanged] - finally: - path1.revert(rec=1) - - def test_status_deleted(self, path1): - d = path1.ensure('sampledir', dir=1) - d.remove() - d.add() - path1.commit() - d.ensure('deletefile', dir=0) - d.commit() - s = d.status() - assert 'deletefile' in [x.basename for x in s.unchanged] - assert not s.deleted - p = d.join('deletefile') - p.remove() - s = d.status() - assert 'deletefile' not in s.unchanged - assert [x.basename for x in s.deleted] == ['deletefile'] - - def test_status_noauthor(self, path1): - # testing for XML without author - this used to raise an exception - xml = '''\ - - - - 2008-08-19T16:50:53.400198Z - - - - ''' - XMLWCStatus.fromstring(xml, path1) - - def test_status_wrong_xml(self, path1): - # testing for XML without author - this used to raise an exception - xml = '\n\n\n' - st = XMLWCStatus.fromstring(xml, path1) - assert len(st.incomplete) == 1 - - def test_diff(self, path1): - p = path1 / 'anotherfile' - out = p.diff(rev=2) - assert out.find('hello') != -1 - - def test_blame(self, path1): - p = path1.join('samplepickle') - lines = p.blame() - assert sum([l[0] for l in lines]) == len(lines) - for l1, l2 in zip(p.readlines(), [l[2] for l in lines]): - assert l1 == l2 - assert [l[1] for l in lines] == ['hpk'] * len(lines) - p = path1.join('samplefile') - lines = p.blame() - assert sum([l[0] for l in lines]) == len(lines) - for l1, l2 in zip(p.readlines(), [l[2] for l in lines]): - assert l1 == l2 - assert [l[1] for l in lines] == ['hpk'] * len(lines) - - def test_join_abs(self, path1): - s = str(path1.localpath) - n = path1.join(s, abs=1) - assert path1 == n - - def test_join_abs2(self, path1): - assert path1.join('samplefile', abs=1) == path1.join('samplefile') - - def test_str_gives_localpath(self, path1): - assert str(path1) == str(path1.localpath) - - def test_versioned(self, path1): - assert path1.check(versioned=1) - # TODO: Why does my copy of svn think .svn is versioned? - #assert path1.join('.svn').check(versioned=0) - assert path1.join('samplefile').check(versioned=1) - assert not path1.join('notexisting').check(versioned=1) - notexisting = path1.join('hello').localpath - try: - notexisting.write("") - assert path1.join('hello').check(versioned=0) - finally: - notexisting.remove() - - def test_nonversioned_remove(self, path1): - assert path1.check(versioned=1) - somefile = path1.join('nonversioned/somefile') - nonwc = py.path.local(somefile) - nonwc.ensure() - assert somefile.check() - assert not somefile.check(versioned=True) - somefile.remove() # this used to fail because it tried to 'svn rm' - - def test_properties(self, path1): - try: - path1.propset('gaga', 'this') - assert path1.propget('gaga') == 'this' - # Comparing just the file names, because paths are unpredictable - # on Windows. (long vs. 8.3 paths) - assert path1.basename in [item.basename for item in - path1.status().prop_modified] - assert 'gaga' in path1.proplist() - assert path1.proplist()['gaga'] == 'this' - - finally: - path1.propdel('gaga') - - def test_proplist_recursive(self, path1): - s = path1.join('samplefile') - s.propset('gugu', 'that') - try: - p = path1.proplist(rec=1) - # Comparing just the file names, because paths are unpredictable - # on Windows. (long vs. 8.3 paths) - assert (path1 / 'samplefile').basename in [item.basename - for item in p] - finally: - s.propdel('gugu') - - def test_long_properties(self, path1): - value = """ - vadm:posix : root root 0100755 - Properties on 'chroot/dns/var/bind/db.net.xots': - """ - try: - path1.propset('gaga', value) - backvalue = path1.propget('gaga') - assert backvalue == value - #assert len(backvalue.split('\n')) == 1 - finally: - path1.propdel('gaga') - - - def test_ensure(self, path1): - newpath = path1.ensure('a', 'b', 'c') - try: - assert newpath.check(exists=1, versioned=1) - newpath.write("hello") - newpath.ensure() - assert newpath.read() == "hello" - finally: - path1.join('a').remove(force=1) - - def test_not_versioned(self, path1): - p = path1.localpath.mkdir('whatever') - f = path1.localpath.ensure('testcreatedfile') - try: - assert path1.join('whatever').check(versioned=0) - assert path1.join('testcreatedfile').check(versioned=0) - assert not path1.join('testcreatedfile').check(versioned=1) - finally: - p.remove(rec=1) - f.remove() - - def test_lock_unlock(self, path1): - root = path1 - somefile = root.join('somefile') - somefile.ensure(file=True) - # not yet added to repo - py.test.raises(py.process.cmdexec.Error, 'somefile.lock()') - somefile.write('foo') - somefile.commit('test') - assert somefile.check(versioned=True) - somefile.lock() - try: - locked = root.status().locked - assert len(locked) == 1 - assert normpath(str(locked[0])) == normpath(str(somefile)) - #assert somefile.locked() - py.test.raises(Exception, 'somefile.lock()') - finally: - somefile.unlock() - #assert not somefile.locked() - locked = root.status().locked - assert locked == [] - py.test.raises(Exception, 'somefile,unlock()') - somefile.remove() - - def test_commit_nonrecursive(self, path1): - somedir = path1.join('sampledir') - somedir.mkdir("subsubdir") - somedir.propset('foo', 'bar') - status = somedir.status() - assert len(status.prop_modified) == 1 - assert len(status.added) == 1 - - somedir.commit('non-recursive commit', rec=0) - status = somedir.status() - assert len(status.prop_modified) == 0 - assert len(status.added) == 1 - - somedir.commit('recursive commit') - status = somedir.status() - assert len(status.prop_modified) == 0 - assert len(status.added) == 0 - - def test_commit_return_value(self, path1): - testfile = path1.join('test.txt').ensure(file=True) - testfile.write('test') - rev = path1.commit('testing') - assert type(rev) == int - - anotherfile = path1.join('another.txt').ensure(file=True) - anotherfile.write('test') - rev2 = path1.commit('testing more') - assert type(rev2) == int - assert rev2 == rev + 1 - - #def test_log(self, path1): - # l = path1.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, path1): - # path = tmpdir.join('checkouttest') - # wcpath = newpath(xsvnwc=str(path), url=path1url) - # try: - # wcpath.checkout(rev=2100) - # wcpath.update() - # assert wcpath.info().rev > 2100 - # finally: - # wcpath.localpath.remove(rec=1) - -def test_parse_wcinfotime(): - assert (parse_wcinfotime('2006-05-30 20:45:26 +0200 (Tue, 30 May 2006)') == - 1149021926) - assert (parse_wcinfotime('2003-10-27 20:43:14 +0100 (Mon, 27 Oct 2003)') == - 1067287394) - -class TestInfoSvnWCCommand: - - def test_svn_1_2(self, path1): - output = """ - Path: test_svnwc.py - Name: test_svnwc.py - URL: http://codespeak.net/svn/py/dist/py/path/svn/wccommand.py - Repository UUID: fd0d7bf2-dfb6-0310-8d31-b7ecfe96aada - Revision: 28137 - Node Kind: file - Schedule: normal - Last Changed Author: jan - Last Changed Rev: 27939 - Last Changed Date: 2006-05-30 20:45:26 +0200 (Tue, 30 May 2006) - Text Last Updated: 2006-06-01 00:42:53 +0200 (Thu, 01 Jun 2006) - Properties Last Updated: 2006-05-23 11:54:59 +0200 (Tue, 23 May 2006) - Checksum: 357e44880e5d80157cc5fbc3ce9822e3 - """ - path = py.path.local(__file__).dirpath().chdir() - try: - info = InfoSvnWCCommand(output) - finally: - path.chdir() - assert info.last_author == 'jan' - assert info.kind == 'file' - assert info.mtime == 1149021926.0 - assert info.url == 'http://codespeak.net/svn/py/dist/py/path/svn/wccommand.py' - assert info.time == 1149021926000000.0 - assert info.rev == 28137 - - - def test_svn_1_3(self, path1): - output = """ - Path: test_svnwc.py - Name: test_svnwc.py - URL: http://codespeak.net/svn/py/dist/py/path/svn/wccommand.py - Repository Root: http://codespeak.net/svn - Repository UUID: fd0d7bf2-dfb6-0310-8d31-b7ecfe96aada - Revision: 28124 - Node Kind: file - Schedule: normal - Last Changed Author: jan - Last Changed Rev: 27939 - Last Changed Date: 2006-05-30 20:45:26 +0200 (Tue, 30 May 2006) - Text Last Updated: 2006-06-02 23:46:11 +0200 (Fri, 02 Jun 2006) - Properties Last Updated: 2006-06-02 23:45:28 +0200 (Fri, 02 Jun 2006) - Checksum: 357e44880e5d80157cc5fbc3ce9822e3 - """ - path = py.path.local(__file__).dirpath().chdir() - try: - info = InfoSvnWCCommand(output) - finally: - path.chdir() - assert info.last_author == 'jan' - assert info.kind == 'file' - assert info.mtime == 1149021926.0 - assert info.url == 'http://codespeak.net/svn/py/dist/py/path/svn/wccommand.py' - assert info.rev == 28124 - assert info.time == 1149021926000000.0 - - -def test_characters_at(): - py.test.raises(ValueError, "py.path.svnwc('/tmp/@@@:')") - -def test_characters_tilde(): - py.path.svnwc('/tmp/test~') - - -class TestRepo: - def test_trailing_slash_is_stripped(self, path1): - # XXX we need to test more normalizing properties - url = path1.join("/") - assert path1 == url - - #def test_different_revs_compare_unequal(self, path1): - # newpath = path1.new(rev=1199) - # assert newpath != path1 - - def test_exists_svn_root(self, path1): - assert path1.check() - - #def test_not_exists_rev(self, path1): - # url = path1.__class__(path1url, rev=500) - # assert url.check(exists=0) - - #def test_nonexisting_listdir_rev(self, path1): - # url = path1.__class__(path1url, rev=500) - # raises(py.error.ENOENT, url.listdir) - - #def test_newrev(self, path1): - # url = path1.new(rev=None) - # assert url.rev == None - # assert url.strpath == path1.strpath - # url = path1.new(rev=10) - # assert url.rev == 10 - - #def test_info_rev(self, path1): - # url = path1.__class__(path1url, 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, path1): - repocache = svncommon.RepoCache() - repocache.put(path1.strpath, 42) - url, rev = repocache.get(path1.join('test').strpath) - assert rev == 42 - assert url == path1.strpath - - def test_repocache_notimeout(self, path1): - repocache = svncommon.RepoCache() - repocache.timeout = 0 - repocache.put(path1.strpath, path1.rev) - url, rev = repocache.get(path1.strpath) - assert rev == -1 - assert url == path1.strpath - - def test_repocache_outdated(self, path1): - repocache = svncommon.RepoCache() - repocache.put(path1.strpath, 42, timestamp=0) - url, rev = repocache.get(path1.join('test').strpath) - assert rev == -1 - assert url == path1.strpath - - def _test_getreporev(self): - """ this test runs so slow it's usually disabled """ - old = svncommon.repositories.repos - try: - _repocache.clear() - root = path1.new(rev=-1) - url, rev = cache.repocache.get(root.strpath) - assert rev>=0 - assert url == svnrepourl - finally: - repositories.repos = old --- a/py/_testing/test_xmlgen.py +++ /dev/null @@ -1,112 +0,0 @@ - -import py -from py.__.xmlgen import unicode, html - -class ns(py.xml.Namespace): - pass - -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()) - unicode(x) # triggers parentifying - 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 == '' - -def test_tag_with_text_entity(): - x = ns.hello('world & rest') - u = unicode(x) - assert u == "world & rest" - -def test_tag_with_text_and_attributes_entity(): - x = ns.some(name="hello & world") - assert x.attr.name == "hello & world" - u = unicode(x) - assert u == '' - -def test_raw(): - x = ns.some(py.xml.raw("

literal

")) - u = unicode(x) - assert u == "

literal

" - - -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_class_None(): - t = html.body(class_=None) - u = unicode(t) - assert u == '' - -def test_alternating_style(): - alternating = ( - html.Style(background="white"), - html.Style(background="grey"), - ) - class my(html): - class li(html.li): - def style(self): - i = self.parent.index(self) - return alternating[i%2] - style = property(style) - - x = my.ul( - my.li("hello"), - my.li("world"), - my.li("42")) - u = unicode(x) - assert u == ('
  • hello
  • ' - '
  • world
  • ' - '
  • 42
  • ' - '
') - -def test_singleton(): - h = html.head(html.link(href="foo")) - assert unicode(h) == '' - - h = html.head(html.script(src="foo")) - assert unicode(h) == '' - -def test_inline(): - h = html.div(html.span('foo'), html.span('bar')) - assert (h.unicode(indent=2) == - '
foobar
') - --- a/py/execnet/testing/test_xspec.py +++ /dev/null @@ -1,140 +0,0 @@ -import py - -XSpec = py.execnet.XSpec - -class TestXSpec: - def test_norm_attributes(self): - spec = XSpec("socket=192.168.102.2:8888//python=c:/this/python2.5//chdir=d:\hello") - assert spec.socket == "192.168.102.2:8888" - assert spec.python == "c:/this/python2.5" - assert spec.chdir == "d:\hello" - assert spec.nice is None - assert not hasattr(spec, 'xyz') - - py.test.raises(AttributeError, "spec._hello") - - spec = XSpec("socket=192.168.102.2:8888//python=python2.5//nice=3") - assert spec.socket == "192.168.102.2:8888" - assert spec.python == "python2.5" - assert spec.chdir is None - assert spec.nice == "3" - - spec = XSpec("ssh=user at host//chdir=/hello/this//python=/usr/bin/python2.5") - assert spec.ssh == "user at host" - assert spec.python == "/usr/bin/python2.5" - assert spec.chdir == "/hello/this" - - spec = XSpec("popen") - assert spec.popen == True - - def test__samefilesystem(self): - assert XSpec("popen")._samefilesystem() - assert XSpec("popen//python=123")._samefilesystem() - assert not XSpec("popen//chdir=hello")._samefilesystem() - - def test__spec_spec(self): - for x in ("popen", "popen//python=this"): - assert XSpec(x)._spec == x - - def test_repr_and_string(self): - for x in ("popen", "popen//python=this"): - assert repr(XSpec(x)).find("popen") != -1 - assert str(XSpec(x)) == x - - def test_hash_equality(self): - assert XSpec("popen") == XSpec("popen") - assert hash(XSpec("popen")) == hash(XSpec("popen")) - assert XSpec("popen//python=123") != XSpec("popen") - assert hash(XSpec("socket=hello:8080")) != hash(XSpec("popen")) - -class TestMakegateway: - def test_popen(self): - gw = py.execnet.makegateway("popen") - assert gw.spec.python == None - rinfo = gw._rinfo() - assert rinfo.executable == py.std.sys.executable - assert rinfo.cwd == py.std.os.getcwd() - assert rinfo.version_info == py.std.sys.version_info - - def test_popen_nice(self): - gw = py.execnet.makegateway("popen//nice=5") - remotenice = gw.remote_exec(""" - import os - if hasattr(os, 'nice'): - channel.send(os.nice(0)) - else: - channel.send(None) - """).receive() - if remotenice is not None: - assert remotenice == 5 - - def test_popen_explicit(self): - gw = py.execnet.makegateway("popen//python=%s" % py.std.sys.executable) - assert gw.spec.python == py.std.sys.executable - rinfo = gw._rinfo() - assert rinfo.executable == py.std.sys.executable - assert rinfo.cwd == py.std.os.getcwd() - assert rinfo.version_info == py.std.sys.version_info - - def test_popen_cpython24(self): - for trypath in ('python2.4', r'C:\Python24\python.exe'): - cpython24 = py.path.local.sysfind(trypath) - if cpython24 is not None: - cpython24 = cpython24.realpath() - break - else: - py.test.skip("cpython2.4 not found") - gw = py.execnet.makegateway("popen//python=%s" % cpython24) - rinfo = gw._rinfo() - if py.std.sys.platform != "darwin": # it's confusing there - assert rinfo.executable == cpython24 - assert rinfo.cwd == py.std.os.getcwd() - assert rinfo.version_info[:2] == (2,4) - - def test_popen_cpython26(self): - for trypath in ('python2.6', r'C:\Python26\python.exe'): - cpython26 = py.path.local.sysfind(trypath) - if cpython26 is not None: - break - else: - py.test.skip("cpython2.6 not found") - gw = py.execnet.makegateway("popen//python=%s" % cpython26) - rinfo = gw._rinfo() - assert rinfo.executable == cpython26 - assert rinfo.cwd == py.std.os.getcwd() - assert rinfo.version_info[:2] == (2,6) - - def test_popen_chdir_absolute(self, testdir): - gw = py.execnet.makegateway("popen//chdir=%s" % testdir.tmpdir) - rinfo = gw._rinfo() - assert rinfo.cwd == str(testdir.tmpdir.realpath()) - - def test_popen_chdir_newsub(self, testdir): - testdir.chdir() - gw = py.execnet.makegateway("popen//chdir=hello") - rinfo = gw._rinfo() - assert rinfo.cwd == str(testdir.tmpdir.join("hello").realpath()) - - def test_ssh(self, specssh): - sshhost = specssh.ssh - gw = py.execnet.makegateway("ssh=%s" % sshhost) - rinfo = gw._rinfo() - gw2 = py.execnet.SshGateway(sshhost) - rinfo2 = gw2._rinfo() - assert rinfo.executable == rinfo2.executable - assert rinfo.cwd == rinfo2.cwd - assert rinfo.version_info == rinfo2.version_info - - def test_socket(self, specsocket): - gw = py.execnet.makegateway("socket=%s" % specsocket.socket) - rinfo = gw._rinfo() - assert rinfo.executable - assert rinfo.cwd - assert rinfo.version_info - # we cannot instantiate a second gateway - - #gw2 = py.execnet.SocketGateway(*specsocket.socket.split(":")) - #rinfo2 = gw2._rinfo() - #assert rinfo.executable == rinfo2.executable - #assert rinfo.cwd == rinfo2.cwd - #assert rinfo.version_info == rinfo2.version_info --- a/py/cmdline/testing/test_convert_unittest.py +++ /dev/null @@ -1,413 +0,0 @@ -from py.__.cmdline.pyconvert_unittest import rewrite_utest - - -class Test_UTestConvert: - def testall(self): - assert rewrite_utest("badger badger badger") == ( - "badger badger badger") - - assert rewrite_utest( - "self.assertRaises(excClass, callableObj, *args, **kwargs)" - ) == ( - "raises(excClass, callableObj, *args, **kwargs)" - ) - - assert rewrite_utest( - """ - self.failUnlessRaises(TypeError, func, 42, **{'arg1': 23}) - """ - ) == ( - """ - raises(TypeError, func, 42, **{'arg1': 23}) - """ - ) - assert rewrite_utest( - """ - self.assertRaises(TypeError, - func, - mushroom) - """ - ) == ( - """ - raises(TypeError, - func, - mushroom) - """ - ) - assert rewrite_utest("self.fail()") == "raise AssertionError" - assert rewrite_utest("self.fail('mushroom, mushroom')") == ( - "raise AssertionError, 'mushroom, mushroom'") - assert rewrite_utest("self.assert_(x)") == "assert x" - assert rewrite_utest("self.failUnless(func(x)) # XXX") == ( - "assert func(x) # XXX") - - assert rewrite_utest( - """ - self.assert_(1 + f(y) - + z) # multiline, keep parentheses - """ - ) == ( - """ - assert (1 + f(y) - + z) # multiline, keep parentheses - """ - ) - - assert rewrite_utest("self.assert_(0, 'badger badger')") == ( - "assert 0, 'badger badger'") - - assert rewrite_utest("self.assert_(0, '''badger badger''')") == ( - "assert 0, '''badger badger'''") - - assert rewrite_utest( - r""" - self.assert_(0, - 'Meet the badger.\n') - """ - ) == ( - r""" - assert 0, ( - 'Meet the badger.\n') - """ - ) - - assert rewrite_utest( - r""" - self.failIf(0 + 0 - + len('badger\n') - + 0, '''badger badger badger badger - mushroom mushroom - Snake! Ooh a snake! - ''') # multiline, must move the parens - """ - ) == ( - r""" - assert not (0 + 0 - + len('badger\n') - + 0), '''badger badger badger badger - mushroom mushroom - Snake! Ooh a snake! - ''' # multiline, must move the parens - """ - ) - - assert rewrite_utest("self.assertEquals(0, 0)") == ( - "assert 0 == 0") - - assert rewrite_utest( - r""" - self.assertEquals(0, - 'Run away from the snake.\n') - """ - ) == ( - r""" - assert 0 == ( - 'Run away from the snake.\n') - """ - ) - - assert rewrite_utest( - """ - self.assertEquals(badger + 0 - + mushroom - + snake, 0) - """ - ) == ( - """ - assert (badger + 0 - + mushroom - + snake) == 0 - """ - ) - - assert rewrite_utest( - """ - self.assertNotEquals(badger + 0 - + mushroom - + snake, - mushroom - - badger) - """ - ) == ( - """ - assert (badger + 0 - + mushroom - + snake) != ( - mushroom - - badger) - """ - ) - - assert rewrite_utest( - """ - self.assertEquals(badger(), - mushroom() - + snake(mushroom) - - badger()) - """ - ) == ( - """ - assert badger() == ( - mushroom() - + snake(mushroom) - - badger()) - """ - ) - assert rewrite_utest("self.failIfEqual(0, 0)") == ( - "assert not 0 == 0") - - assert rewrite_utest("self.failUnlessEqual(0, 0)") == ( - "assert 0 == 0") - - assert rewrite_utest( - """ - self.failUnlessEqual(mushroom() - + mushroom() - + mushroom(), '''badger badger badger - badger badger badger badger - badger badger badger badger - ''') # multiline, must move the parens - """ - ) == ( - """ - assert (mushroom() - + mushroom() - + mushroom()) == '''badger badger badger - badger badger badger badger - badger badger badger badger - ''' # multiline, must move the parens - """ - ) - - - assert rewrite_utest( - """ - self.assertEquals('''snake snake snake - snake snake snake''', mushroom) - """ - ) == ( - """ - assert '''snake snake snake - snake snake snake''' == mushroom - """ - ) - - assert rewrite_utest( - """ - self.assertEquals(badger(), - snake(), 'BAD BADGER') - """ - ) == ( - """ - assert badger() == ( - snake()), 'BAD BADGER' - """ - ) - - assert rewrite_utest( - """ - self.assertNotEquals(badger(), - snake()+ - snake(), 'POISONOUS MUSHROOM!\ - Ai! I ate a POISONOUS MUSHROOM!!') - """ - ) == ( - """ - assert badger() != ( - snake()+ - snake()), 'POISONOUS MUSHROOM!\ - Ai! I ate a POISONOUS MUSHROOM!!' - """ - ) - - assert rewrite_utest( - """ - self.assertEquals(badger(), - snake(), '''BAD BADGER - BAD BADGER - BAD BADGER''' - ) - """ - ) == ( - """ - assert badger() == ( - snake()), ( '''BAD BADGER - BAD BADGER - BAD BADGER''' - ) - """ - ) - - assert rewrite_utest( - """ - self.assertEquals('''BAD BADGER - BAD BADGER - BAD BADGER''', '''BAD BADGER - BAD BADGER - BAD BADGER''') - """ - ) == ( - """ - assert '''BAD BADGER - BAD BADGER - BAD BADGER''' == '''BAD BADGER - BAD BADGER - BAD BADGER''' - """ - ) - - assert rewrite_utest( - """ - self.assertEquals('''GOOD MUSHROOM - GOOD MUSHROOM - GOOD MUSHROOM''', - '''GOOD MUSHROOM - GOOD MUSHROOM - GOOD MUSHROOM''', - ''' FAILURE - FAILURE - FAILURE''') - """ - ) == ( - """ - assert '''GOOD MUSHROOM - GOOD MUSHROOM - GOOD MUSHROOM''' == ( - '''GOOD MUSHROOM - GOOD MUSHROOM - GOOD MUSHROOM'''), ( - ''' FAILURE - FAILURE - FAILURE''') - """ - ) - - assert rewrite_utest( - """ - self.assertAlmostEquals(first, second, 5, 'A Snake!') - """ - ) == ( - """ - assert round(first - second, 5) == 0, 'A Snake!' - """ - ) - - assert rewrite_utest( - """ - self.assertAlmostEquals(first, second, 120) - """ - ) == ( - """ - assert round(first - second, 120) == 0 - """ - ) - - assert rewrite_utest( - """ - self.assertAlmostEquals(first, second) - """ - ) == ( - """ - assert round(first - second, 7) == 0 - """ - ) - - assert rewrite_utest( - """ - self.assertAlmostEqual(first, second, 5, '''A Snake! - Ohh A Snake! A Snake!! - ''') - """ - ) == ( - """ - assert round(first - second, 5) == 0, '''A Snake! - Ohh A Snake! A Snake!! - ''' - """ - ) - - assert rewrite_utest( - """ - self.assertNotAlmostEqual(first, second, 5, 'A Snake!') - """ - ) == ( - """ - assert round(first - second, 5) != 0, 'A Snake!' - """ - ) - - assert rewrite_utest( - """ - self.failIfAlmostEqual(first, second, 5, 'A Snake!') - """ - ) == ( - """ - assert not round(first - second, 5) == 0, 'A Snake!' - """ - ) - - assert rewrite_utest( - """ - self.failIfAlmostEqual(first, second, 5, 6, 7, 'Too Many Args') - """ - ) == ( - """ - self.failIfAlmostEqual(first, second, 5, 6, 7, 'Too Many Args') - """ - ) - - assert rewrite_utest( - """ - self.failUnlessAlmostEquals(first, second, 5, 'A Snake!') - """ - ) == ( - """ - assert round(first - second, 5) == 0, 'A Snake!' - """ - ) - - assert rewrite_utest( - """ - self.assertAlmostEquals(now do something reasonable ..() - oops, I am inside a comment as a ''' string, and the fname was - mentioned in passing, leaving us with something that isn't an - expression ... will this blow up? - """ - ) == ( - """ - self.assertAlmostEquals(now do something reasonable ..() - oops, I am inside a comment as a ''' string, and the fname was - mentioned in passing, leaving us with something that isn't an - expression ... will this blow up? - """ - ) - - assert rewrite_utest( - """ - self.failUnless('__builtin__' in modules, "An entry for __builtin__ " - "is not in sys.modules.") - """ - ) == ( - """ - assert '__builtin__' in modules, ( "An entry for __builtin__ " - "is not in sys.modules.") - """ - ) - - # two unittests on the same line separated by a semi-colon is - # only half-converted. Just so you know. - assert rewrite_utest( - """ - self.assertEquals(0, 0); self.assertEquals(1, 1) #not 2 per line! - """ - ) == ( - """ - assert 0 == 0; self.assertEquals(1, 1) #not 2 per line! - """ - ) - - -if __name__ == '__main__': - unittest.main() - - --- a/py/io/testing/test_capture.py +++ /dev/null @@ -1,321 +0,0 @@ -import os, sys -import py - -from py.builtin import print_ - -if sys.version_info >= (3,0): - def tobytes(obj): - if isinstance(obj, str): - obj = obj.encode('UTF-8') - assert isinstance(obj, bytes) - return obj - def totext(obj): - if isinstance(obj, bytes): - obj = str(obj, 'UTF-8') - assert isinstance(obj, str) - return obj -else: - def tobytes(obj): - if isinstance(obj, unicode): - obj = obj.encode('UTF-8') - assert isinstance(obj, str) - return obj - def totext(obj): - if isinstance(obj, str): - obj = unicode(obj, 'UTF-8') - assert isinstance(obj, unicode) - return obj - -def oswritebytes(fd, obj): - os.write(fd, tobytes(obj)) - -class TestTextIO: - def test_text(self): - f = py.io.TextIO() - f.write("hello") - s = f.getvalue() - assert s == "hello" - f.close() - - def test_unicode_and_str_mixture(self): - f = py.io.TextIO() - if sys.version_info >= (3,0): - f.write("\u00f6") - py.test.skip("3k IO beahviour?") - f.write(bytes("hello", 'UTF-8')) - else: - f.write(unicode("\u00f6", 'UTF-8')) - f.write("hello") # bytes - s = f.getvalue() - f.close() - assert isinstance(s, unicode) - -def test_bytes_io(): - f = py.io.BytesIO() - f.write(tobytes("hello")) - py.test.raises(TypeError, "f.write(totext('hello'))") - s = f.getvalue() - assert s == tobytes("hello") - -def test_dontreadfrominput(): - from py.__.io.capture import DontReadFromInput - f = DontReadFromInput() - assert not f.isatty() - py.test.raises(IOError, f.read) - py.test.raises(IOError, f.readlines) - py.test.raises(IOError, iter, f) - py.test.raises(ValueError, f.fileno) - -def pytest_funcarg__tmpfile(request): - testdir = request.getfuncargvalue("testdir") - f = testdir.makepyfile("").open('wb+') - request.addfinalizer(f.close) - return f - -def test_dupfile(tmpfile): - somefile = tmpfile - flist = [] - for i in range(5): - nf = py.io.dupfile(somefile) - assert nf != somefile - assert nf.fileno() != somefile.fileno() - assert nf not in flist - print_(i, end="", file=nf) - flist.append(nf) - for i in range(5): - f = flist[i] - f.close() - somefile.seek(0) - s = somefile.read() - assert "01234" in repr(s) - somefile.close() - -class TestFDCapture: - def test_stdout(self, tmpfile): - fd = tmpfile.fileno() - cap = py.io.FDCapture(fd) - data = tobytes("hello") - os.write(fd, data) - f = cap.done() - s = f.read() - assert s == "hello" - - def test_stderr(self): - cap = py.io.FDCapture(2) - cap.setasfile('stderr') - print_("hello", file=sys.stderr) - f = cap.done() - s = f.read() - assert s == "hello\n" - - def test_stdin(self, tmpfile): - tmpfile.write(tobytes("3")) - tmpfile.seek(0) - cap = py.io.FDCapture(0, tmpfile=tmpfile) - # check with os.read() directly instead of raw_input(), because - # sys.stdin itself may be redirected (as py.test now does by default) - x = os.read(0, 100).strip() - f = cap.done() - assert x == tobytes("3") - - def test_writeorg(self, tmpfile): - data1, data2 = tobytes("foo"), tobytes("bar") - try: - cap = py.io.FDCapture(tmpfile.fileno()) - tmpfile.write(data1) - cap.writeorg(data2) - finally: - tmpfile.close() - f = cap.done() - scap = f.read() - assert scap == totext(data1) - stmp = open(tmpfile.name, 'rb').read() - assert stmp == data2 - - -class TestStdCapture: - def getcapture(self, **kw): - return py.io.StdCapture(**kw) - - def test_capturing_done_simple(self): - cap = self.getcapture() - sys.stdout.write("hello") - sys.stderr.write("world") - outfile, errfile = cap.done() - s = outfile.read() - assert s == "hello" - s = errfile.read() - assert s == "world" - - def test_capturing_reset_simple(self): - cap = self.getcapture() - print("hello world") - sys.stderr.write("hello error\n") - out, err = cap.reset() - assert out == "hello world\n" - assert err == "hello error\n" - - def test_capturing_readouterr(self): - cap = self.getcapture() - try: - print ("hello world") - sys.stderr.write("hello error\n") - out, err = cap.readouterr() - assert out == "hello world\n" - assert err == "hello error\n" - sys.stderr.write("error2") - finally: - out, err = cap.reset() - assert err == "error2" - - def test_capturing_mixed(self): - cap = self.getcapture(mixed=True) - sys.stdout.write("hello ") - sys.stderr.write("world") - sys.stdout.write(".") - out, err = cap.reset() - assert out.strip() == "hello world." - assert not err - - def test_capturing_twice_error(self): - cap = self.getcapture() - print ("hello") - cap.reset() - py.test.raises(Exception, "cap.reset()") - - def test_capturing_modify_sysouterr_in_between(self): - oldout = sys.stdout - olderr = sys.stderr - cap = self.getcapture() - sys.stdout.write("hello") - sys.stderr.write("world") - sys.stdout = py.io.TextIO() - sys.stderr = py.io.TextIO() - print ("not seen" ) - sys.stderr.write("not seen\n") - out, err = cap.reset() - assert out == "hello" - assert err == "world" - assert sys.stdout == oldout - assert sys.stderr == olderr - - def test_capturing_error_recursive(self): - cap1 = self.getcapture() - print ("cap1") - cap2 = self.getcapture() - print ("cap2") - out2, err2 = cap2.reset() - py.test.raises(Exception, "cap2.reset()") - out1, err1 = cap1.reset() - assert out1 == "cap1\n" - assert out2 == "cap2\n" - - def test_just_out_capture(self): - cap = self.getcapture(out=True, err=False) - sys.stdout.write("hello") - sys.stderr.write("world") - out, err = cap.reset() - assert out == "hello" - assert not err - - def test_just_err_capture(self): - cap = self.getcapture(out=False, err=True) - sys.stdout.write("hello") - sys.stderr.write("world") - out, err = cap.reset() - assert err == "world" - assert not out - - def test_stdin_restored(self): - old = sys.stdin - cap = self.getcapture(in_=True) - newstdin = sys.stdin - out, err = cap.reset() - assert newstdin != sys.stdin - assert sys.stdin is old - - def test_stdin_nulled_by_default(self): - print ("XXX this test may well hang instead of crashing") - print ("XXX which indicates an error in the underlying capturing") - print ("XXX mechanisms" ) - cap = self.getcapture() - py.test.raises(IOError, "sys.stdin.read()") - out, err = cap.reset() - - def test_suspend_resume(self): - cap = self.getcapture(out=True, err=False, in_=False) - try: - print ("hello") - sys.stderr.write("error\n") - out, err = cap.suspend() - assert out == "hello\n" - assert not err - print ("in between") - sys.stderr.write("in between\n") - cap.resume() - print ("after") - sys.stderr.write("error_after\n") - finally: - out, err = cap.reset() - assert out == "after\n" - assert not err - -class TestStdCaptureFD(TestStdCapture): - def getcapture(self, **kw): - return py.io.StdCaptureFD(**kw) - - def test_intermingling(self): - cap = self.getcapture() - oswritebytes(1, "1") - sys.stdout.write(str(2)) - sys.stdout.flush() - oswritebytes(1, "3") - oswritebytes(2, "a") - sys.stderr.write("b") - sys.stderr.flush() - oswritebytes(2, "c") - out, err = cap.reset() - assert out == "123" - assert err == "abc" - - def test_callcapture(self): - def func(x, y): - print (x) - py.std.sys.stderr.write(str(y)) - return 42 - - res, out, err = py.io.StdCaptureFD.call(func, 3, y=4) - assert res == 42 - assert out.startswith("3") - assert err.startswith("4") - -def test_capture_no_sys(): - capsys = py.io.StdCapture() - try: - cap = py.io.StdCaptureFD(patchsys=False) - sys.stdout.write("hello") - sys.stderr.write("world") - oswritebytes(1, "1") - oswritebytes(2, "2") - out, err = cap.reset() - assert out == "1" - assert err == "2" - finally: - capsys.reset() - -def test_callcapture_nofd(): - def func(x, y): - oswritebytes(1, "hello") - oswritebytes(2, "hello") - print (x) - sys.stderr.write(str(y)) - return 42 - - capfd = py.io.StdCaptureFD(patchsys=False) - try: - res, out, err = py.io.StdCapture.call(func, 3, y=4) - finally: - capfd.reset() - assert res == 42 - assert out.startswith("3") - assert err.startswith("4") --- a/py/execnet/testing/test_multi.py +++ /dev/null @@ -1,58 +0,0 @@ -""" - tests for - - multi channels and multi gateways - -""" - -import py - -class TestMultiChannelAndGateway: - def test_multichannel_receive_each(self): - class pseudochannel: - def receive(self): - return 12 - - pc1 = pseudochannel() - pc2 = pseudochannel() - multichannel = py.execnet.MultiChannel([pc1, pc2]) - l = multichannel.receive_each(withchannel=True) - assert len(l) == 2 - assert l == [(pc1, 12), (pc2, 12)] - l = multichannel.receive_each(withchannel=False) - assert l == [12,12] - - def test_multichannel_send_each(self): - l = [py.execnet.PopenGateway() for x in range(2)] - gm = py.execnet.MultiGateway(l) - mc = gm.remote_exec(""" - import os - channel.send(channel.receive() + 1) - """) - mc.send_each(41) - l = mc.receive_each() - assert l == [42,42] - - def test_multichannel_receive_queue_for_two_subprocesses(self): - l = [py.execnet.PopenGateway() for x in range(2)] - gm = py.execnet.MultiGateway(l) - mc = gm.remote_exec(""" - import os - channel.send(os.getpid()) - """) - queue = mc.make_receive_queue() - ch, item = queue.get(timeout=10) - ch2, item2 = queue.get(timeout=10) - assert ch != ch2 - assert ch.gateway != ch2.gateway - assert item != item2 - mc.waitclose() - - def test_multichannel_waitclose(self): - l = [] - class pseudochannel: - def waitclose(self): - l.append(0) - multichannel = py.execnet.MultiChannel([pseudochannel(), pseudochannel()]) - multichannel.waitclose() - assert len(l) == 2 - --- a/py/_testing/test_api.py +++ /dev/null @@ -1,6 +0,0 @@ - -from py.test import raises -import py -import sys -import inspect - --- a/py/builtin/testing/test_builtin.py +++ /dev/null @@ -1,148 +0,0 @@ -import sys -import py -from py.builtin import set, frozenset, reversed, sorted - -def test_enumerate(): - l = [0,1,2] - for i,x in enumerate(l): - assert i == x - -def test_BaseException(): - assert issubclass(IndexError, py.builtin.BaseException) - assert issubclass(Exception, py.builtin.BaseException) - assert issubclass(KeyboardInterrupt, py.builtin.BaseException) - - class MyRandomClass(object): - pass - assert not issubclass(MyRandomClass, py.builtin.BaseException) - - assert py.builtin.BaseException.__module__ in ('exceptions', 'builtins') - assert Exception.__name__ == 'Exception' - - -def test_GeneratorExit(): - assert py.builtin.GeneratorExit.__module__ in ('exceptions', 'builtins') - assert issubclass(py.builtin.GeneratorExit, py.builtin.BaseException) - -def test_reversed(): - reversed = py.builtin.reversed - r = reversed("hello") - assert iter(r) is r - s = "".join(list(r)) - assert s == "olleh" - assert list(reversed(list(reversed("hello")))) == ['h','e','l','l','o'] - py.test.raises(TypeError, reversed, reversed("hello")) - -def test_simple(): - s = set([1, 2, 3, 4]) - assert s == set([3, 4, 2, 1]) - s1 = s.union(set([5, 6])) - assert 5 in s1 - assert 1 in s1 - -def test_frozenset(): - s = set([frozenset([0, 1]), frozenset([1, 0])]) - assert len(s) == 1 - -def test_sorted(): - if sorted == py.builtin.sorted: - return # don't test a real builtin - for s in [py.builtin.sorted]: - def test(): - assert s([3, 2, 1]) == [1, 2, 3] - assert s([1, 2, 3], reverse=True) == [3, 2, 1] - l = s([1, 2, 3, 4, 5, 6], key=lambda x: x % 2) - assert l == [2, 4, 6, 1, 3, 5] - l = s([1, 2, 3, 4], cmp=lambda x, y: -cmp(x, y)) - assert l == [4, 3, 2, 1] - l = s([1, 2, 3, 4], cmp=lambda x, y: -cmp(x, y), - key=lambda x: x % 2) - assert l == [1, 3, 2, 4] - - def compare(x, y): - assert type(x) == str - assert type(y) == str - return cmp(x, y) - data = 'The quick Brown fox Jumped over The lazy Dog'.split() - s(data, cmp=compare, key=str.lower) - yield test - - -def test_print_simple(): - from py.builtin import print_ - py.test.raises(TypeError, "print_(hello=3)") - f = py.io.TextIO() - print_("hello", "world", file=f) - s = f.getvalue() - assert s == "hello world\n" - - f = py.io.TextIO() - print_("hello", end="", file=f) - s = f.getvalue() - assert s == "hello" - - f = py.io.TextIO() - print_("xyz", "abc", sep="", end="", file=f) - s = f.getvalue() - assert s == "xyzabc" - - class X: - def __repr__(self): return "rep" - f = py.io.TextIO() - print_(X(), file=f) - assert f.getvalue() == "rep\n" - -def test_execfile(tmpdir): - test_file = tmpdir.join("test.py") - test_file.write("x = y\ndef f(): pass") - ns = {"y" : 42} - py.builtin.execfile(str(test_file), ns) - assert ns["x"] == 42 - assert py.code.getrawcode(ns["f"]).co_filename == str(test_file) - class A: - y = 3 - x = 4 - py.builtin.execfile(str(test_file)) - assert A.x == 3 - -def test_getfuncdict(): - def f(): - pass - f.x = 4 - assert py.builtin._getfuncdict(f)["x"] == 4 - assert py.builtin._getfuncdict(2) is None - -def test_callable(): - class A: pass - assert py.builtin.callable(test_callable) - assert py.builtin.callable(A) - assert py.builtin.callable(list) - assert py.builtin.callable(id) - assert not py.builtin.callable(4) - assert not py.builtin.callable("hi") - -def test_totext(): - py.builtin._totext("hello", "UTF-8") - -def test_reraise(): - from py.builtin import _reraise - try: - raise Exception() - except Exception: - cls, val, tb = sys.exc_info() - excinfo = py.test.raises(Exception, "_reraise(cls, val, tb)") - -def test_exec(): - l = [] - py.builtin.exec_("l.append(1)") - assert l == [1] - d = {} - py.builtin.exec_("x=4", d) - assert d['x'] == 4 - -def test_tryimport(): - py.test.raises(ImportError, py.builtin._tryimport, 'xqwe123') - x = py.builtin._tryimport('asldkajsdl', 'py') - assert x == py - x = py.builtin._tryimport('asldkajsdl', 'py.path') - assert x == py.path --- a/py/_testing/check_compile.py +++ /dev/null @@ -1,13 +0,0 @@ -import sys - -def main(fn): - print("Testing %s" % (fn,)) - fp = open(fn, "rb") - try: - source = fp.read() - finally: - fp.close() - compile(source, fn, "exec") - -if __name__ == "__main__": - main(sys.argv[1]) --- a/py/code/testing/test_frame.py +++ /dev/null @@ -1,2 +0,0 @@ -import sys -import py --- a/doc/code.txt +++ b/doc/code.txt @@ -46,7 +46,7 @@ A quick example:: >>> isinstance(c.source(), py.code.Source) True >>> str(c.source()).split('\n')[0] - "def read(self, mode='rb'):" + "def read(self, mode='r'):" source: :source:`py/code/code.py` --- a/py/compat/testing/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -# --- a/py/execnet/testing/test_rsync.py +++ /dev/null @@ -1,148 +0,0 @@ -import py -from py.execnet import RSync - - -def pytest_funcarg__gw1(request): - return request.cached_setup( - setup=py.execnet.PopenGateway, - teardown=lambda val: val.exit(), - scope="module" - ) -pytest_funcarg__gw2 = pytest_funcarg__gw1 - -def pytest_funcarg__dirs(request): - t = request.getfuncargvalue('tmpdir') - class dirs: - source = t.join("source") - dest1 = t.join("dest1") - dest2 = t.join("dest2") - return dirs - -class TestRSync: - def test_notargets(self, dirs): - rsync = RSync(dirs.source) - py.test.raises(IOError, "rsync.send()") - assert rsync.send(raises=False) is None - - def test_dirsync(self, dirs, gw1, gw2): - dest = dirs.dest1 - dest2 = dirs.dest2 - source = dirs.source - - for s in ('content1', 'content2', 'content2-a-bit-longer'): - source.ensure('subdir', 'file1').write(s) - rsync = RSync(dirs.source) - rsync.add_target(gw1, dest) - rsync.add_target(gw2, dest2) - rsync.send() - assert dest.join('subdir').check(dir=1) - assert dest.join('subdir', 'file1').check(file=1) - assert dest.join('subdir', 'file1').read() == s - assert dest2.join('subdir').check(dir=1) - assert dest2.join('subdir', 'file1').check(file=1) - assert dest2.join('subdir', 'file1').read() == s - for x in dest, dest2: - fn = x.join("subdir", "file1") - fn.setmtime(0) - - source.join('subdir').remove('file1') - rsync = RSync(source) - rsync.add_target(gw2, dest2) - rsync.add_target(gw1, dest) - rsync.send() - assert dest.join('subdir', 'file1').check(file=1) - assert dest2.join('subdir', 'file1').check(file=1) - rsync = RSync(source) - rsync.add_target(gw1, dest, delete=True) - rsync.add_target(gw2, dest2) - rsync.send() - assert not dest.join('subdir', 'file1').check() - assert dest2.join('subdir', 'file1').check() - - def test_dirsync_twice(self, dirs, gw1, gw2): - source = dirs.source - source.ensure("hello") - rsync = RSync(source) - rsync.add_target(gw1, dirs.dest1) - rsync.send() - assert dirs.dest1.join('hello').check() - py.test.raises(IOError, "rsync.send()") - assert rsync.send(raises=False) is None - rsync.add_target(gw1, dirs.dest2) - rsync.send() - assert dirs.dest2.join('hello').check() - py.test.raises(IOError, "rsync.send()") - assert rsync.send(raises=False) is None - - def test_rsync_default_reporting(self, capsys, dirs, gw1): - source = dirs.source - source.ensure("hello") - rsync = RSync(source) - rsync.add_target(gw1, dirs.dest1) - rsync.send() - out, err = capsys.readouterr() - assert out.find("hello") != -1 - - def test_rsync_non_verbose(self, capsys, dirs, gw1): - source = dirs.source - source.ensure("hello") - rsync = RSync(source, verbose=False) - rsync.add_target(gw1, dirs.dest1) - rsync.send() - out, err = capsys.readouterr() - assert not out - assert not err - - def test_symlink_rsync(self, dirs, gw1): - if py.std.sys.platform == 'win32': - py.test.skip("symlinks are unsupported on Windows.") - source = dirs.source - dest = dirs.dest1 - dirs.source.ensure("existant") - source.join("rellink").mksymlinkto(source.join("existant"), absolute=0) - source.join('abslink').mksymlinkto(source.join("existant")) - - rsync = RSync(source) - rsync.add_target(gw1, dest) - rsync.send() - - assert dest.join('rellink').readlink() == dest.join("existant") - assert dest.join('abslink').readlink() == dest.join("existant") - - def test_callback(self, dirs, gw1): - dest = dirs.dest1 - source = dirs.source - source.ensure("existant").write("a" * 100) - source.ensure("existant2").write("a" * 10) - total = {} - def callback(cmd, lgt, channel): - total[(cmd, lgt)] = True - - rsync = RSync(source, callback=callback) - #rsync = RSync() - rsync.add_target(gw1, dest) - rsync.send() - - assert total == {("list", 110):True, ("ack", 100):True, ("ack", 10):True} - - def test_file_disappearing(self, dirs, gw1): - dest = dirs.dest1 - source = dirs.source - source.ensure("ex").write("a" * 100) - source.ensure("ex2").write("a" * 100) - - class DRsync(RSync): - def filter(self, x): - assert x != source - if x.endswith("ex2"): - self.x = 1 - source.join("ex2").remove() - return True - - rsync = DRsync(source) - rsync.add_target(gw1, dest) - rsync.send() - assert rsync.x == 1 - assert len(dest.listdir()) == 1 - assert len(source.listdir()) == 1 - --- a/py/path/testing/conftest.py +++ /dev/null @@ -1,73 +0,0 @@ -import py -from py.__.path import svnwc as svncommon - -svnbin = py.path.local.sysfind('svn') -repodump = py.path.local(__file__).dirpath('repotest.dump') -from py.builtin import print_ - -def pytest_funcarg__repowc1(request): - if svnbin is None: - py.test.skip("svn binary not found") - - modname = request.module.__name__ - tmpdir = request.getfuncargvalue("tmpdir") - repo, wc = request.cached_setup( - setup=lambda: getrepowc(tmpdir, "repo-"+modname, "wc-" + modname), - scope="module", - ) - for x in ('test_remove', 'test_move', 'test_status_deleted'): - if request.function.__name__.startswith(x): - _savedrepowc = save_repowc(repo, wc) - request.addfinalizer(lambda: restore_repowc(_savedrepowc)) - return repo, wc - -def pytest_funcarg__repowc2(request): - tmpdir = request.getfuncargvalue("tmpdir") - name = request.function.__name__ - return getrepowc(tmpdir, "%s-repo-2" % name, "%s-wc-2" % name) - -def getsvnbin(): - if svnbin is None: - py.test.skip("svn binary not found") - return svnbin - -# make a wc directory out of a given root url -# cache previously obtained wcs! -# -def getrepowc(tmpdir, reponame='basetestrepo', wcname='wc'): - repo = tmpdir.mkdir(reponame) - wcdir = tmpdir.mkdir(wcname) - repo.ensure(dir=1) - py.process.cmdexec('svnadmin create "%s"' % - svncommon._escape_helper(repo)) - py.process.cmdexec('svnadmin load -q "%s" <"%s"' % - (svncommon._escape_helper(repo), repodump)) - print_("created svn repository", repo) - wcdir.ensure(dir=1) - wc = py.path.svnwc(wcdir) - if py.std.sys.platform == 'win32': - repo = '/' + str(repo).replace('\\', '/') - wc.checkout(url='file://%s' % repo) - print_("checked out new repo into", wc) - return ("file://%s" % repo, wc) - - -def save_repowc(repo, wc): - repo = py.path.local(repo[len("file://"):]) - assert repo.check() - savedrepo = repo.dirpath(repo.basename+".1") - savedwc = wc.dirpath(wc.basename+".1") - repo.copy(savedrepo) - wc.localpath.copy(savedwc.localpath) - return savedrepo, savedwc - -def restore_repowc(obj): - savedrepo, savedwc = obj - repo = savedrepo.new(basename=savedrepo.basename[:-2]) - assert repo.check() - wc = savedwc.new(basename=savedwc.basename[:-2]) - assert wc.check() - wc.localpath.remove() - repo.remove() - savedrepo.move(repo) - savedwc.localpath.move(wc.localpath) --- a/py/execnet/testing/test_gateway.py +++ /dev/null @@ -1,566 +0,0 @@ -from __future__ import generators -import os, sys, time -import py -from py.__.execnet import gateway_base, gateway -queue = py.builtin._tryimport('queue', 'Queue') - -pytest_plugins = "pytester" - -TESTTIMEOUT = 10.0 # seconds - -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._receiverthread.isAlive() - - def test_repr_doesnt_crash(self): - assert isinstance(repr(self.gw), str) - - def test_attribute__name__(self): - channel = self.gw.remote_exec("channel.send(__name__)") - name = channel.receive() - assert name == "__channelexec__" - - def test_correct_setup_no_py(self): - channel = self.gw.remote_exec(""" - import sys - channel.send(list(sys.modules)) - """) - remotemodules = channel.receive() - assert 'py' not in remotemodules, ( - "py should not be imported on remote side") - - def test_remote_exec_waitclose(self): - channel = self.gw.remote_exec('pass') - channel.waitclose(TESTTIMEOUT) - - def test_remote_exec_waitclose_2(self): - channel = self.gw.remote_exec('def gccycle(): pass') - channel.waitclose(TESTTIMEOUT) - - def test_remote_exec_waitclose_noarg(self): - channel = self.gw.remote_exec('pass') - channel.waitclose() - - def test_remote_exec_error_after_close(self): - channel = self.gw.remote_exec('pass') - channel.waitclose(TESTTIMEOUT) - py.test.raises(IOError, channel.send, 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(channel.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() - assert x == 42 - py.test.raises(channel.RemoteError, channel.receive) - - def test_channel__local_close(self): - channel = self.gw._channelfactory.new() - self.gw._channelfactory._local_close(channel.id) - channel.waitclose(0.1) - - def test_channel__local_close_error(self): - channel = self.gw._channelfactory.new() - self.gw._channelfactory._local_close(channel.id, - channel.RemoteError("error")) - py.test.raises(channel.RemoteError, channel.waitclose, 0.01) - - def test_channel_error_reporting(self): - channel = self.gw.remote_exec('def foo():\n return foobar()\nfoo()\n') - try: - channel.receive() - except channel.RemoteError: - e = sys.exc_info()[1] - assert str(e).startswith('Traceback (most recent call last):') - assert str(e).find('NameError: global name \'foobar\' ' - 'is not defined') > -1 - else: - py.test.fail('No exception raised') - - def test_channel_syntax_error(self): - # missing colon - channel = self.gw.remote_exec('def foo()\n return 1\nfoo()\n') - try: - channel.receive() - except channel.RemoteError: - e = sys.exc_info()[1] - assert str(e).startswith('Traceback (most recent call last):') - assert str(e).find('SyntaxError') > -1 - - def test_channel_iter(self): - channel = self.gw.remote_exec(""" - for x in range(3): - channel.send(x) - """) - l = list(channel) - assert l == [0, 1, 2] - - def test_channel_passing_over_channel(self): - channel = self.gw.remote_exec(''' - c = channel.gateway.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(TESTTIMEOUT) - #assert c.id not in self.gw._channelfactory - newchan = self.gw.remote_exec(''' - assert %d not in channel.gateway._channelfactory._channels - ''' % (channel.id)) - newchan.waitclose(TESTTIMEOUT) - assert channel.id not in self.gw._channelfactory._channels - - def test_channel_receiver_callback(self): - l = [] - #channel = self.gw.newchannel(receiver=l.append) - channel = self.gw.remote_exec(source=''' - channel.send(42) - channel.send(13) - channel.send(channel.gateway.newchannel()) - ''') - channel.setcallback(callback=l.append) - py.test.raises(IOError, channel.receive) - channel.waitclose(TESTTIMEOUT) - assert len(l) == 3 - assert l[:2] == [42,13] - assert isinstance(l[2], channel.__class__) - - def test_channel_callback_after_receive(self): - l = [] - channel = self.gw.remote_exec(source=''' - channel.send(42) - channel.send(13) - channel.send(channel.gateway.newchannel()) - ''') - x = channel.receive() - assert x == 42 - channel.setcallback(callback=l.append) - py.test.raises(IOError, channel.receive) - channel.waitclose(TESTTIMEOUT) - assert len(l) == 2 - assert l[0] == 13 - assert isinstance(l[1], channel.__class__) - - def test_waiting_for_callbacks(self): - l = [] - def callback(msg): - import time; time.sleep(0.2) - l.append(msg) - channel = self.gw.remote_exec(source=''' - channel.send(42) - ''') - channel.setcallback(callback) - channel.waitclose(TESTTIMEOUT) - assert l == [42] - - def test_channel_callback_stays_active(self): - self.check_channel_callback_stays_active(earlyfree=True) - - def check_channel_callback_stays_active(self, earlyfree=True): - # with 'earlyfree==True', this tests the "sendonly" channel state. - l = [] - channel = self.gw.remote_exec(source=''' - try: - import thread - except ImportError: - import _thread as thread - import time - def producer(subchannel): - for i in range(5): - time.sleep(0.15) - subchannel.send(i*100) - channel2 = channel.receive() - thread.start_new_thread(producer, (channel2,)) - del channel2 - ''') - subchannel = self.gw.newchannel() - subchannel.setcallback(l.append) - channel.send(subchannel) - if earlyfree: - subchannel = None - counter = 100 - while len(l) < 5: - if subchannel and subchannel.isclosed(): - break - counter -= 1 - print(counter) - if not counter: - py.test.fail("timed out waiting for the answer[%d]" % len(l)) - time.sleep(0.04) # busy-wait - assert l == [0, 100, 200, 300, 400] - return subchannel - - def test_channel_callback_remote_freed(self): - channel = self.check_channel_callback_stays_active(earlyfree=False) - channel.waitclose(TESTTIMEOUT) # freed automatically at the end of producer() - - def test_channel_endmarker_callback(self): - l = [] - channel = self.gw.remote_exec(source=''' - channel.send(42) - channel.send(13) - channel.send(channel.gateway.newchannel()) - ''') - channel.setcallback(l.append, 999) - py.test.raises(IOError, channel.receive) - channel.waitclose(TESTTIMEOUT) - assert len(l) == 4 - assert l[:2] == [42,13] - assert isinstance(l[2], channel.__class__) - assert l[3] == 999 - - def test_channel_endmarker_callback_error(self): - q = queue.Queue() - channel = self.gw.remote_exec(source=''' - raise ValueError() - ''') - channel.setcallback(q.put, endmarker=999) - val = q.get(TESTTIMEOUT) - assert val == 999 - err = channel._getremoteerror() - assert err - assert str(err).find("ValueError") != -1 - - @py.test.mark.xfail - def test_remote_redirect_stdout(self): - out = py.io.TextIO() - handle = self.gw._remote_redirect(stdout=out) - c = self.gw.remote_exec("print 42") - c.waitclose(TESTTIMEOUT) - handle.close() - s = out.getvalue() - assert s.strip() == "42" - - @py.test.mark.xfail - def test_remote_exec_redirect_multi(self): - num = 3 - l = [[] for x in range(num)] - channels = [self.gw.remote_exec("print %d" % i, - stdout=l[i].append) - for i in range(num)] - for x in channels: - x.waitclose(TESTTIMEOUT) - - for i in range(num): - subl = l[i] - assert subl - s = subl[0] - assert s.strip() == str(i) - - def test_channel_file_write(self): - channel = self.gw.remote_exec(""" - f = channel.makefile() - f.write("hello world\\n") - f.close() - channel.send(42) - """) - first = channel.receive() - assert first.strip() == 'hello world' - second = channel.receive() - assert second == 42 - - def test_channel_file_write_error(self): - channel = self.gw.remote_exec("pass") - f = channel.makefile() - channel.waitclose(TESTTIMEOUT) - py.test.raises(IOError, f.write, 'hello') - - def test_channel_file_proxyclose(self): - channel = self.gw.remote_exec(""" - f = channel.makefile(proxyclose=True) - f.write("hello world") - f.close() - channel.send(42) - """) - first = channel.receive() - assert first.strip() == 'hello world' - py.test.raises(EOFError, channel.receive) - - def test_channel_file_read(self): - channel = self.gw.remote_exec(""" - f = channel.makefile(mode='r') - s = f.read(2) - channel.send(s) - s = f.read(5) - channel.send(s) - """) - channel.send("xyabcde") - s1 = channel.receive() - s2 = channel.receive() - assert s1 == "xy" - assert s2 == "abcde" - - def test_channel_file_read_empty(self): - channel = self.gw.remote_exec("pass") - f = channel.makefile(mode="r") - s = f.read(3) - assert s == "" - s = f.read(5) - assert s == "" - - def test_channel_file_readline_remote(self): - channel = self.gw.remote_exec(""" - channel.send('123\\n45') - """) - channel.waitclose(TESTTIMEOUT) - f = channel.makefile(mode="r") - s = f.readline() - assert s == "123\n" - s = f.readline() - assert s == "45" - - def test_channel_makefile_incompatmode(self): - channel = self.gw.newchannel() - py.test.raises(ValueError, 'channel.makefile("rw")') - - def test_confusion_from_os_write_stdout(self): - channel = self.gw.remote_exec(""" - import os - os.write(1, 'confusion!'.encode('ascii')) - channel.send(channel.receive() * 6) - channel.send(channel.receive() * 6) - """) - channel.send(3) - res = channel.receive() - assert res == 18 - channel.send(7) - res = channel.receive() - assert res == 42 - - def test_confusion_from_os_write_stderr(self): - channel = self.gw.remote_exec(""" - import os - os.write(2, 'test'.encode('ascii')) - channel.send(channel.receive() * 6) - channel.send(channel.receive() * 6) - """) - channel.send(3) - res = channel.receive() - assert res == 18 - channel.send(7) - res = channel.receive() - assert res == 42 - - def test__rinfo(self): - rinfo = self.gw._rinfo() - assert rinfo.executable - assert rinfo.cwd - assert rinfo.version_info - s = repr(rinfo) - old = self.gw.remote_exec(""" - import os.path - cwd = os.getcwd() - channel.send(os.path.basename(cwd)) - os.chdir('..') - """).receive() - try: - rinfo2 = self.gw._rinfo() - assert rinfo2.cwd == rinfo.cwd - rinfo3 = self.gw._rinfo(update=True) - assert rinfo3.cwd != rinfo2.cwd - finally: - self.gw._cache_rinfo = rinfo - self.gw.remote_exec("import os ; os.chdir(%r)" % old).waitclose() - -class BasicCmdbasedRemoteExecution(BasicRemoteExecution): - def test_cmdattr(self): - assert hasattr(self.gw, '_cmd') - -#class TestBlockingIssues: -# def test_join_blocked_execution_gateway(self): -# gateway = py.execnet.PopenGateway() -# channel = gateway.remote_exec(""" -# time.sleep(5.0) -# """) -# def doit(): -# gateway.exit() -# gateway.join(joinexec=True) -# return 17 -# -# pool = py._thread.WorkerPool() -# reply = pool.dispatch(doit) -# x = reply.get(timeout=1.0) -# assert x == 17 - -class TestPopenGateway(PopenGatewayTestSetup, BasicRemoteExecution): - def test_rinfo_popen(self): - rinfo = self.gw._rinfo() - assert rinfo.executable == py.std.sys.executable - assert rinfo.cwd == py.std.os.getcwd() - assert rinfo.version_info == py.std.sys.version_info - - def test_chdir_separation(self, tmpdir): - old = tmpdir.chdir() - try: - gw = py.execnet.PopenGateway() - finally: - waschangedir = old.chdir() - c = gw.remote_exec("import os ; channel.send(os.getcwd())") - x = c.receive() - assert x == str(waschangedir) - - 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() - while channels: - channel = channels.pop() - ret = channel.receive() - assert ret == 42 - - @py.test.mark.xfail # "fix needed: dying remote process does not cause waitclose() to fail" - def test_waitclose_on_remote_killed(self): - gw = py.execnet.PopenGateway() - channel = gw.remote_exec(""" - import os - import time - channel.send(os.getpid()) - while 1: - channel.send("#" * 100) - """) - remotepid = channel.receive() - py.process.kill(remotepid) - py.test.raises(channel.RemoteError, "channel.waitclose(TESTTIMEOUT)") - py.test.raises(EOFError, channel.send, None) - py.test.raises(EOFError, channel.receive) - - at py.test.mark.xfail -def test_endmarker_delivery_on_remote_killterm(): - if not hasattr(py.std.os, 'kill'): - py.test.skip("no os.kill()") - gw = py.execnet.PopenGateway() - try: - q = queue.Queue() - channel = gw.remote_exec(source=''' - import os - os.kill(os.getpid(), 15) - ''') - channel.setcallback(q.put, endmarker=999) - val = q.get(TESTTIMEOUT) - assert val == 999 - err = channel._getremoteerror() - finally: - gw.exit() - assert "killed" in str(err) - assert "15" in str(err) - - -class SocketGatewaySetup: - def setup_class(cls): - # open a gateway to a fresh child process - cls.proxygw = py.execnet.PopenGateway() - cls.gw = py.execnet.SocketGateway.new_remote(cls.proxygw, - ("127.0.0.1", 0) - ) - def test_host_not_found(self): - py.test.raises(py.execnet.HostNotFound, - 'py.execnet.SocketGateway("qowieuqowe", 9000)' - ) - -## def teardown_class(cls): -## cls.gw.exit() -## cls.proxygw.exit() - -class TestSocketGateway(SocketGatewaySetup, BasicRemoteExecution): - pass - -class TestSshGateway(BasicRemoteExecution): - def setup_class(cls): - from py.__.conftest import getspecssh - cls.sshhost = getspecssh().ssh - cls.gw = py.execnet.SshGateway(cls.sshhost) - - def test_sshconfig_functional(self, tmpdir): - ssh_config = tmpdir.join("ssh_config") - ssh_config.write( - "Host alias123\n" - " HostName %s\n" % self.sshhost) - gw = py.execnet.SshGateway("alias123", ssh_config=ssh_config) - pid = gw.remote_exec("import os ; channel.send(os.getpid())").receive() - gw.exit() - - def test_sshaddress(self): - assert self.gw.remoteaddress == self.sshhost - - def test_connexion_failes_on_non_existing_hosts(self): - py.test.raises(py.execnet.HostNotFound, - "py.execnet.SshGateway('nowhere.codespeak.net')") - -def test_threads(): - gw = py.execnet.PopenGateway() - gw.remote_init_threads(3) - c1 = gw.remote_exec("channel.send(channel.receive())") - c2 = gw.remote_exec("channel.send(channel.receive())") - c2.send(1) - res = c2.receive() - assert res == 1 - c1.send(42) - res = c1.receive() - assert res == 42 - gw.exit() - -def test_threads_twice(): - gw = py.execnet.PopenGateway() - gw.remote_init_threads(3) - py.test.raises(IOError, gw.remote_init_threads, 3) - gw.exit() - -class TestExecnetEvents: - def test_popengateway(self, _pytest): - rec = _pytest.gethookrecorder(gateway_base.ExecnetAPI) - gw = py.execnet.PopenGateway() - call = rec.popcall("pyexecnet_gateway_init") - assert call.gateway == gw - gw.exit() - call = rec.popcall("pyexecnet_gateway_exit") - assert call.gateway == gw - -def test_nodebug(): - from py.__.execnet import gateway_base - assert not gateway_base.debug --- a/py/io/testing/test_terminalwriter.py +++ /dev/null @@ -1,158 +0,0 @@ -import py -import os, sys -from py.__.io import terminalwriter - -def skip_win32(): - if sys.platform == 'win32': - py.test.skip('Not relevant on win32') - -import os -import py - -def test_terminal_width_COLUMNS(monkeypatch): - """ Dummy test for get_terminal_width - """ - fcntl = py.test.importorskip("fcntl") - monkeypatch.setattr(fcntl, 'ioctl', lambda *args: int('x')) - monkeypatch.setenv('COLUMNS', '42') - assert terminalwriter.get_terminal_width() == 41 - monkeypatch.delenv('COLUMNS', raising=False) - -def test_terminalwriter_defaultwidth_80(monkeypatch): - monkeypatch.setattr(terminalwriter, '_getdimensions', lambda: 0/0) - monkeypatch.delenv('COLUMNS', raising=False) - tw = py.io.TerminalWriter() - assert tw.fullwidth == 80-1 - -def test_terminalwriter_computes_width(monkeypatch): - monkeypatch.setattr(terminalwriter, 'get_terminal_width', lambda: 42) - tw = py.io.TerminalWriter() - assert tw.fullwidth == 42 - -def test_terminalwriter_default_instantiation(): - tw = py.io.TerminalWriter(stringio=True) - assert hasattr(tw, 'stringio') - -def test_terminalwriter_dumb_term_no_markup(monkeypatch): - monkeypatch.setattr(os, 'environ', {'TERM': 'dumb', 'PATH': ''}) - class MyFile: - def isatty(self): - return True - monkeypatch.setattr(sys, 'stdout', MyFile()) - assert sys.stdout.isatty() - tw = py.io.TerminalWriter() - assert not tw.hasmarkup - -def test_unicode_encoding(): - msg = py.builtin._totext('b\u00f6y', 'utf8') - for encoding in 'utf8', 'latin1': - l = [] - tw = py.io.TerminalWriter(l.append, encoding=encoding) - tw.line(msg) - assert l[0] == msg.encode(encoding) - -class BaseTests: - def test_line(self): - tw = self.getwriter() - tw.line("hello") - l = self.getlines() - assert len(l) == 1 - assert l[0] == "hello\n" - - def test_line_unicode(self): - tw = self.getwriter() - for encoding in 'utf8', 'latin1': - tw._encoding = encoding - msg = py.builtin._totext('b\u00f6y', 'utf8') - tw.line(msg) - l = self.getlines() - assert l[0] == msg + "\n" - - def test_sep_no_title(self): - tw = self.getwriter() - tw.sep("-", fullwidth=60) - l = self.getlines() - assert len(l) == 1 - assert l[0] == "-" * 60 + "\n" - - def test_sep_with_title(self): - tw = self.getwriter() - tw.sep("-", "hello", fullwidth=60) - l = self.getlines() - assert len(l) == 1 - assert l[0] == "-" * 26 + " hello " + "-" * 27 + "\n" - - def test__escaped(self): - skip_win32() - tw = self.getwriter() - text2 = tw._escaped("hello", (31)) - assert text2.find("hello") != -1 - - def test_markup(self): - skip_win32() - tw = self.getwriter() - for bold in (True, False): - for color in ("red", "green"): - text2 = tw.markup("hello", **{color: True, 'bold': bold}) - assert text2.find("hello") != -1 - py.test.raises(ValueError, "tw.markup('x', wronkw=3)") - py.test.raises(ValueError, "tw.markup('x', wronkw=0)") - - def test_line_write_markup(self): - tw = self.getwriter() - tw.hasmarkup = True - tw.line("x", bold=True) - tw.write("x\n", red=True) - l = self.getlines() - skip_win32() - assert len(l[0]) > 2, l - assert len(l[1]) > 2, l - - def test_attr_fullwidth(self): - tw = self.getwriter() - tw.sep("-", "hello", fullwidth=70) - tw.fullwidth = 70 - tw.sep("-", "hello") - l = self.getlines() - assert len(l[0]) == len(l[1]) - -class TestTmpfile(BaseTests): - def getwriter(self): - self.path = py.test.config.ensuretemp("terminalwriter").ensure("tmpfile") - self.tw = py.io.TerminalWriter(self.path.open('w+')) - return self.tw - def getlines(self): - io = self.tw._file - io.flush() - return self.path.open('r').readlines() - -class TestWithStringIO(BaseTests): - def getwriter(self): - self.tw = py.io.TerminalWriter(stringio=True) - return self.tw - def getlines(self): - io = self.tw.stringio - io.seek(0) - return io.readlines() - -class TestCallableFile(BaseTests): - def getwriter(self): - self.writes = [] - return py.io.TerminalWriter(self.writes.append) - - def getlines(self): - io = py.io.TextIO() - io.write("".join(self.writes)) - io.seek(0) - return io.readlines() - -def test_attr_hasmarkup(): - tw = py.io.TerminalWriter(stringio=True) - assert not tw.hasmarkup - tw.hasmarkup = True - tw.line("hello", bold=True) - s = tw.stringio.getvalue() - assert len(s) > len("hello") - - - --- a/py/_testing/test_sources.py +++ /dev/null @@ -1,19 +0,0 @@ -import os -import py - - -this_dir = py.path.local(__file__).dirpath() -_compile_checker = this_dir.join("check_compile.py") -_py_root = this_dir.join("..") -del this_dir - - at py.test.mark.multi(pyversion=("2.4", "2.5", "2.6", "3.1")) -def test_syntax(pyversion): - executable = py.path.local.sysfind("python" + pyversion) - if executable is None: - py.test.skip("no python%s found" % (pyversion,)) - for path, dirs, filenames in os.walk(str(_py_root)): - for fn in filenames: - if fn.endswith(".py"): - full = os.path.join(path, fn) - executable.sysexec(_compile_checker, full) --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -2,7 +2,7 @@ Changes between 1.0.x and 'trunk' ===================================== * consolidate builtins implementation to be compatible with >=2.3, - add print_, exec_ and _reraise helpers for 2-3 compatible code + add helpers to ease keeping 2 and 3k compatible code * deprecate py.compat.doctest|subprocess|textwrap|optparse --- a/py/_testing/test_initpkg.py +++ /dev/null @@ -1,184 +0,0 @@ -from __future__ import generators - -import py -import types -import sys - -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.__.initpkg import ApiModule - for name in dir(py): - if name == 'magic': # greenlets don't work everywhere, we don't care here - continue - if not name.startswith('_'): - yield checksubpackage, name - -from py.initpkg import ApiModule -glob = [] -class MyModule(ApiModule): - def __init__(self, *args): - glob.append(self.__dict__) - assert isinstance(glob[-1], (dict, type(None))) - ApiModule.__init__(self, *args) - -def test_early__dict__access(): - mymod = MyModule("whatever", "myname") - assert isinstance(mymod.__dict__, dict) - -def test_resolve_attrerror(): - extpyish = "./initpkg.py", "hello" - excinfo = py.test.raises(AttributeError, "py.__pkg__._resolve(extpyish)") - s = str(excinfo.value) - assert s.find(extpyish[0]) != -1 - assert s.find(extpyish[1]) != -1 - -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_importall(): - base = py.path.local(py.__file__).dirpath() - nodirs = [ - base.join('test', 'testing', 'data'), - base.join('test', 'web'), - base.join('path', 'gateway',), - base.join('doc',), - base.join('rest', 'directive.py'), - base.join('test', 'testing', 'import_test'), - base.join('bin'), - base.join('code', 'oldmagic.py'), - base.join('execnet', 'script'), - base.join('compat', 'testing'), - ] - if sys.version_info >= (3,0): - nodirs.append(base.join('code', '_assertionold.py')) - else: - nodirs.append(base.join('code', '_assertionnew.py')) - - def recurse(p): - return p.check(dotfile=0) and p.basename != "attic" - - for p in base.visit('*.py', recurse): - if p.basename == '__init__.py': - continue - relpath = p.new(ext='').relto(base) - if base.sep in relpath: # not py/*.py itself - for x in nodirs: - if p == x or p.relto(x): - break - else: - relpath = relpath.replace(base.sep, '.') - modpath = 'py.__.%s' % relpath - yield check_import, modpath - -def check_import(modpath): - py.builtin.print_("checking import", modpath) - assert __import__(modpath) - -# -# test support for importing modules -# - -class TestRealModule: - - def setup_class(cls): - cls.tmpdir = py.test.ensuretemp('test_initpkg') - sys.path = [str(cls.tmpdir)] + sys.path - pkgdir = cls.tmpdir.ensure('realtest', dir=1) - - tfile = pkgdir.join('__init__.py') - tfile.write(py.code.Source(""" - import py - py.initpkg('realtest', { - 'x.module.__doc__': ('./testmodule.py', '__doc__'), - 'x.module': ('./testmodule.py', '*'), - }) - """)) - - tfile = pkgdir.join('testmodule.py') - tfile.write(py.code.Source(""" - 'test module' - - __all__ = ['mytest0', 'mytest1', 'MyTest'] - - def mytest0(): - pass - def mytest1(): - pass - class MyTest: - pass - - """)) - - import realtest # need to mimic what a user would do - #py.initpkg('realtest', { - # 'module': ('./testmodule.py', None) - #}) - - def setup_method(self, *args): - """Unload the test modules before each test.""" - module_names = ['realtest', 'realtest.x', 'realtest.x.module'] - for modname in module_names: - if modname in sys.modules: - del sys.modules[modname] - - def test_realmodule(self): - """Testing 'import realtest.x.module'""" - import realtest.x.module - assert 'realtest.x.module' in sys.modules - assert getattr(realtest.x.module, 'mytest0') - - def test_realmodule_from(self): - """Testing 'from test import module'.""" - from realtest.x import module - assert getattr(module, 'mytest1') - - def test_realmodule_star(self): - """Testing 'from test.module import *'.""" - tfile = self.tmpdir.join('startest.py') - tfile.write(py.code.Source(""" - from realtest.x.module import * - globals()['mytest0'] - globals()['mytest1'] - globals()['MyTest'] - """)) - import startest # an exception will be raise if an error occurs - - def test_realmodule_dict_import(self): - "Test verifying that accessing the __dict__ invokes the import" - import realtest.x.module - moddict = realtest.x.module.__dict__ - assert 'mytest0' in moddict - assert 'mytest1' in moddict - assert 'MyTest' in moddict - - def test_realmodule___doc__(self): - """test whether the __doc__ attribute is set properly from initpkg""" - import realtest.x.module - assert realtest.x.module.__doc__ == 'test module' - -def test_autoimport(): - from py.initpkg import autoimport - py.std.os.environ['AUTOTEST_AUTOIMPORT'] = "nonexistmodule" - py.test.raises(ImportError, "autoimport('autotest')") - - -def test_all_resolves(): - seen = py.builtin.set([py]) - lastlength = None - while len(seen) != lastlength: - lastlength = len(seen) - for item in py.builtin.frozenset(seen): - for value in item.__dict__.values(): - if isinstance(value, type(py.test)): - seen.add(value) --- a/example/funcarg/mysetup/conftest.py +++ b/example/funcarg/mysetup/conftest.py @@ -1,5 +1,5 @@ -from myapp import MyApp +from mysetup.myapp import MyApp def pytest_funcarg__mysetup(request): return MySetup() --- /dev/null +++ b/conftest.py @@ -0,0 +1,55 @@ +pytest_plugins = '_pytest doctest pytester'.split() + +rsyncdirs = ['conftest.py', 'py', 'doc', 'testing'] + +import py +def pytest_addoption(parser): + group = parser.addgroup("pylib", "py lib testing options") + group.addoption('--sshhost', + action="store", dest="sshhost", default=None, + help=("ssh xspec for ssh functional tests. ")) + group.addoption('--gx', + action="append", dest="gspecs", default=None, + help=("add a global test environment, XSpec-syntax. ")) + group.addoption('--runslowtests', + action="store_true", dest="runslowtests", default=False, + help=("run slow tests")) + +def pytest_funcarg__specssh(request): + return getspecssh(request.config) +def pytest_funcarg__specsocket(request): + return getsocketspec(request.config) + + +# configuration information for tests +def getgspecs(config=None): + if config is None: + config = py.test.config + return [py.execnet.XSpec(spec) + for spec in config.getvalueorskip("gspecs")] + +def getspecssh(config=None): + xspecs = getgspecs(config) + for spec in xspecs: + if spec.ssh: + if not py.path.local.sysfind("ssh"): + py.test.skip("command not found: ssh") + return spec + py.test.skip("need '--gx ssh=...'") + +def getsocketspec(config=None): + xspecs = getgspecs(config) + for spec in xspecs: + if spec.socket: + return spec + py.test.skip("need '--gx socket=...'") + + +def pytest_generate_tests(metafunc): + multi = getattr(metafunc.function, 'multi', None) + if multi is None: + return + assert len(multi.__dict__) == 1 + for name, l in multi.__dict__.items(): + for val in l: + metafunc.addcall(funcargs={name: val}) --- a/py/_testing/test_error.py +++ /dev/null @@ -1,26 +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) - -def test_unknown_error(): - num = 3999 - cls = py.error._geterrnoclass(num) - assert cls.__name__ == 'UnknownErrno%d' % (num,) - assert issubclass(cls, py.error.Error) - assert issubclass(cls, EnvironmentError) - cls2 = py.error._geterrnoclass(num) - assert cls is cls2 - -def test_error_conversion_ENOTDIR(testdir): - p = testdir.makepyfile("") - excinfo = py.test.raises(py.error.Error, py.error.checked_call, p.listdir) - assert isinstance(excinfo.value, EnvironmentError) - assert isinstance(excinfo.value, py.error.Error) - assert "ENOTDIR" in repr(excinfo.value) --- a/py/cmdline/testing/test_generic.py +++ /dev/null @@ -1,64 +0,0 @@ -import py -import sys - -binpath = py.path.local(py.__file__).dirpath("bin") -binwinpath = binpath.join("win32") - -def setup_module(mod): - mod.tmpdir = py.test.ensuretemp(__name__) - mod.iswin32 = sys.platform == "win32" - -def checkmain(name): - main = getattr(py.cmdline, name) - assert py.builtin.callable(main) - assert name[:2] == "py" - scriptname = "py." + name[2:] - assert binpath.join(scriptname).check() - assert binwinpath.join(scriptname + ".cmd").check() - -def checkprocess(script): - assert script.check() - old = tmpdir.ensure(script.basename, dir=1).chdir() - try: - if iswin32: - cmd = script.basename - else: - cmd = "%s" %(script, ) - # XXX distributed testing's rsync does not support - # syncing executable bits - script.chmod(int("777", 8)) - - if script.basename.startswith("py.lookup") or \ - script.basename.startswith("py.which"): - cmd += " sys" - py.builtin.print_("executing", script) - try: - old = script.dirpath().chdir() - try: - py.process.cmdexec(cmd) - finally: - old.chdir() - except py.process.cmdexec.Error: - e = sys.exc_info()[1] - if cmd.find("py.rest") != -1 and \ - e.out.find("module named") != -1: - return - raise - - finally: - old.chdir() - -def test_cmdline_namespace(): - for name in dir(py.cmdline): - if name[0] != "_": - yield checkmain, name - -def test_script_invocation(): - if iswin32: - scripts = binwinpath.listdir("py.*") - else: - scripts = binpath.listdir("py.*") - scripts = [x for x in scripts - if not x.basename.startswith("py.svnwcrevert")] - for script in scripts: - yield checkprocess, script --- a/py/path/testing/test_sourcepath.py +++ /dev/null @@ -1,3 +0,0 @@ -import py -import sys - --- a/py/code/testing/test_excinfo.py +++ /dev/null @@ -1,681 +0,0 @@ - -import py -from py.__.code.code import FormattedExcinfo, ReprExceptionInfo -queue = py.builtin._tryimport('queue', 'Queue') - -class TWMock: - def __init__(self): - self.lines = [] - def sep(self, sep, line=None): - self.lines.append((sep, line)) - def line(self, line, **kw): - self.lines.append(line) - def markup(self, text, **kw): - return text - - fullwidth = 80 - -def test_excinfo_simple(): - try: - raise ValueError - except ValueError: - info = py.code.ExceptionInfo() - assert info.type == ValueError - -def test_excinfo_getstatement(): - def g(): - raise ValueError - def f(): - g() - try: - f() - except ValueError: - excinfo = py.code.ExceptionInfo() - linenumbers = [py.code.getrawcode(f).co_firstlineno-1+3, - py.code.getrawcode(f).co_firstlineno-1+1, - py.code.getrawcode(g).co_firstlineno-1+1,] - l = list(excinfo.traceback) - foundlinenumbers = [x.lineno for x in l] - 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(): - # - __tracebackhide__ = True - f() - # -def h(): - # - g() - # - -class TestTraceback_f_g_h: - def setup_method(self, method): - try: - h() - except ValueError: - self.excinfo = py.code.ExceptionInfo() - - 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_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_cut(self): - co = py.code.Code(f) - path, firstlineno = co.path, co.firstlineno - traceback = self.excinfo.traceback - newtraceback = traceback.cut(path=path, firstlineno=firstlineno) - assert len(newtraceback) == 1 - newtraceback = traceback.cut(path=path, lineno=firstlineno+2) - assert len(newtraceback) == 1 - - def test_traceback_cut_excludepath(self, testdir): - p = testdir.makepyfile("def f(): raise ValueError") - excinfo = py.test.raises(ValueError, "p.pyimport().f()") - pydir = py.path.local(py.__file__).dirpath() - newtraceback = excinfo.traceback.cut(excludepath=pydir) - assert len(newtraceback) == 1 - assert newtraceback[0].frame.code.path == p - - def test_traceback_filter(self): - traceback = self.excinfo.traceback - ntraceback = traceback.filter() - assert len(ntraceback) == len(traceback) - 1 - - def test_traceback_recursion_index(self): - def f(n): - if n < 10: - n += 1 - f(n) - excinfo = py.test.raises(RuntimeError, f, 8) - traceback = excinfo.traceback - recindex = traceback.recursionindex() - assert recindex == 3 - - def test_traceback_no_recursion_index(self): - def do_stuff(): - raise RuntimeError - def reraise_me(): - import sys - exc, val, tb = sys.exc_info() - py.builtin._reraise(exc, val, tb) - def f(n): - try: - do_stuff() - except: - reraise_me() - excinfo = py.test.raises(RuntimeError, f, 8) - traceback = excinfo.traceback - recindex = traceback.recursionindex() - assert recindex is None - - def test_traceback_getcrashentry(self): - def i(): - __tracebackhide__ = True - raise ValueError - def h(): - i() - def g(): - __tracebackhide__ = True - h() - def f(): - g() - - excinfo = py.test.raises(ValueError, f) - tb = excinfo.traceback - entry = tb.getcrashentry() - co = py.code.Code(h) - assert entry.frame.code.path == co.path - assert entry.lineno == co.firstlineno + 1 - assert entry.frame.code.name == 'h' - - def test_traceback_getcrashentry_empty(self): - def g(): - __tracebackhide__ = True - raise ValueError - def f(): - __tracebackhide__ = True - g() - - excinfo = py.test.raises(ValueError, f) - tb = excinfo.traceback - entry = tb.getcrashentry() - co = py.code.Code(g) - assert entry.frame.code.path == co.path - assert entry.lineno == co.firstlineno + 2 - assert entry.frame.code.name == 'g' - -def 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_exconly(): - excinfo = py.test.raises(ValueError, h) - assert excinfo.exconly().startswith('ValueError') - excinfo = py.test.raises(ValueError, - "raise ValueError('hello\\nworld')") - msg = excinfo.exconly(tryshort=True) - assert msg.startswith('ValueError') - assert msg.endswith("world") - -def test_excinfo_repr(): - excinfo = py.test.raises(ValueError, h) - s = repr(excinfo) - assert s == "" - -def test_excinfo_str(): - excinfo = py.test.raises(ValueError, h) - s = str(excinfo) - assert s.startswith(__file__[:-1]) # pyc file - assert s.endswith("ValueError") - assert len(s.split(":")) >= 3 # on windows it's 4 - -def test_excinfo_errisinstance(): - excinfo = py.test.raises(ValueError, h) - assert excinfo.errisinstance(ValueError) - -def test_excinfo_no_sourcecode(): - try: - exec ("raise ValueError()") - except ValueError: - excinfo = py.code.ExceptionInfo() - s = str(excinfo.traceback[-1]) - if py.std.sys.version_info < (2,5): - assert s == " File '':1 in ?\n ???\n" - else: - assert s == " File '':1 in \n ???\n" - -def test_entrysource_Queue_example(): - try: - queue.Queue().get(timeout=0.001) - except queue.Empty: - excinfo = py.code.ExceptionInfo() - entry = excinfo.traceback[-1] - source = entry.getsource() - assert source is not None - s = str(source).strip() - assert s.startswith("def get") - -def test_codepath_Queue_example(): - try: - queue.Queue().get(timeout=0.001) - except queue.Empty: - excinfo = py.code.ExceptionInfo() - entry = excinfo.traceback[-1] - path = entry.path - assert isinstance(path, py.path.local) - assert path.basename.lower() == "queue.py" - assert path.check() - -class TestFormattedExcinfo: - def setup_method(self, method): - self.tmpdir = py.test.ensuretemp("%s_%s" %( - self.__class__.__name__, method.__name__)) - - def importasmod(self, source): - source = py.code.Source(source) - modpath = self.tmpdir.join("mod.py") - self.tmpdir.ensure("__init__.py") - modpath.write(source) - return modpath.pyimport() - - def excinfo_from_exec(self, source): - source = py.code.Source(source).strip() - try: - exec (source.compile()) - except KeyboardInterrupt: - raise - except: - return py.code.ExceptionInfo() - assert 0, "did not raise" - - def test_repr_source(self): - pr = FormattedExcinfo() - source = py.code.Source(""" - def f(x): - pass - """).strip() - pr.flow_marker = "|" - lines = pr.get_source(source, 0) - assert len(lines) == 2 - assert lines[0] == "| def f(x):" - assert lines[1] == " pass" - - def test_repr_source_excinfo(self): - """ check if indentation is right """ - pr = FormattedExcinfo() - py.code.patch_builtins() - try: - excinfo = self.excinfo_from_exec(""" - def f(): - assert 0 - f() - """) - finally: - py.code.unpatch_builtins() - pr = FormattedExcinfo() - source = pr._getentrysource(excinfo.traceback[-1]) - lines = pr.get_source(source, 1, excinfo) - assert lines == [ - ' def f():', - '> assert 0', - 'E assert 0' - ] - - - def test_repr_source_not_existing(self): - pr = FormattedExcinfo() - co = compile("raise ValueError()", "", "exec") - try: - exec (co) - except ValueError: - excinfo = py.code.ExceptionInfo() - repr = pr.repr_excinfo(excinfo) - assert repr.reprtraceback.reprentries[1].lines[0] == "> ???" - - def test_repr_many_line_source_not_existing(self): - pr = FormattedExcinfo() - co = compile(""" -a = 1 -raise ValueError() -""", "", "exec") - try: - exec (co) - except ValueError: - excinfo = py.code.ExceptionInfo() - repr = pr.repr_excinfo(excinfo) - assert repr.reprtraceback.reprentries[1].lines[0] == "> ???" - - def test_repr_source_failing_fullsource(self): - pr = FormattedExcinfo() - - class FakeCode(object): - path = '?' - firstlineno = 5 - - def fullsource(self): - return None - fullsource = property(fullsource) - - class FakeFrame(object): - code = FakeCode() - f_locals = {} - - class FakeTracebackEntry(py.code.Traceback.Entry): - def __init__(self, tb): - self.frame = FakeFrame() - self.lineno = 5+3 - - class Traceback(py.code.Traceback): - Entry = FakeTracebackEntry - - class FakeExcinfo(py.code.ExceptionInfo): - typename = "Foo" - def __init__(self): - pass - - def exconly(self, tryshort): - return "EXC" - def errisinstance(self, cls): - return False - - excinfo = FakeExcinfo() - class FakeRawTB(object): - tb_next = None - tb = FakeRawTB() - excinfo.traceback = Traceback(tb) - - fail = IOError() - repr = pr.repr_excinfo(excinfo) - assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" - - fail = py.error.ENOENT - repr = pr.repr_excinfo(excinfo) - assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" - - - def test_repr_local(self): - p = FormattedExcinfo(showlocals=True) - loc = {'y': 5, 'z': 7, 'x': 3, '__builtins__': __builtins__} - reprlocals = p.repr_locals(loc) - assert reprlocals.lines - assert reprlocals.lines[0] == '__builtins__ = ' - assert reprlocals.lines[1] == 'x = 3' - assert reprlocals.lines[2] == 'y = 5' - assert reprlocals.lines[3] == 'z = 7' - - def test_repr_tracebackentry_lines(self): - mod = self.importasmod(""" - def func1(): - raise ValueError("hello\\nworld") - """) - excinfo = py.test.raises(ValueError, mod.func1) - excinfo.traceback = excinfo.traceback.filter() - p = FormattedExcinfo() - reprtb = p.repr_traceback_entry(excinfo.traceback[-1]) - - # test as intermittent entry - lines = reprtb.lines - assert lines[0] == ' def func1():' - assert lines[1] == '> raise ValueError("hello\\nworld")' - - # test as last entry - p = FormattedExcinfo(showlocals=True) - repr_entry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) - lines = repr_entry.lines - assert lines[0] == ' def func1():' - assert lines[1] == '> raise ValueError("hello\\nworld")' - assert lines[2] == 'E ValueError: hello' - assert lines[3] == 'E world' - assert not lines[4:] - - loc = repr_entry.reprlocals is not None - loc = repr_entry.reprfileloc - assert loc.path == mod.__file__ - assert loc.lineno == 3 - #assert loc.message == "ValueError: hello" - - def test_repr_tracebackentry_lines(self): - mod = self.importasmod(""" - def func1(m, x, y, z): - raise ValueError("hello\\nworld") - """) - excinfo = py.test.raises(ValueError, mod.func1, "m"*90, 5, 13, "z"*120) - excinfo.traceback = excinfo.traceback.filter() - entry = excinfo.traceback[-1] - p = FormattedExcinfo(funcargs=True) - reprfuncargs = p.repr_args(entry) - assert reprfuncargs.args[0] == ('m', repr("m"*90)) - assert reprfuncargs.args[1] == ('x', '5') - assert reprfuncargs.args[2] == ('y', '13') - assert reprfuncargs.args[3] == ('z', repr("z" * 120)) - - p = FormattedExcinfo(funcargs=True) - repr_entry = p.repr_traceback_entry(entry) - assert repr_entry.reprfuncargs.args == reprfuncargs.args - tw = TWMock() - repr_entry.toterminal(tw) - assert tw.lines[0] == "m = " + repr('m' * 90) - assert tw.lines[1] == "x = 5, y = 13" - assert tw.lines[2] == "z = " + repr('z' * 120) - - def test_repr_tracebackentry_short(self): - mod = self.importasmod(""" - def func1(): - raise ValueError("hello") - def entry(): - func1() - """) - excinfo = py.test.raises(ValueError, mod.entry) - p = FormattedExcinfo(style="short") - reprtb = p.repr_traceback_entry(excinfo.traceback[-2]) - lines = reprtb.lines - basename = py.path.local(mod.__file__).basename - assert lines[0] == ' File "%s", line 5, in entry' % basename - assert lines[1] == ' func1()' - - # test last entry - p = FormattedExcinfo(style="short") - reprtb = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) - lines = reprtb.lines - assert lines[0] == ' File "%s", line 3, in func1' % basename - assert lines[1] == ' raise ValueError("hello")' - assert lines[2] == 'E ValueError: hello' - - def test_repr_tracebackentry_no(self): - mod = self.importasmod(""" - def func1(): - raise ValueError("hello") - def entry(): - func1() - """) - excinfo = py.test.raises(ValueError, mod.entry) - p = FormattedExcinfo(style="no") - p.repr_traceback_entry(excinfo.traceback[-2]) - - p = FormattedExcinfo(style="no") - reprentry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) - lines = reprentry.lines - assert lines[0] == 'E ValueError: hello' - assert not lines[1:] - - def test_repr_traceback_tbfilter(self): - mod = self.importasmod(""" - def f(x): - raise ValueError(x) - def entry(): - f(0) - """) - excinfo = py.test.raises(ValueError, mod.entry) - p = FormattedExcinfo(tbfilter=True) - reprtb = p.repr_traceback(excinfo) - assert len(reprtb.reprentries) == 2 - p = FormattedExcinfo(tbfilter=False) - reprtb = p.repr_traceback(excinfo) - assert len(reprtb.reprentries) == 3 - - def test_repr_traceback_and_excinfo(self): - mod = self.importasmod(""" - def f(x): - raise ValueError(x) - def entry(): - f(0) - """) - excinfo = py.test.raises(ValueError, mod.entry) - - for style in ("long", "short"): - p = FormattedExcinfo(style=style) - reprtb = p.repr_traceback(excinfo) - assert len(reprtb.reprentries) == 2 - assert reprtb.style == style - assert not reprtb.extraline - repr = p.repr_excinfo(excinfo) - assert repr.reprtraceback - assert len(repr.reprtraceback.reprentries) == len(reprtb.reprentries) - assert repr.reprcrash.path.endswith("mod.py") - assert repr.reprcrash.message == "ValueError: 0" - - def test_repr_excinfo_addouterr(self): - mod = self.importasmod(""" - def entry(): - raise ValueError() - """) - excinfo = py.test.raises(ValueError, mod.entry) - repr = excinfo.getrepr() - repr.addsection("title", "content") - twmock = TWMock() - repr.toterminal(twmock) - assert twmock.lines[-1] == "content" - assert twmock.lines[-2] == ("-", "title") - - def test_repr_excinfo_reprcrash(self): - mod = self.importasmod(""" - def entry(): - raise ValueError() - """) - excinfo = py.test.raises(ValueError, mod.entry) - repr = excinfo.getrepr() - assert repr.reprcrash.path.endswith("mod.py") - assert repr.reprcrash.lineno == 3 - assert repr.reprcrash.message == "ValueError" - assert str(repr.reprcrash).endswith("mod.py:3: ValueError") - - def test_repr_traceback_recursion(self): - mod = self.importasmod(""" - def rec2(x): - return rec1(x+1) - def rec1(x): - return rec2(x-1) - def entry(): - rec1(42) - """) - excinfo = py.test.raises(RuntimeError, mod.entry) - - for style in ("short", "long", "no"): - p = FormattedExcinfo(style="short") - reprtb = p.repr_traceback(excinfo) - assert reprtb.extraline == "!!! Recursion detected (same locals & position)" - assert str(reprtb) - - def test_tb_entry_AssertionError(self): - # probably this test is a bit redundant - # as py/magic/testing/test_assertion.py - # already tests correctness of - # assertion-reinterpretation logic - mod = self.importasmod(""" - def somefunc(): - x = 1 - assert x == 2 - """) - py.code.patch_builtins(assertion=True) - try: - excinfo = py.test.raises(AssertionError, mod.somefunc) - finally: - py.code.unpatch_builtins(assertion=True) - - p = FormattedExcinfo() - reprentry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) - lines = reprentry.lines - assert lines[-1] == "E assert 1 == 2" - - def test_reprexcinfo_getrepr(self): - mod = self.importasmod(""" - def f(x): - raise ValueError(x) - def entry(): - f(0) - """) - excinfo = py.test.raises(ValueError, mod.entry) - - for style in ("short", "long", "no"): - for showlocals in (True, False): - repr = excinfo.getrepr(style=style, showlocals=showlocals) - assert isinstance(repr, ReprExceptionInfo) - assert repr.reprtraceback.style == style - - def test_toterminal_long(self): - mod = self.importasmod(""" - def g(x): - raise ValueError(x) - def f(): - g(3) - """) - excinfo = py.test.raises(ValueError, mod.f) - excinfo.traceback = excinfo.traceback.filter() - repr = excinfo.getrepr() - tw = TWMock() - repr.toterminal(tw) - assert tw.lines[0] == "" - tw.lines.pop(0) - assert tw.lines[0] == " def f():" - assert tw.lines[1] == "> g(3)" - assert tw.lines[2] == "" - assert tw.lines[3].endswith("mod.py:5: ") - assert tw.lines[4] == ("_ ", None) - assert tw.lines[5] == "" - assert tw.lines[6] == " def g(x):" - assert tw.lines[7] == "> raise ValueError(x)" - assert tw.lines[8] == "E ValueError: 3" - assert tw.lines[9] == "" - assert tw.lines[10].endswith("mod.py:3: ValueError") - - def test_toterminal_long_filenames(self): - mod = self.importasmod(""" - def f(): - raise ValueError() - """) - excinfo = py.test.raises(ValueError, mod.f) - tw = TWMock() - path = py.path.local(mod.__file__) - old = path.dirpath().chdir() - try: - repr = excinfo.getrepr(abspath=False) - repr.toterminal(tw) - line = tw.lines[-1] - x = py.path.local().bestrelpath(path) - if len(x) < len(str(path)): - assert line == "mod.py:3: ValueError" - - repr = excinfo.getrepr(abspath=True) - repr.toterminal(tw) - line = tw.lines[-1] - assert line == "%s:3: ValueError" %(path,) - finally: - old.chdir() - - def test_format_excinfo(self): - mod = self.importasmod(""" - def g(x): - raise ValueError(x) - def f(): - g(3) - """) - excinfo = py.test.raises(ValueError, mod.f) - def format_and_str(kw): - tw = py.io.TerminalWriter(stringio=True) - repr = excinfo.getrepr(**kw) - repr.toterminal(tw) - assert tw.stringio.getvalue() - - for combo in self.allcombos(): - yield format_and_str, combo - - def allcombos(self): - for style in ("long", "short", "no"): - for showlocals in (True, False): - for tbfilter in (True, False): - for funcargs in (True, False): - kw = {'style': style, - 'showlocals': showlocals, - 'funcargs': funcargs, - 'tbfilter': tbfilter - } - yield kw --- a/py/path/testing/common.py +++ /dev/null @@ -1,425 +0,0 @@ -import py -import sys - -class CommonFSTests(object): - def test_constructor_equality(self, path1): - p = path1.__class__(path1) - assert p == path1 - - def test_eq_nonstring(self, path1): - p1 = path1.join('sampledir') - p2 = path1.join('sampledir') - assert p1 == p2 - - def test_new_identical(self, path1): - assert path1 == path1.new() - - def test_join(self, path1): - p = path1.join('sampledir') - strp = str(p) - assert strp.endswith('sampledir') - assert strp.startswith(str(path1)) - - def test_join_normalized(self, path1): - newpath = path1.join(path1.sep+'sampledir') - strp = str(newpath) - assert strp.endswith('sampledir') - assert strp.startswith(str(path1)) - newpath = path1.join((path1.sep*2) + 'sampledir') - strp = str(newpath) - assert strp.endswith('sampledir') - assert strp.startswith(str(path1)) - - def test_join_noargs(self, path1): - newpath = path1.join() - assert path1 == newpath - - def test_add_something(self, path1): - p = path1.join('sample') - p = p + 'dir' - assert p.check() - - def test_parts(self, path1): - newpath = path1.join('sampledir', 'otherfile') - par = newpath.parts()[-3:] - assert par == [path1, path1.join('sampledir'), newpath] - - revpar = newpath.parts(reverse=True)[:3] - assert revpar == [newpath, path1.join('sampledir'), path1] - - def test_common(self, path1): - other = path1.join('sampledir') - x = other.common(path1) - assert x == path1 - - #def test_parents_nonexisting_file(self, path1): - # newpath = path1 / 'dirnoexist' / 'nonexisting file' - # par = list(newpath.parents()) - # assert par[:2] == [path1 / 'dirnoexist', path1] - - def test_basename_checks(self, path1): - newpath = path1.join('sampledir') - assert newpath.check(basename='sampledir') - assert newpath.check(notbasename='xyz') - assert newpath.basename == 'sampledir' - - def test_basename(self, path1): - newpath = path1.join('sampledir') - assert newpath.check(basename='sampledir') - assert newpath.basename, 'sampledir' - - def test_dirpath(self, path1): - newpath = path1.join('sampledir') - assert newpath.dirpath() == path1 - - def test_dirpath_with_args(self, path1): - newpath = path1.join('sampledir') - assert newpath.dirpath('x') == path1.join('x') - - def test_newbasename(self, path1): - newpath = path1.join('samplefile') - newbase = newpath.new(basename="samplefile2") - assert newbase.basename == "samplefile2" - assert newbase.dirpath() == newpath.dirpath() - - def test_not_exists(self, path1): - assert not path1.join('does_not_exist').check() - assert path1.join('does_not_exist').check(exists=0) - - def test_exists(self, path1): - assert path1.join("samplefile").check() - assert path1.join("samplefile").check(exists=1) - - def test_dir(self, path1): - #print repr(path1.join("sampledir")) - assert path1.join("sampledir").check(dir=1) - assert path1.join('samplefile').check(notdir=1) - assert not path1.join("samplefile").check(dir=1) - - def test_fnmatch_file(self, path1): - assert path1.join("samplefile").check(fnmatch='s*e') - assert path1.join("samplefile").check(notfnmatch='s*x') - assert not path1.join("samplefile").check(fnmatch='s*x') - - #def test_fnmatch_dir(self, path1): - - # pattern = path1.sep.join(['s*file']) - # sfile = path1.join("samplefile") - # assert sfile.check(fnmatch=pattern) - - def test_relto(self, path1): - l=path1.join("sampledir", "otherfile") - assert l.relto(path1) == l.sep.join(["sampledir", "otherfile"]) - assert l.check(relto=path1) - assert path1.check(notrelto=l) - assert not path1.check(relto=l) - - def test_bestrelpath(self, path1): - curdir = path1 - sep = curdir.sep - s = curdir.bestrelpath(curdir.join("hello", "world")) - assert s == "hello" + sep + "world" - - s = curdir.bestrelpath(curdir.dirpath().join("sister")) - assert s == ".." + sep + "sister" - assert curdir.bestrelpath(curdir.dirpath()) == ".." - - assert curdir.bestrelpath("hello") == "hello" - - def test_relto_not_relative(self, path1): - l1=path1.join("bcde") - l2=path1.join("b") - assert not l1.relto(l2) - assert not l2.relto(l1) - - def test_listdir(self, path1): - l = path1.listdir() - assert path1.join('sampledir') in l - assert path1.join('samplefile') in l - py.test.raises(py.error.ENOTDIR, - "path1.join('samplefile').listdir()") - - def test_listdir_fnmatchstring(self, path1): - l = path1.listdir('s*dir') - assert len(l) - assert l[0], path1.join('sampledir') - - def test_listdir_filter(self, path1): - l = path1.listdir(lambda x: x.check(dir=1)) - assert path1.join('sampledir') in l - assert not path1.join('samplefile') in l - - def test_listdir_sorted(self, path1): - l = path1.listdir(lambda x: x.check(basestarts="sample"), sort=True) - assert path1.join('sampledir') == l[0] - assert path1.join('samplefile') == l[1] - assert path1.join('samplepickle') == l[2] - - def test_visit_nofilter(self, path1): - l = [] - for i in path1.visit(): - l.append(i.relto(path1)) - assert "sampledir" in l - assert path1.sep.join(["sampledir", "otherfile"]) in l - - def test_visit_norecurse(self, path1): - l = [] - for i in path1.visit(None, lambda x: x.basename != "sampledir"): - l.append(i.relto(path1)) - assert "sampledir" in l - assert not path1.sep.join(["sampledir", "otherfile"]) in l - - def test_visit_filterfunc_is_string(self, path1): - l = [] - for i in path1.visit('*dir'): - l.append(i.relto(path1)) - assert len(l), 2 - assert "sampledir" in l - assert "otherdir" in l - - def test_visit_ignore(self, path1): - p = path1.join('nonexisting') - assert list(p.visit(ignore=py.error.ENOENT)) == [] - - def test_visit_endswith(self, path1): - l = [] - for i in path1.visit(lambda x: x.check(endswith="file")): - l.append(i.relto(path1)) - assert path1.sep.join(["sampledir", "otherfile"]) in l - assert "samplefile" in l - - def test_endswith(self, path1): - assert path1.check(notendswith='.py') - x = path1.join('samplefile') - assert x.check(endswith='file') - - def test_cmp(self, path1): - path1 = path1.join('samplefile') - path2 = path1.join('samplefile2') - assert (path1 < path2) == ('samplefile' < 'samplefile2') - assert not (path1 < path1) - - def test_simple_read(self, path1): - x = path1.join('samplefile').read('r') - assert x == 'samplefile\n' - - def test_join_div_operator(self, path1): - newpath = path1 / '/sampledir' / '/test//' - newpath2 = path1.join('sampledir', 'test') - assert newpath == newpath2 - - def test_ext(self, path1): - newpath = path1.join('sampledir.ext') - assert newpath.ext == '.ext' - newpath = path1.join('sampledir') - assert not newpath.ext - - def test_purebasename(self, path1): - newpath = path1.join('samplefile.py') - assert newpath.purebasename == 'samplefile' - - def test_multiple_parts(self, path1): - newpath = path1.join('samplefile.py') - dirname, purebasename, basename, ext = newpath._getbyspec( - 'dirname,purebasename,basename,ext') - assert str(path1).endswith(dirname) # be careful with win32 'drive' - assert purebasename == 'samplefile' - assert basename == 'samplefile.py' - assert ext == '.py' - - def test_dotted_name_ext(self, path1): - newpath = path1.join('a.b.c') - ext = newpath.ext - assert ext == '.c' - assert newpath.ext == '.c' - - def test_newext(self, path1): - newpath = path1.join('samplefile.py') - newext = newpath.new(ext='.txt') - assert newext.basename == "samplefile.txt" - assert newext.purebasename == "samplefile" - - def test_readlines(self, path1): - fn = path1.join('samplefile') - contents = fn.readlines() - assert contents == ['samplefile\n'] - - def test_readlines_nocr(self, path1): - fn = path1.join('samplefile') - contents = fn.readlines(cr=0) - assert contents == ['samplefile', ''] - - def test_file(self, path1): - assert path1.join('samplefile').check(file=1) - - def test_not_file(self, path1): - assert not path1.join("sampledir").check(file=1) - assert path1.join("sampledir").check(file=0) - - def test_non_existent(self, path1): - assert path1.join("sampledir.nothere").check(dir=0) - assert path1.join("sampledir.nothere").check(file=0) - assert path1.join("sampledir.nothere").check(notfile=1) - assert path1.join("sampledir.nothere").check(notdir=1) - assert path1.join("sampledir.nothere").check(notexists=1) - assert not path1.join("sampledir.nothere").check(notfile=0) - - # pattern = path1.sep.join(['s*file']) - # sfile = path1.join("samplefile") - # assert sfile.check(fnmatch=pattern) - - def test_size(self, path1): - url = path1.join("samplefile") - assert url.size() > len("samplefile") - - def test_mtime(self, path1): - url = path1.join("samplefile") - assert url.mtime() > 0 - - def test_relto_wrong_type(self, path1): - py.test.raises(TypeError, "path1.relto(42)") - - def test_visit_filesonly(self, path1): - l = [] - for i in path1.visit(lambda x: x.check(file=1)): - l.append(i.relto(path1)) - assert not "sampledir" in l - assert path1.sep.join(["sampledir", "otherfile"]) in l - - def test_load(self, path1): - p = path1.join('samplepickle') - obj = p.load() - assert type(obj) is dict - assert obj.get('answer',None) == 42 - - def test_visit_nodotfiles(self, path1): - l = [] - for i in path1.visit(lambda x: x.check(dotfile=0)): - l.append(i.relto(path1)) - assert "sampledir" in l - assert path1.sep.join(["sampledir", "otherfile"]) in l - assert not ".dotfile" in l - - def test_endswith(self, path1): - def chk(p): - return p.check(endswith="pickle") - assert not chk(path1) - assert not chk(path1.join('samplefile')) - assert chk(path1.join('somepickle')) - - def test_copy_file(self, path1): - otherdir = path1.join('otherdir') - initpy = otherdir.join('__init__.py') - copied = otherdir.join('copied') - initpy.copy(copied) - try: - assert copied.check() - s1 = initpy.read() - s2 = copied.read() - assert s1 == s2 - finally: - if copied.check(): - copied.remove() - - def test_copy_dir(self, path1): - otherdir = path1.join('otherdir') - copied = path1.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 - finally: - if copied.check(dir=1): - copied.remove(rec=1) - - def test_remove_file(self, path1): - d = path1.ensure('todeleted') - assert d.check() - d.remove() - assert not d.check() - - def test_remove_dir_recursive_by_default(self, path1): - d = path1.ensure('to', 'be', 'deleted') - assert d.check() - p = path1.join('to') - p.remove() - assert not p.check() - - def test_mkdir_and_remove(self, path1): - tmpdir = path1 - py.test.raises(py.error.EEXIST, tmpdir.mkdir, 'sampledir') - new = tmpdir.join('mktest1') - new.mkdir() - assert new.check(dir=1) - new.remove() - - new = tmpdir.mkdir('mktest') - assert new.check(dir=1) - new.remove() - assert tmpdir.join('mktest') == new - - def test_move_file(self, path1): - p = path1.join('samplefile') - newp = p.dirpath('moved_samplefile') - p.move(newp) - try: - assert newp.check(file=1) - assert not p.check() - finally: - dp = newp.dirpath() - if hasattr(dp, 'revert'): - dp.revert() - else: - newp.move(p) - assert p.check() - - def test_move_directory(self, path1): - source = path1.join('sampledir') - dest = path1.join('moveddir') - source.move(dest) - assert dest.check(dir=1) - assert dest.join('otherfile').check(file=1) - assert not source.join('sampledir').check() - -def setuptestfs(path): - if path.join('samplefile').check(): - 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') - - execfilepy = path.ensure('execfile.py') - execfilepy.write('x=42') - - d = {1:2, 'hello': 'world', 'answer': 42} - path.ensure('samplepickle').dump(d) - - sampledir = path.ensure('sampledir', dir=1) - sampledir.ensure('otherfile') - - otherdir = path.ensure('otherdir', dir=1) - otherdir.ensure('__init__.py') - - module_a = otherdir.ensure('a.py') - if sys.version_info >= (2,6): - module_a.write('from .b import stuff as result\n') - else: - module_a.write('from b import stuff as result\n') - module_b = otherdir.ensure('b.py') - module_b.write('stuff="got it"\n') - module_c = otherdir.ensure('c.py') - module_c.write('''import py; -import otherdir.a -value = otherdir.a.result -''') - module_d = otherdir.ensure('d.py') - module_d.write('''import py; -from otherdir import a -value2 = a.result -''') --- a/example/assertion/test_setup_flow_example.py +++ b/example/assertion/test_setup_flow_example.py @@ -9,7 +9,7 @@ class TestStateFullThing: cls.classcount -= 1 def setup_method(self, method): - self.id = eval(method.func_name[5:]) + self.id = eval(method.__name__[5:]) def test_42(self): assert self.classcount == 1 --- a/py/compat/testing/test_deprecation.py +++ /dev/null @@ -1,17 +0,0 @@ - -def test_functional_deprecation(testdir): - testdir.makepyfile(""" - import py - def test_compat_deprecations(recwarn): - for name in 'subprocess optparse textwrap doctest'.split(): - check(recwarn, name) - def check(recwarn, name): - x = getattr(py.compat, name) - recwarn.pop(DeprecationWarning) - recwarn.clear() - assert x == getattr(py.std, name) - """) - result = testdir.runpytest() - assert result.ret == 0 - - --- a/py/conftest.py +++ /dev/null @@ -1,55 +0,0 @@ -pytest_plugins = '_pytest doctest pytester'.split() - -rsyncdirs = ['.', '../doc'] - -import py -def pytest_addoption(parser): - group = parser.addgroup("pylib", "py lib testing options") - group.addoption('--sshhost', - action="store", dest="sshhost", default=None, - help=("ssh xspec for ssh functional tests. ")) - group.addoption('--gx', - action="append", dest="gspecs", default=None, - help=("add a global test environment, XSpec-syntax. ")) - group.addoption('--runslowtests', - action="store_true", dest="runslowtests", default=False, - help=("run slow tests")) - -def pytest_funcarg__specssh(request): - return getspecssh(request.config) -def pytest_funcarg__specsocket(request): - return getsocketspec(request.config) - - -# configuration information for tests -def getgspecs(config=None): - if config is None: - config = py.test.config - return [py.execnet.XSpec(spec) - for spec in config.getvalueorskip("gspecs")] - -def getspecssh(config=None): - xspecs = getgspecs(config) - for spec in xspecs: - if spec.ssh: - if not py.path.local.sysfind("ssh"): - py.test.skip("command not found: ssh") - return spec - py.test.skip("need '--gx ssh=...'") - -def getsocketspec(config=None): - xspecs = getgspecs(config) - for spec in xspecs: - if spec.socket: - return spec - py.test.skip("need '--gx socket=...'") - - -def pytest_generate_tests(metafunc): - multi = getattr(metafunc.function, 'multi', None) - if multi is None: - return - assert len(multi.__dict__) == 1 - for name, l in multi.__dict__.items(): - for val in l: - metafunc.addcall(funcargs={name: val}) --- a/py/path/testing/repotest.dump +++ /dev/null @@ -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 - --- a/example/funcarg/mysetup2/conftest.py +++ b/example/funcarg/mysetup2/conftest.py @@ -1,5 +1,5 @@ import py -from myapp import MyApp +from mysetup2.myapp import MyApp def pytest_funcarg__mysetup(request): return MySetup(request) --- a/py/path/testing/test_cacheutil.py +++ /dev/null @@ -1,81 +0,0 @@ -import py -from py.__.path import cacheutil - -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): - py.test.raises(KeyError, "self.cache._getentry(-23)") - - def test_delentry_non_raising(self): - val = self.cache.getorbuild(100, lambda: 100) - self.cache.delentry(100) - py.test.raises(KeyError, "self.cache._getentry(100)") - - 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 = cacheutil.BuildcostAccessCache(maxentries=128) - - def test_cache_works_somewhat_simple(self, monkeypatch): - cache = cacheutil.BuildcostAccessCache() - # the default gettime - # BuildcostAccessCache.build can - # result into time()-time() == 0 which makes the below - # test fail randomly. Let's rather use incrementing - # numbers instead. - l = [0] - def counter(): - l[0] = l[0] + 1 - return l[0] - monkeypatch.setattr(cacheutil, 'gettime', counter) - 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 - halfentries = int(cache.maxentries / 2) - for x in range(halfentries): - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(x, None) == x - # evict one entry - val = cache.getorbuild(-1, lambda: 42) - assert val == 42 - # check that recently used ones are still there - # and are not build again - for x in range(halfentries): - assert cache.getorbuild(x, None) == x - assert cache.getorbuild(-1, None) == 42 - - -class TestAging(BasicCacheAPITest): - maxsecs = 0.10 - cache = cacheutil.AgingCache(maxentries=128, maxseconds=maxsecs) - - def test_cache_eviction(self): - self.cache.getorbuild(17, lambda: 17) - endtime = py.std.time.time() + self.maxsecs * 10 - while py.std.time.time() < endtime: - try: - self.cache._getentry(17) - except KeyError: - break - py.std.time.sleep(self.maxsecs*0.3) - else: - py.test.fail("waiting for cache eviction failed") - -def test_prune_lowestweight(): - maxsecs = 0.05 - cache = cacheutil.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 commits-noreply at bitbucket.org Mon Sep 7 15:00:54 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 7 Sep 2009 13:00:54 +0000 (UTC) Subject: [py-svn] py-trunk commit 8f96e4ede295: regen setup.py and docs so that "python3 setup.py build" maybe works if setuptools does Message-ID: <20090907130054.D5619710A9@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252250257 -7200 # Node ID 8f96e4ede295d3171bf3ecd7477ac1ed9df2c34b # Parent b4b8bc6f107612f700a4585b7a9a7ebde7895871 regen setup.py and docs so that "python3 setup.py build" maybe works if setuptools does --- a/doc/test/plugin/links.txt +++ b/doc/test/plugin/links.txt @@ -1,38 +1,38 @@ .. _`helpconfig`: helpconfig.html .. _`terminal`: terminal.html -.. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_recwarn.py +.. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_recwarn.py .. _`unittest`: unittest.html -.. _`pytest_monkeypatch.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_monkeypatch.py -.. _`pytest_keyword.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_keyword.py +.. _`pytest_monkeypatch.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_monkeypatch.py +.. _`pytest_keyword.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_keyword.py .. _`pastebin`: pastebin.html .. _`plugins`: index.html -.. _`pytest_capture.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_capture.py -.. _`pytest_doctest.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_doctest.py +.. _`pytest_capture.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_capture.py +.. _`pytest_doctest.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_doctest.py .. _`capture`: capture.html -.. _`pytest_nose.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_nose.py -.. _`pytest_restdoc.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_restdoc.py +.. _`pytest_nose.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_nose.py +.. _`pytest_restdoc.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_restdoc.py .. _`xfail`: xfail.html -.. _`pytest_pastebin.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_pastebin.py -.. _`pytest_figleaf.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_figleaf.py -.. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_hooklog.py +.. _`pytest_pastebin.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_pastebin.py +.. _`pytest_figleaf.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_figleaf.py +.. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_hooklog.py .. _`checkout the py.test development version`: ../../download.html#checkout -.. _`pytest_helpconfig.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_helpconfig.py +.. _`pytest_helpconfig.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_helpconfig.py .. _`oejskit`: oejskit.html .. _`doctest`: doctest.html .. _`get in contact`: ../../contact.html -.. _`pytest_xfail.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_xfail.py +.. _`pytest_xfail.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_xfail.py .. _`figleaf`: figleaf.html .. _`customize`: ../customize.html .. _`hooklog`: hooklog.html -.. _`pytest_terminal.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_terminal.py +.. _`pytest_terminal.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_terminal.py .. _`recwarn`: recwarn.html -.. _`pytest_pdb.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_pdb.py +.. _`pytest_pdb.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_pdb.py .. _`monkeypatch`: monkeypatch.html .. _`resultlog`: resultlog.html .. _`keyword`: keyword.html .. _`restdoc`: restdoc.html .. _`django`: django.html -.. _`pytest_unittest.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_unittest.py +.. _`pytest_unittest.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_unittest.py .. _`nose`: nose.html -.. _`pytest_resultlog.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.2/py/test/plugin/pytest_resultlog.py +.. _`pytest_resultlog.py`: http://bitbucket.org/hpk42/py-trunk/raw/trunk/py/test/plugin/pytest_resultlog.py .. _`pdb`: pdb.html --- a/doc/test/plugin/monkeypatch.txt +++ b/doc/test/plugin/monkeypatch.txt @@ -10,8 +10,8 @@ safely patch object attributes, dicts an Usage ---------------- -Use the `monkeypatch funcarg`_ to safely patch environment -variables, object attributes or dictionaries. For example, if you want +Use the `monkeypatch funcarg`_ to safely modify or delete environment +variables, object attributes or dictionary values. For example, if you want to set the environment variable ``ENV1`` and patch the ``os.path.abspath`` function to return a particular value during a test function execution you can write it down like this: @@ -37,6 +37,20 @@ can use this example: monkeypatch.setenv('PATH', 'x/y', prepend=":") # x/y will be at the beginning of $PATH +calling "undo" finalization explicitely +----------------------------------------- + +Usually at the end of function execution py.test will invoke +a teardown hook which undoes the changes. If you cannot wait +that long you can also call finalization explicitely:: + + monkeypatch.undo() + +This will undo previous changes. This call consumes the +undo stack. Calling it a second time has no effect. +Within a test you can continue to use the monkeypatch +object, however. + .. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ .. _`monkeypatch funcarg`: @@ -45,15 +59,22 @@ can use this example: the 'monkeypatch' test function argument ---------------------------------------- -The returned ``monkeypatch`` funcarg provides three +The returned ``monkeypatch`` funcarg provides these helper methods to modify objects, dictionaries or os.environ:: monkeypatch.setattr(obj, name, value) + monkeypatch.delattr(obj, name, raising=True) monkeypatch.setitem(mapping, name, value) - monkeypatch.setenv(name, value) + monkeypatch.delitem(obj, name, raising=True) + monkeypatch.setenv(name, value, prepend=False) + monkeypatch.delenv(name, value, raising=True) + monkeypatch.syspath_prepend(path) -All such modifications will be undone when the requesting -test function finished its execution. +All modifications will be undone when the requesting +test function finished its execution. For the ``del`` +methods the ``raising`` parameter determines if a +KeyError or AttributeError will be raised if the +deletion has no target. Start improving this plugin in 30 seconds ========================================= --- a/doc/test/plugin/capture.txt +++ b/doc/test/plugin/capture.txt @@ -32,8 +32,8 @@ on tests that wait on reading something You can influence output capturing mechanisms from the command line:: py.test -s # disable all capturing - py.test --capture=sys # set StringIO() to each of sys.stdout/stderr - py.test --capture=fd # capture stdout/stderr on Filedescriptors 1/2 + py.test --capture=sys # replace sys.stdout/stderr with in-mem files + py.test --capture=fd # point filedescriptors 1 and 2 to temp file If you set capturing values in a conftest file like this:: @@ -46,7 +46,9 @@ sys-level capturing ------------------------------------------ Capturing on 'sys' level means that ``sys.stdout`` and ``sys.stderr`` -will be replaced with StringIO() objects. +will be replaced with in-memory files (``py.io.TextIO`` to be precise) +that capture writes and decode non-unicode strings to a unicode object +(using a default, usually, UTF-8, encoding). FD-level capturing and subprocesses ------------------------------------------ @@ -71,8 +73,9 @@ per-test capturing. Here is an example .. sourcecode:: python def test_myoutput(capsys): - print "hello" - print >>sys.stderr, "world" + print ("hello") + sys.stderr.write("world +") out, err = capsys.readouterr() assert out == "hello\n" assert err == "world\n" --- a/setup.py +++ b/setup.py @@ -23,6 +23,7 @@ For questions please check out http://py .. _`py.path`: http://pylib.org/path.html .. _`py.code`: http://pylib.org/code.html +(c) Holger Krekel and others, 2009 """ trunk = 'trunk' @@ -58,44 +59,25 @@ def main(): 'Topic :: Utilities', 'Programming Language :: Python'], packages=['py', - 'py._testing', 'py.builtin', - 'py.builtin.testing', 'py.cmdline', - 'py.cmdline.testing', 'py.code', - 'py.code.testing', 'py.compat', - 'py.compat.testing', 'py.execnet', 'py.execnet.script', - 'py.execnet.testing', 'py.io', - 'py.io.testing', 'py.log', - 'py.log.testing', 'py.path', 'py.path.gateway', - 'py.path.testing', 'py.process', - 'py.process.testing', 'py.rest', - 'py.rest.testing', 'py.test', 'py.test.dist', - 'py.test.dist.testing', 'py.test.looponfail', - 'py.test.looponfail.testing', 'py.test.plugin', - 'py.test.testing', - 'py.test.testing.import_test.package', 'py.test.web', - 'py.thread', - 'py.thread.testing', - 'py.xmlobj', - 'py.xmlobj.testing'], - package_data={'py': ['LICENSE', - 'bin/_findpy.py', + 'py.thread'], + package_data={'py': ['bin/_findpy.py', 'bin/env.cmd', 'bin/env.py', 'bin/py.cleanup', @@ -114,23 +96,7 @@ def main(): 'bin/win32/py.svnwcrevert.cmd', 'bin/win32/py.test.cmd', 'bin/win32/py.which.cmd', - 'compat/LICENSE', - 'compat/testing/test_doctest.txt', - 'compat/testing/test_doctest2.txt', - 'execnet/NOTES', - 'execnet/improve-remote-tracebacks.txt', - 'path/gateway/TODO.txt', - 'path/notes-svn-quoting.txt', - 'path/testing/repotest.dump', - 'rest/rest.sty.template', - 'rest/testing/data/example.rst2pdfconfig', - 'rest/testing/data/example1.dot', - 'rest/testing/data/formula.txt', - 'rest/testing/data/formula1.txt', - 'rest/testing/data/graphviz.txt', - 'rest/testing/data/part1.txt', - 'rest/testing/data/part2.txt', - 'rest/testing/data/tocdepth.rst2pdfconfig']}, + 'rest/rest.sty.template']}, zip_safe=False, ) From commits-noreply at bitbucket.org Mon Sep 7 15:01:02 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 7 Sep 2009 13:01:02 +0000 (UTC) Subject: [py-svn] py-trunk commit e972df3fae4d: some fixes to support Jython better Message-ID: <20090907130102.E65FE710FB@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252328366 -7200 # Node ID e972df3fae4d69929dedbe85b20f0f81d64cd915 # Parent 8f96e4ede295d3171bf3ecd7477ac1ed9df2c34b some fixes to support Jython better --- a/py/execnet/gateway.py +++ b/py/execnet/gateway.py @@ -327,6 +327,8 @@ def stdouterrin_setnull(): # blocks there, while it works (sending to stderr if possible else # ignoring) on *nix import sys, os + if not hasattr(os, 'dup'): # jython + return try: devnull = os.devnull except AttributeError: --- a/testing/code/test_code.py +++ b/testing/code/test_code.py @@ -53,7 +53,7 @@ def test_newcode_with_filename(): filename = MyStr("hello") filename.__source__ = py.code.Source(source) newco = code.new(rec=True, co_filename=filename) - assert newco.co_filename is filename + assert newco.co_filename.__source__ == filename.__source__ s = py.code.Source(newco) assert str(s) == source --- a/py/code/code.py +++ b/py/code/code.py @@ -32,7 +32,7 @@ class Code(object): for name in kwargs: if name not in names: raise TypeError("unknown code attribute: %r" %(name, )) - if rec: + if rec and hasattr(self.raw, 'co_consts'): # jython newconstlist = [] co = self.raw cotype = type(co) @@ -47,22 +47,24 @@ class Code(object): arglist = [ kwargs['co_argcount'], kwargs['co_nlocals'], - kwargs['co_stacksize'], - kwargs['co_flags'], - kwargs['co_code'], - kwargs['co_consts'], - kwargs['co_names'], + kwargs.get('co_stacksize', 0), # jython + kwargs.get('co_flags', 0), # jython + kwargs.get('co_code', ''), # jython + kwargs.get('co_consts', ()), # jython + kwargs.get('co_names', []), # kwargs['co_varnames'], kwargs['co_filename'], kwargs['co_name'], kwargs['co_firstlineno'], - kwargs['co_lnotab'], - kwargs['co_freevars'], - kwargs['co_cellvars'], + kwargs.get('co_lnotab', ''), #jython + kwargs.get('co_freevars', None), #jython + kwargs.get('co_cellvars', None), # jython ] if sys.version_info >= (3,0): arglist.insert(1, kwargs['co_kwonlyargcount']) - return self.raw.__class__(*arglist) + return self.raw.__class__(*arglist) + else: + return py.std.new.code(*arglist) def path(self): """ return a py.path.local object pointing to the source code """ From commits-noreply at bitbucket.org Mon Sep 7 17:54:08 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 7 Sep 2009 15:54:08 +0000 (UTC) Subject: [py-svn] py-trunk commit 92aeb806f7f0: monkeypatch, doc, apiwarn, deprecation fixes Message-ID: <20090907155408.86A1B71100@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252338830 -7200 # Node ID 92aeb806f7f0b544a4ee6865e0bea79a27d387be # Parent e972df3fae4d69929dedbe85b20f0f81d64cd915 monkeypatch, doc, apiwarn, deprecation fixes --- a/testing/log/test_warning.py +++ b/testing/log/test_warning.py @@ -6,7 +6,7 @@ def test_forwarding_to_warnings_module() def test_apiwarn_functional(): capture = py.io.StdCapture() - py.log._apiwarn("x.y.z", "something") + py.log._apiwarn("x.y.z", "something", stacklevel=1) out, err = capture.reset() py.builtin.print_("out", out) py.builtin.print_("err", err) --- a/py/log/warning.py +++ b/py/log/warning.py @@ -10,11 +10,11 @@ class Warning(DeprecationWarning): def __str__(self): return self.msg -def _apiwarn(startversion, msg, stacklevel=1, function=None): +def _apiwarn(startversion, msg, stacklevel=2, function=None): # below is mostly COPIED from python2.4/warnings.py's def warn() # Get context information if stacklevel == "initpkg": - frame = sys._getframe(1) + frame = sys._getframe(stacklevel == "initpkg" and 1 or stacklevel) level = 2 while frame: co = frame.f_code --- a/testing/pytest/plugin/test_pytest_monkeypatch.py +++ b/testing/pytest/plugin/test_pytest_monkeypatch.py @@ -6,6 +6,13 @@ def test_setattr(): class A: x = 1 monkeypatch = MonkeyPatch() + py.test.raises(AttributeError, "monkeypatch.setattr(A, 'notexists', 2)") + monkeypatch.setattr(A, 'y', 2, raising=False) + assert A.y == 2 + monkeypatch.undo() + assert not hasattr(A, 'y') + + monkeypatch = MonkeyPatch() monkeypatch.setattr(A, 'x', 2) assert A.x == 2 monkeypatch.setattr(A, 'x', 3) @@ -17,11 +24,6 @@ def test_setattr(): monkeypatch.undo() # double-undo makes no modification assert A.x == 5 - monkeypatch.setattr(A, 'y', 3) - assert A.y == 3 - monkeypatch.undo() - assert not hasattr(A, 'y') - def test_delattr(): class A: x = 1 @@ -35,7 +37,7 @@ def test_delattr(): monkeypatch.delattr(A, 'x') py.test.raises(AttributeError, "monkeypatch.delattr(A, 'y')") monkeypatch.delattr(A, 'y', raising=False) - monkeypatch.setattr(A, 'x', 5) + monkeypatch.setattr(A, 'x', 5, raising=False) assert A.x == 5 monkeypatch.undo() assert A.x == 1 @@ -45,6 +47,7 @@ def test_setitem(): monkeypatch = MonkeyPatch() monkeypatch.setitem(d, 'x', 2) monkeypatch.setitem(d, 'y', 1700) + monkeypatch.setitem(d, 'y', 1700) assert d['x'] == 2 assert d['y'] == 1700 monkeypatch.setitem(d, 'x', 3) --- a/py/test/plugin/pytest_capture.py +++ b/py/test/plugin/pytest_capture.py @@ -68,7 +68,7 @@ per-test capturing. Here is an example def test_myoutput(capsys): print ("hello") - sys.stderr.write("world\n") + sys.stderr.write("world\\n") out, err = capsys.readouterr() assert out == "hello\\n" assert err == "world\\n" --- a/doc/test/plugin/capture.txt +++ b/doc/test/plugin/capture.txt @@ -74,8 +74,7 @@ per-test capturing. Here is an example def test_myoutput(capsys): print ("hello") - sys.stderr.write("world -") + sys.stderr.write("world\n") out, err = capsys.readouterr() assert out == "hello\n" assert err == "world\n" --- a/py/test/plugin/pytest_monkeypatch.py +++ b/py/test/plugin/pytest_monkeypatch.py @@ -1,49 +1,54 @@ """ safely patch object attributes, dicts and environment variables. -Usage +Usage ---------------- -Use the `monkeypatch funcarg`_ to safely modify or delete environment -variables, object attributes or dictionary values. For example, if you want -to set the environment variable ``ENV1`` and patch the -``os.path.abspath`` function to return a particular value during a test -function execution you can write it down like this: +Use the `monkeypatch funcarg`_ to tweak your global test environment +for running a particular test. You can safely set/del an attribute, +dictionary item or environment variable by respective methods +on the monkeypatch funcarg. If you want e.g. to set an ENV1 variable +and have os.path.expanduser return a particular directory, you can +write it down like this: .. sourcecode:: python def test_mytest(monkeypatch): monkeypatch.setenv('ENV1', 'myval') - monkeypatch.setattr(os.path, 'abspath', lambda x: '/') - ... # your test code + monkeypatch.setattr(os.path, 'expanduser', lambda x: '/tmp/xyz') + ... # your test code that uses those patched values implicitely -The function argument will do the modifications and memorize the -old state. After the test function finished execution all -modifications will be reverted. See the `monkeypatch blog post`_ -for an extensive discussion. +After the test function finished all modifications will be undone, +because the ``monkeypatch.undo()`` method is registered as a finalizer. -To add to a possibly existing environment parameter you -can use this example: +``monkeypatch.setattr/delattr/delitem/delenv()`` all +by default raise an Exception if the target does not exist. +Pass ``raising=False`` if you want to skip this check. + +prepending to PATH or other environment variables +--------------------------------------------------------- + +To prepend a value to an already existing environment parameter: .. sourcecode:: python def test_mypath_finding(monkeypatch): monkeypatch.setenv('PATH', 'x/y', prepend=":") - # x/y will be at the beginning of $PATH + # in bash language: export PATH=x/y:$PATH calling "undo" finalization explicitely ----------------------------------------- -Usually at the end of function execution py.test will invoke -a teardown hook which undoes the changes. If you cannot wait -that long you can also call finalization explicitely:: +At the end of function execution py.test invokes +a teardown hook which undoes all monkeypatch changes. +If you do not want to wait that long you can call +finalization explicitely:: monkeypatch.undo() This will undo previous changes. This call consumes the -undo stack. Calling it a second time has no effect. -Within a test you can continue to use the monkeypatch -object, however. +undo stack. Calling it a second time has no effect unless +you start monkeypatching after the undo call. .. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ """ @@ -54,7 +59,7 @@ def pytest_funcarg__monkeypatch(request) """The returned ``monkeypatch`` funcarg provides these helper methods to modify objects, dictionaries or os.environ:: - monkeypatch.setattr(obj, name, value) + monkeypatch.setattr(obj, name, value, raising=True) monkeypatch.delattr(obj, name, raising=True) monkeypatch.setitem(mapping, name, value) monkeypatch.delitem(obj, name, raising=True) @@ -79,8 +84,11 @@ class MonkeyPatch: self._setattr = [] self._setitem = [] - def setattr(self, obj, name, value): - self._setattr.insert(0, (obj, name, getattr(obj, name, notset))) + def setattr(self, obj, name, value, raising=True): + oldval = getattr(obj, name, notset) + if raising and oldval is notset: + raise AttributeError("%r has no attribute %r" %(obj, name)) + self._setattr.insert(0, (obj, name, oldval)) setattr(obj, name, value) def delattr(self, obj, name, raising=True): --- a/doc/test/plugin/monkeypatch.txt +++ b/doc/test/plugin/monkeypatch.txt @@ -7,49 +7,54 @@ safely patch object attributes, dicts an .. contents:: :local: -Usage +Usage ---------------- -Use the `monkeypatch funcarg`_ to safely modify or delete environment -variables, object attributes or dictionary values. For example, if you want -to set the environment variable ``ENV1`` and patch the -``os.path.abspath`` function to return a particular value during a test -function execution you can write it down like this: +Use the `monkeypatch funcarg`_ to tweak your global test environment +for running a particular test. You can safely set/del an attribute, +dictionary item or environment variable by respective methods +on the monkeypatch funcarg. If you want e.g. to set an ENV1 variable +and have os.path.expanduser return a particular directory, you can +write it down like this: .. sourcecode:: python def test_mytest(monkeypatch): monkeypatch.setenv('ENV1', 'myval') - monkeypatch.setattr(os.path, 'abspath', lambda x: '/') - ... # your test code + monkeypatch.setattr(os.path, 'expanduser', lambda x: '/tmp/xyz') + ... # your test code that uses those patched values implicitely -The function argument will do the modifications and memorize the -old state. After the test function finished execution all -modifications will be reverted. See the `monkeypatch blog post`_ -for an extensive discussion. +After the test function finished all modifications will be undone, +because the ``monkeypatch.undo()`` method is registered as a finalizer. -To add to a possibly existing environment parameter you -can use this example: +``monkeypatch.setattr/delattr/delitem/delenv()`` all +by default raise an Exception if the target does not exist. +Pass ``raising=False`` if you want to skip this check. + +prepending to PATH or other environment variables +--------------------------------------------------------- + +To prepend a value to an already existing environment parameter: .. sourcecode:: python def test_mypath_finding(monkeypatch): monkeypatch.setenv('PATH', 'x/y', prepend=":") - # x/y will be at the beginning of $PATH + # in bash language: export PATH=x/y:$PATH calling "undo" finalization explicitely ----------------------------------------- -Usually at the end of function execution py.test will invoke -a teardown hook which undoes the changes. If you cannot wait -that long you can also call finalization explicitely:: +At the end of function execution py.test invokes +a teardown hook which undoes all monkeypatch changes. +If you do not want to wait that long you can call +finalization explicitely:: monkeypatch.undo() This will undo previous changes. This call consumes the -undo stack. Calling it a second time has no effect. -Within a test you can continue to use the monkeypatch -object, however. +undo stack. Calling it a second time has no effect unless +you start monkeypatching after the undo call. .. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ @@ -62,7 +67,7 @@ the 'monkeypatch' test function argument The returned ``monkeypatch`` funcarg provides these helper methods to modify objects, dictionaries or os.environ:: - monkeypatch.setattr(obj, name, value) + monkeypatch.setattr(obj, name, value, raising=True) monkeypatch.delattr(obj, name, raising=True) monkeypatch.setitem(mapping, name, value) monkeypatch.delitem(obj, name, raising=True) --- a/doc/download.txt +++ b/doc/download.txt @@ -10,7 +10,8 @@ using easy_install =================================================== -With a working `setuptools installation`_ you can type:: +With a working `setuptools installation`_ or `distribute installation`_ +you can type:: easy_install -U py @@ -19,19 +20,11 @@ will trigger an upgrade if you already h On Linux systems you may need to execute the command as superuser and on Windows you might need to write down the full path to ``easy_install``. The py lib and its tools are expected to work well on Linux, -Windows and OSX, Python versions 2.3, 2.4, 2.5 and 2.6. - -**IMPORTANT NOTE**: if you are using Windows and have -0.8 versions of the py lib on your system, please download -and execute http://codespeak.net/svn/py/build/winpathclean.py -This will check that no previous files are getting in the way. -You can find out the py lib version with:: - - import py - print py.version - +Windows and OSX, Python versions 2.4, 2.5, 2.6 through to +the Python3 versions 3.0 and 3.1. .. _mercurial: http://mercurial.selenic.com/wiki/ +.. _`distribute installation`: http://pypi.python.org/pypi/distribute .. _checkout: .. _tarball: --- a/doc/confrest.py +++ b/doc/confrest.py @@ -148,7 +148,7 @@ def getrealname(username): class Project: - mydir = py.magic.autopath().dirpath() + mydir = py.path.local(__file__).dirpath() title = "py lib" prefix_title = "" # we have a logo already containing "py lib" encoding = 'latin1' From commits-noreply at bitbucket.org Tue Sep 8 10:00:14 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 8 Sep 2009 08:00:14 +0000 (UTC) Subject: [py-svn] py-trunk commit 869e75a384c7: relicense to LGPL, add an FAQ entry reasoning about it. Message-ID: <20090908080014.5E7A271114@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252396639 -7200 # Node ID 869e75a384c7e23f12974073ba0612cf740f3cb7 # Parent 92aeb806f7f0b544a4ee6865e0bea79a27d387be relicense to LGPL, add an FAQ entry reasoning about it. --- a/doc/faq.txt +++ b/doc/faq.txt @@ -6,8 +6,9 @@ Frequently Asked Questions :local: :depth: 2 -On naming, nose and magic -============================ + +On naming, nosetests, licensing and magic +=========================================== Why the ``py`` naming? what is it? ------------------------------------ @@ -31,8 +32,8 @@ was to make it obvious where testing fun for the ``py.test`` command line tool is: in the ``py.test`` package name space. -What's the relation to ``nosetests``? ----------------------------------------- +What's py.test's relation to ``nosetests``? +--------------------------------------------- py.test and nose_ share basic philosophy when it comes to running Python tests. In fact, @@ -45,6 +46,44 @@ have no counterpart in nose_. .. _nose: http://somethingaboutorange.com/mrl/projects/nose/0.11.1/ .. _features: test/features.html +.. _whygpl: + +Why did you choose a GPL-style license? +---------------------------------------- + +Older versions of the py lib and (up until 1.0.x) +were licensed under the MIT license. Starting +with the 1.1 series Holger Krekel - being the main maintainer +and developer since several years - decided to go for +a GPL-style license mainly for these reasons: + +1. increase likelyness of flow-back, contributions and publicity. + +2. make use of the FSF_ efforts which produced a consistent and interoperable legal framework. + +3. Potentially get some money from dual-licensing to companies. + +Developers want to co-operate no matter what context they +are in, commercial, free, whatever. BSD-licenses sound like +a fit because they minimize the need for checking for +constraints from the company or legal department. + +Developers wanting to produce free software for a living also +want to connect to a sustainable revenue system, however. When +releasing software for public use they want to seek means, +some security on getting something back: Contributions, +recognition or money. The GPL license tries to foster a +universe of free software and force proprietary players +to contribute back. + +Choosing the Lesser GPL kind of strikes a balance - it allows +the code to interact in proprietary contexts but increases +likelyness of flow backs. Practically it all does not make +much of a difference. Anyway, if you do have actual practical +issues regarding the license please just get in contact. + +.. _fsf: http://www.fsf.org + What's all this "magic" with py.test? ---------------------------------------- @@ -119,5 +158,3 @@ and implement the `parametrization schem .. _`pytest_generate_tests`: test/funcargs.html#parametrizing-tests .. _`parametrization scheme of your choice`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/ - - --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,165 @@ -All files in the 'py' directory are licensed under the MIT license: + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. From commits-noreply at bitbucket.org Wed Sep 9 13:39:01 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 9 Sep 2009 11:39:01 +0000 (UTC) Subject: [py-svn] py-trunk commit d9e4ef1a07e9: * moving execnet tests to funcarg-style, some cleanup Message-ID: <20090909113901.2E1F071102@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252397436 -7200 # Node ID d9e4ef1a07e999a0fc810516a76c56cb4f473707 # Parent 869e75a384c7e23f12974073ba0612cf740f3cb7 * moving execnet tests to funcarg-style, some cleanup * slight refinement to FAQ license topic --- a/testing/execnet/test_gateway.py +++ b/testing/execnet/test_gateway.py @@ -1,34 +1,27 @@ -from __future__ import generators +""" +mostly functional tests of gateways. +""" import os, sys, time import py from py.__.execnet import gateway_base, gateway queue = py.builtin._tryimport('queue', 'Queue') -pytest_plugins = "pytester" +TESTTIMEOUT = 10.0 # seconds + +class TestBasicRemoteExecution: + def test_correct_setup(self, gw): + assert gw._receiverthread.isAlive() -TESTTIMEOUT = 10.0 # seconds + def test_repr_doesnt_crash(self, gw): + assert isinstance(repr(gw), str) -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._receiverthread.isAlive() - - def test_repr_doesnt_crash(self): - assert isinstance(repr(self.gw), str) - - def test_attribute__name__(self): - channel = self.gw.remote_exec("channel.send(__name__)") + def test_attribute__name__(self, gw): + channel = gw.remote_exec("channel.send(__name__)") name = channel.receive() assert name == "__channelexec__" - def test_correct_setup_no_py(self): - channel = self.gw.remote_exec(""" + def test_correct_setup_no_py(self, gw): + channel = gw.remote_exec(""" import sys channel.send(list(sys.modules)) """) @@ -36,25 +29,25 @@ class BasicRemoteExecution: assert 'py' not in remotemodules, ( "py should not be imported on remote side") - def test_remote_exec_waitclose(self): - channel = self.gw.remote_exec('pass') + def test_remote_exec_waitclose(self, gw): + channel = gw.remote_exec('pass') channel.waitclose(TESTTIMEOUT) - def test_remote_exec_waitclose_2(self): - channel = self.gw.remote_exec('def gccycle(): pass') + def test_remote_exec_waitclose_2(self, gw): + channel = gw.remote_exec('def gccycle(): pass') channel.waitclose(TESTTIMEOUT) - def test_remote_exec_waitclose_noarg(self): - channel = self.gw.remote_exec('pass') + def test_remote_exec_waitclose_noarg(self, gw): + channel = gw.remote_exec('pass') channel.waitclose() - def test_remote_exec_error_after_close(self): - channel = self.gw.remote_exec('pass') + def test_remote_exec_error_after_close(self, gw): + channel = gw.remote_exec('pass') channel.waitclose(TESTTIMEOUT) py.test.raises(IOError, channel.send, 0) - def test_remote_exec_channel_anonymous(self): - channel = self.gw.remote_exec(''' + def test_remote_exec_channel_anonymous(self, gw): + channel = gw.remote_exec(''' obj = channel.receive() channel.send(obj) ''') @@ -62,37 +55,38 @@ class BasicRemoteExecution: result = channel.receive() assert result == 42 - def test_channel_close_and_then_receive_error(self): - channel = self.gw.remote_exec('raise ValueError') +class TestChannelBasicBehaviour: + def test_channel_close_and_then_receive_error(self, gw): + channel = gw.remote_exec('raise ValueError') py.test.raises(channel.RemoteError, channel.receive) - def test_channel_finish_and_then_EOFError(self): - channel = self.gw.remote_exec('channel.send(42)') + def test_channel_finish_and_then_EOFError(self, gw): + channel = 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') + def test_channel_close_and_then_receive_error_multiple(self, gw): + channel = gw.remote_exec('channel.send(42) ; raise ValueError') x = channel.receive() assert x == 42 py.test.raises(channel.RemoteError, channel.receive) - def test_channel__local_close(self): - channel = self.gw._channelfactory.new() - self.gw._channelfactory._local_close(channel.id) + def test_channel__local_close(self, gw): + channel = gw._channelfactory.new() + gw._channelfactory._local_close(channel.id) channel.waitclose(0.1) - def test_channel__local_close_error(self): - channel = self.gw._channelfactory.new() - self.gw._channelfactory._local_close(channel.id, + def test_channel__local_close_error(self, gw): + channel = gw._channelfactory.new() + gw._channelfactory._local_close(channel.id, channel.RemoteError("error")) py.test.raises(channel.RemoteError, channel.waitclose, 0.01) - def test_channel_error_reporting(self): - channel = self.gw.remote_exec('def foo():\n return foobar()\nfoo()\n') + def test_channel_error_reporting(self, gw): + channel = gw.remote_exec('def foo():\n return foobar()\nfoo()\n') try: channel.receive() except channel.RemoteError: @@ -103,9 +97,9 @@ class BasicRemoteExecution: else: py.test.fail('No exception raised') - def test_channel_syntax_error(self): + def test_channel_syntax_error(self, gw): # missing colon - channel = self.gw.remote_exec('def foo()\n return 1\nfoo()\n') + channel = gw.remote_exec('def foo()\n return 1\nfoo()\n') try: channel.receive() except channel.RemoteError: @@ -113,16 +107,16 @@ class BasicRemoteExecution: assert str(e).startswith('Traceback (most recent call last):') assert str(e).find('SyntaxError') > -1 - def test_channel_iter(self): - channel = self.gw.remote_exec(""" + def test_channel_iter(self, gw): + channel = gw.remote_exec(""" for x in range(3): channel.send(x) """) l = list(channel) assert l == [0, 1, 2] - def test_channel_passing_over_channel(self): - channel = self.gw.remote_exec(''' + def test_channel_passing_over_channel(self, gw): + channel = gw.remote_exec(''' c = channel.gateway.newchannel() channel.send(c) c.send(42) @@ -133,17 +127,17 @@ class BasicRemoteExecution: # check that the both sides previous channels are really gone channel.waitclose(TESTTIMEOUT) - #assert c.id not in self.gw._channelfactory - newchan = self.gw.remote_exec(''' + #assert c.id not in gw._channelfactory + newchan = gw.remote_exec(''' assert %d not in channel.gateway._channelfactory._channels ''' % (channel.id)) newchan.waitclose(TESTTIMEOUT) - assert channel.id not in self.gw._channelfactory._channels + assert channel.id not in gw._channelfactory._channels - def test_channel_receiver_callback(self): + def test_channel_receiver_callback(self, gw): l = [] - #channel = self.gw.newchannel(receiver=l.append) - channel = self.gw.remote_exec(source=''' + #channel = gw.newchannel(receiver=l.append) + channel = gw.remote_exec(source=''' channel.send(42) channel.send(13) channel.send(channel.gateway.newchannel()) @@ -155,9 +149,9 @@ class BasicRemoteExecution: assert l[:2] == [42,13] assert isinstance(l[2], channel.__class__) - def test_channel_callback_after_receive(self): + def test_channel_callback_after_receive(self, gw): l = [] - channel = self.gw.remote_exec(source=''' + channel = gw.remote_exec(source=''' channel.send(42) channel.send(13) channel.send(channel.gateway.newchannel()) @@ -171,25 +165,25 @@ class BasicRemoteExecution: assert l[0] == 13 assert isinstance(l[1], channel.__class__) - def test_waiting_for_callbacks(self): + def test_waiting_for_callbacks(self, gw): l = [] def callback(msg): import time; time.sleep(0.2) l.append(msg) - channel = self.gw.remote_exec(source=''' + channel = gw.remote_exec(source=''' channel.send(42) ''') channel.setcallback(callback) channel.waitclose(TESTTIMEOUT) assert l == [42] - def test_channel_callback_stays_active(self): - self.check_channel_callback_stays_active(earlyfree=True) + def test_channel_callback_stays_active(self, gw): + self.check_channel_callback_stays_active(gw, earlyfree=True) - def check_channel_callback_stays_active(self, earlyfree=True): + def check_channel_callback_stays_active(self, gw, earlyfree=True): # with 'earlyfree==True', this tests the "sendonly" channel state. l = [] - channel = self.gw.remote_exec(source=''' + channel = gw.remote_exec(source=''' try: import thread except ImportError: @@ -203,7 +197,7 @@ class BasicRemoteExecution: thread.start_new_thread(producer, (channel2,)) del channel2 ''') - subchannel = self.gw.newchannel() + subchannel = gw.newchannel() subchannel.setcallback(l.append) channel.send(subchannel) if earlyfree: @@ -220,13 +214,14 @@ class BasicRemoteExecution: assert l == [0, 100, 200, 300, 400] return subchannel - def test_channel_callback_remote_freed(self): - channel = self.check_channel_callback_stays_active(earlyfree=False) - channel.waitclose(TESTTIMEOUT) # freed automatically at the end of producer() + def test_channel_callback_remote_freed(self, gw): + channel = self.check_channel_callback_stays_active(gw, earlyfree=False) + # freed automatically at the end of producer() + channel.waitclose(TESTTIMEOUT) - def test_channel_endmarker_callback(self): + def test_channel_endmarker_callback(self, gw): l = [] - channel = self.gw.remote_exec(source=''' + channel = gw.remote_exec(source=''' channel.send(42) channel.send(13) channel.send(channel.gateway.newchannel()) @@ -239,9 +234,9 @@ class BasicRemoteExecution: assert isinstance(l[2], channel.__class__) assert l[3] == 999 - def test_channel_endmarker_callback_error(self): + def test_channel_endmarker_callback_error(self, gw): q = queue.Queue() - channel = self.gw.remote_exec(source=''' + channel = gw.remote_exec(source=''' raise ValueError() ''') channel.setcallback(q.put, endmarker=999) @@ -252,20 +247,20 @@ class BasicRemoteExecution: assert str(err).find("ValueError") != -1 @py.test.mark.xfail - def test_remote_redirect_stdout(self): + def test_remote_redirect_stdout(self, gw): out = py.io.TextIO() - handle = self.gw._remote_redirect(stdout=out) - c = self.gw.remote_exec("print 42") + handle = gw._remote_redirect(stdout=out) + c = gw.remote_exec("print 42") c.waitclose(TESTTIMEOUT) handle.close() s = out.getvalue() assert s.strip() == "42" @py.test.mark.xfail - def test_remote_exec_redirect_multi(self): + def test_remote_exec_redirect_multi(self, gw): num = 3 l = [[] for x in range(num)] - channels = [self.gw.remote_exec("print %d" % i, + channels = [gw.remote_exec("print %d" % i, stdout=l[i].append) for i in range(num)] for x in channels: @@ -277,8 +272,9 @@ class BasicRemoteExecution: s = subl[0] assert s.strip() == str(i) - def test_channel_file_write(self): - channel = self.gw.remote_exec(""" +class TestChannelFile: + def test_channel_file_write(self, gw): + channel = gw.remote_exec(""" f = channel.makefile() f.write("hello world\\n") f.close() @@ -289,14 +285,14 @@ class BasicRemoteExecution: second = channel.receive() assert second == 42 - def test_channel_file_write_error(self): - channel = self.gw.remote_exec("pass") + def test_channel_file_write_error(self, gw): + channel = gw.remote_exec("pass") f = channel.makefile() channel.waitclose(TESTTIMEOUT) py.test.raises(IOError, f.write, 'hello') - def test_channel_file_proxyclose(self): - channel = self.gw.remote_exec(""" + def test_channel_file_proxyclose(self, gw): + channel = gw.remote_exec(""" f = channel.makefile(proxyclose=True) f.write("hello world") f.close() @@ -306,8 +302,8 @@ class BasicRemoteExecution: assert first.strip() == 'hello world' py.test.raises(EOFError, channel.receive) - def test_channel_file_read(self): - channel = self.gw.remote_exec(""" + def test_channel_file_read(self, gw): + channel = gw.remote_exec(""" f = channel.makefile(mode='r') s = f.read(2) channel.send(s) @@ -320,16 +316,16 @@ class BasicRemoteExecution: assert s1 == "xy" assert s2 == "abcde" - def test_channel_file_read_empty(self): - channel = self.gw.remote_exec("pass") + def test_channel_file_read_empty(self, gw): + channel = gw.remote_exec("pass") f = channel.makefile(mode="r") s = f.read(3) assert s == "" s = f.read(5) assert s == "" - def test_channel_file_readline_remote(self): - channel = self.gw.remote_exec(""" + def test_channel_file_readline_remote(self, gw): + channel = gw.remote_exec(""" channel.send('123\\n45') """) channel.waitclose(TESTTIMEOUT) @@ -339,12 +335,12 @@ class BasicRemoteExecution: s = f.readline() assert s == "45" - def test_channel_makefile_incompatmode(self): - channel = self.gw.newchannel() + def test_channel_makefile_incompatmode(self, gw): + channel = gw.newchannel() py.test.raises(ValueError, 'channel.makefile("rw")') - def test_confusion_from_os_write_stdout(self): - channel = self.gw.remote_exec(""" + def test_confusion_from_os_write_stdout(self, gw): + channel = gw.remote_exec(""" import os os.write(1, 'confusion!'.encode('ascii')) channel.send(channel.receive() * 6) @@ -357,8 +353,8 @@ class BasicRemoteExecution: res = channel.receive() assert res == 42 - def test_confusion_from_os_write_stderr(self): - channel = self.gw.remote_exec(""" + def test_confusion_from_os_write_stderr(self, gw): + channel = gw.remote_exec(""" import os os.write(2, 'test'.encode('ascii')) channel.send(channel.receive() * 6) @@ -371,53 +367,44 @@ class BasicRemoteExecution: res = channel.receive() assert res == 42 - def test__rinfo(self): - rinfo = self.gw._rinfo() + def test__rinfo(self, gw): + rinfo = gw._rinfo() assert rinfo.executable assert rinfo.cwd assert rinfo.version_info s = repr(rinfo) - old = self.gw.remote_exec(""" + old = gw.remote_exec(""" import os.path cwd = os.getcwd() channel.send(os.path.basename(cwd)) os.chdir('..') """).receive() try: - rinfo2 = self.gw._rinfo() + rinfo2 = gw._rinfo() assert rinfo2.cwd == rinfo.cwd - rinfo3 = self.gw._rinfo(update=True) + rinfo3 = gw._rinfo(update=True) assert rinfo3.cwd != rinfo2.cwd finally: - self.gw._cache_rinfo = rinfo - self.gw.remote_exec("import os ; os.chdir(%r)" % old).waitclose() + gw._cache_rinfo = rinfo + gw.remote_exec("import os ; os.chdir(%r)" % old).waitclose() -class BasicCmdbasedRemoteExecution(BasicRemoteExecution): - def test_cmdattr(self): - assert hasattr(self.gw, '_cmd') +def test_join_blocked_execution_gateway(): + gateway = py.execnet.PopenGateway() + channel = gateway.remote_exec(""" + time.sleep(5.0) + """) + def doit(): + gateway.exit() + gateway.join(joinexec=True) + return 17 -#class TestBlockingIssues: -# def test_join_blocked_execution_gateway(self): -# gateway = py.execnet.PopenGateway() -# channel = gateway.remote_exec(""" -# time.sleep(5.0) -# """) -# def doit(): -# gateway.exit() -# gateway.join(joinexec=True) -# return 17 -# -# pool = py._thread.WorkerPool() -# reply = pool.dispatch(doit) -# x = reply.get(timeout=1.0) -# assert x == 17 + pool = py._thread.WorkerPool() + reply = pool.dispatch(doit) + x = reply.get(timeout=1.0) + assert x == 17 -class TestPopenGateway(PopenGatewayTestSetup, BasicRemoteExecution): - def test_rinfo_popen(self): - rinfo = self.gw._rinfo() - assert rinfo.executable == py.std.sys.executable - assert rinfo.cwd == py.std.os.getcwd() - assert rinfo.version_info == py.std.sys.version_info +class TestPopenGateway: + gwtype = 'popen' def test_chdir_separation(self, tmpdir): old = tmpdir.chdir() @@ -428,7 +415,7 @@ class TestPopenGateway(PopenGatewayTestS c = gw.remote_exec("import os ; channel.send(os.getcwd())") x = c.receive() assert x == str(waschangedir) - + def test_many_popen(self): num = 4 l = [] @@ -453,6 +440,21 @@ class TestPopenGateway(PopenGatewayTestS channel = channels.pop() ret = channel.receive() assert ret == 42 + + def test_rinfo_popen(self, gw): + rinfo = gw._rinfo() + assert rinfo.executable == py.std.sys.executable + assert rinfo.cwd == py.std.os.getcwd() + assert rinfo.version_info == py.std.sys.version_info + + def test_gateway_init_event(self, _pytest): + rec = _pytest.gethookrecorder(gateway_base.ExecnetAPI) + gw = py.execnet.PopenGateway() + call = rec.popcall("pyexecnet_gateway_init") + assert call.gateway == gw + gw.exit() + call = rec.popcall("pyexecnet_gateway_exit") + assert call.gateway == gw @py.test.mark.xfail # "fix needed: dying remote process does not cause waitclose() to fail" def test_waitclose_on_remote_killed(self): @@ -491,75 +493,51 @@ def test_endmarker_delivery_on_remote_ki assert "15" in str(err) -class SocketGatewaySetup: - def setup_class(cls): - # open a gateway to a fresh child process - cls.proxygw = py.execnet.PopenGateway() - cls.gw = py.execnet.SocketGateway.new_remote(cls.proxygw, - ("127.0.0.1", 0) - ) +def test_socket_gw_host_not_found(gw): + py.test.raises(py.execnet.HostNotFound, + 'py.execnet.SocketGateway("qowieuqowe", 9000)' + ) + +class TestSshPopenGateway: + gwtype = "ssh" + + def test_sshconfig_config_parsing(self, monkeypatch): + import subprocess + l = [] + monkeypatch.setattr(subprocess, 'Popen', + lambda *args, **kwargs: l.append(args[0])) + py.test.raises(AttributeError, + """py.execnet.SshGateway("xyz", ssh_config='qwe')""") + assert len(l) == 1 + popen_args = l[0] + i = popen_args.index('-F') + assert popen_args[i+1] == "qwe" + + def test_sshaddress(self, gw, specssh): + assert gw.remoteaddress == specssh.ssh + def test_host_not_found(self): py.test.raises(py.execnet.HostNotFound, - 'py.execnet.SocketGateway("qowieuqowe", 9000)' - ) - -## def teardown_class(cls): -## cls.gw.exit() -## cls.proxygw.exit() - -class TestSocketGateway(SocketGatewaySetup, BasicRemoteExecution): - pass - -class TestSshGateway(BasicRemoteExecution): - def setup_class(cls): - from conftest import getspecssh - cls.sshhost = getspecssh().ssh - cls.gw = py.execnet.SshGateway(cls.sshhost) - - def test_sshconfig_functional(self, tmpdir): - ssh_config = tmpdir.join("ssh_config") - ssh_config.write( - "Host alias123\n" - " HostName %s\n" % self.sshhost) - gw = py.execnet.SshGateway("alias123", ssh_config=ssh_config) - pid = gw.remote_exec("import os ; channel.send(os.getpid())").receive() - gw.exit() - - def test_sshaddress(self): - assert self.gw.remoteaddress == self.sshhost - - def test_connexion_failes_on_non_existing_hosts(self): - py.test.raises(py.execnet.HostNotFound, "py.execnet.SshGateway('nowhere.codespeak.net')") -def test_threads(): - gw = py.execnet.PopenGateway() - gw.remote_init_threads(3) - c1 = gw.remote_exec("channel.send(channel.receive())") - c2 = gw.remote_exec("channel.send(channel.receive())") - c2.send(1) - res = c2.receive() - assert res == 1 - c1.send(42) - res = c1.receive() - assert res == 42 - gw.exit() +class TestThreads: + def test_threads(self): + gw = py.execnet.PopenGateway() + gw.remote_init_threads(3) + c1 = gw.remote_exec("channel.send(channel.receive())") + c2 = gw.remote_exec("channel.send(channel.receive())") + c2.send(1) + res = c2.receive() + assert res == 1 + c1.send(42) + res = c1.receive() + assert res == 42 -def test_threads_twice(): - gw = py.execnet.PopenGateway() - gw.remote_init_threads(3) - py.test.raises(IOError, gw.remote_init_threads, 3) - gw.exit() + def test_threads_twice(self): + gw = py.execnet.PopenGateway() + gw.remote_init_threads(3) + py.test.raises(IOError, gw.remote_init_threads, 3) -class TestExecnetEvents: - def test_popengateway(self, _pytest): - rec = _pytest.gethookrecorder(gateway_base.ExecnetAPI) - gw = py.execnet.PopenGateway() - call = rec.popcall("pyexecnet_gateway_init") - assert call.gateway == gw - gw.exit() - call = rec.popcall("pyexecnet_gateway_exit") - assert call.gateway == gw def test_nodebug(): from py.__.execnet import gateway_base --- a/py/execnet/gateway.py +++ b/py/execnet/gateway.py @@ -1,6 +1,5 @@ import sys, os, inspect, socket, atexit, weakref import py -from subprocess import Popen, PIPE from py.__.execnet.gateway_base import BaseGateway, Message, Popen2IO, SocketIO from py.__.execnet.gateway_base import ExecnetAPI @@ -196,6 +195,7 @@ channel.send(dict( class PopenCmdGateway(InitiatingGateway): def __init__(self, args): + from subprocess import Popen, PIPE self._popen = p = Popen(args, stdin=PIPE, stdout=PIPE) io = Popen2IO(p.stdin, p.stdout) super(PopenCmdGateway, self).__init__(io=io) --- a/doc/faq.txt +++ b/doc/faq.txt @@ -51,7 +51,7 @@ have no counterpart in nose_. Why did you choose a GPL-style license? ---------------------------------------- -Older versions of the py lib and (up until 1.0.x) +Older versions of the py lib and py.test (up until 1.0.x) were licensed under the MIT license. Starting with the 1.1 series Holger Krekel - being the main maintainer and developer since several years - decided to go for @@ -66,23 +66,25 @@ 3. Potentially get some money from dual- Developers want to co-operate no matter what context they are in, commercial, free, whatever. BSD-licenses sound like a fit because they minimize the need for checking for -constraints from the company or legal department. +constraints from the company or legal department. They allow +to use and modify software for whatever purpose. -Developers wanting to produce free software for a living also -want to connect to a sustainable revenue system, however. When -releasing software for public use they want to seek means, -some security on getting something back: Contributions, -recognition or money. The GPL license tries to foster a -universe of free software and force proprietary players -to contribute back. +However, developers wanting to produce free software for a living +often need to connect to a sustainable revenue system. When +releasing software for public use they seek means, some security +on getting something back: Contributions, recognition or money. +The GPL license tries to foster a universe of free software and +force proprietary players to contribute back. -Choosing the Lesser GPL kind of strikes a balance - it allows -the code to interact in proprietary contexts but increases -likelyness of flow backs. Practically it all does not make -much of a difference. Anyway, if you do have actual practical -issues regarding the license please just get in contact. +The py lib choose the Lesser GPL. It strikes a balance because it +allows the code to interact in proprietary contexts and increases +likelyness of flow backs. + +If you do have or get actual practical issues regarding +licensing please get in contact_. .. _fsf: http://www.fsf.org +.. _contact: contact.html What's all this "magic" with py.test? ---------------------------------------- From commits-noreply at bitbucket.org Wed Sep 9 15:37:16 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 9 Sep 2009 13:37:16 +0000 (UTC) Subject: [py-svn] py-trunk commit f780a7e071f2: ups, forgot to add a neccessary file. Message-ID: <20090909133716.4D5C38AC85@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252503413 -7200 # Node ID f780a7e071f2b4a7a505dc8544c5c30229b6bc7c # Parent d9e4ef1a07e999a0fc810516a76c56cb4f473707 ups, forgot to add a neccessary file. --- /dev/null +++ b/testing/execnet/conftest.py @@ -0,0 +1,46 @@ +import py + +def pytest_generate_tests(metafunc): + if 'gw' in metafunc.funcargnames: + if hasattr(metafunc.cls, 'gwtype'): + gwtypes = [metafunc.cls.gwtype] + else: + gwtypes = ['popen', 'socket', 'ssh'] + for gwtype in gwtypes: + metafunc.addcall(id=gwtype, param=gwtype) + +def pytest_funcarg__gw(request): + scope = "module" + if request.param == "popen": + return request.cached_setup( + setup=py.execnet.PopenGateway, + teardown=lambda gw: gw.exit(), + extrakey=request.param, + scope=scope) + elif request.param == "socket": + return request.cached_setup( + setup=setup_socket_gateway, + teardown=teardown_socket_gateway, + extrakey=request.param, + scope=scope) + elif request.param == "ssh": + return request.cached_setup( + setup=lambda: setup_ssh_gateway(request), + teardown=lambda gw: gw.exit(), + extrakey=request.param, + scope=scope) + +def setup_socket_gateway(): + proxygw = py.execnet.PopenGateway() + gw = py.execnet.SocketGateway.new_remote(proxygw, ("127.0.0.1", 0)) + gw.proxygw = proxygw + return gw + +def teardown_socket_gateway(gw): + gw.exit() + gw.proxygw.exit() + +def setup_ssh_gateway(request): + sshhost = request.getfuncargvalue('specssh').ssh + gw = py.execnet.SshGateway(sshhost) + return gw From commits-noreply at bitbucket.org Wed Sep 9 20:16:59 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 9 Sep 2009 18:16:59 +0000 (UTC) Subject: [py-svn] py-trunk commit 860b07080773: * move gateway management code to py/test/dist because it's not clear Message-ID: <20090909181659.A436871107@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252519923 -7200 # Node ID 860b0708077350a60c1b100ef6460c0a086dff2b # Parent f780a7e071f2b4a7a505dc8544c5c30229b6bc7c * move gateway management code to py/test/dist because it's not clear how generally useful it is. * provide pytest_dist_makegateway(txspec) hook so that plugins can add their own interpretation/keywords. --- a/py/execnet/xspec.py +++ b/py/execnet/xspec.py @@ -57,7 +57,6 @@ def makegateway(spec): hostport = spec.socket.split(":") gw = py.execnet.SocketGateway(*hostport) gw.spec = spec - # XXX events if spec.chdir or spec.nice: channel = gw.remote_exec(""" import os --- a/py/execnet/gwmanage.py +++ /dev/null @@ -1,127 +0,0 @@ -""" - instantiating, managing and rsyncing to hosts - -""" - -import py -import sys, os -from py.__.execnet.gateway_base import RemoteError - -NO_ENDMARKER_WANTED = object() - -class GatewayManager: - RemoteError = RemoteError - def __init__(self, specs, defaultchdir="pyexecnetcache"): - self.gateways = [] - self.specs = [] - for spec in specs: - if not isinstance(spec, py.execnet.XSpec): - spec = py.execnet.XSpec(spec) - if not spec.chdir and not spec.popen: - spec.chdir = defaultchdir - self.specs.append(spec) - self.hook = py._com.HookRelay( - py.execnet._HookSpecs, py._com.comregistry) - - def makegateways(self): - assert not self.gateways - for spec in self.specs: - gw = py.execnet.makegateway(spec) - self.gateways.append(gw) - gw.id = "[%s]" % len(self.gateways) - self.hook.pyexecnet_gwmanage_newgateway( - gateway=gw, platinfo=gw._rinfo()) - - def getgateways(self, remote=True, inplacelocal=True): - if not self.gateways and self.specs: - self.makegateways() - l = [] - for gw in self.gateways: - if gw.spec._samefilesystem(): - if inplacelocal: - l.append(gw) - else: - if remote: - l.append(gw) - return py.execnet.MultiGateway(gateways=l) - - def multi_exec(self, source, inplacelocal=True): - """ remote execute code on all gateways. - @param inplacelocal=False: don't send code to inplacelocal hosts. - """ - multigw = self.getgateways(inplacelocal=inplacelocal) - return multigw.remote_exec(source) - - def multi_chdir(self, basename, inplacelocal=True): - """ perform a remote chdir to the given path, may be relative. - @param inplacelocal=False: don't send code to inplacelocal hosts. - """ - self.multi_exec("import os ; os.chdir(%r)" % basename, - inplacelocal=inplacelocal).waitclose() - - def rsync(self, source, notify=None, verbose=False, ignores=None): - """ perform rsync to all remote hosts. - """ - rsync = HostRSync(source, verbose=verbose, ignores=ignores) - seen = py.builtin.set() - gateways = [] - for gateway in self.gateways: - spec = gateway.spec - if not spec._samefilesystem(): - if spec not in seen: - def finished(): - if notify: - notify("rsyncrootready", spec, source) - rsync.add_target_host(gateway, finished=finished) - seen.add(spec) - gateways.append(gateway) - if seen: - self.hook.pyexecnet_gwmanage_rsyncstart( - source=source, - gateways=gateways, - ) - rsync.send() - self.hook.pyexecnet_gwmanage_rsyncfinish( - source=source, - gateways=gateways, - ) - - def exit(self): - while self.gateways: - gw = self.gateways.pop() - gw.exit() - -class HostRSync(py.execnet.RSync): - """ RSyncer that filters out common files - """ - def __init__(self, sourcedir, *args, **kwargs): - self._synced = {} - ignores= None - if 'ignores' in kwargs: - ignores = kwargs.pop('ignores') - self._ignores = ignores or [] - super(HostRSync, self).__init__(sourcedir=sourcedir, **kwargs) - - def filter(self, path): - path = py.path.local(path) - if not path.ext in ('.pyc', '.pyo'): - if not path.basename.endswith('~'): - if path.check(dotfile=0): - for x in self._ignores: - if path == x: - break - else: - return True - - def add_target_host(self, gateway, finished=None): - remotepath = os.path.basename(self._sourcedir) - super(HostRSync, self).add_target(gateway, remotepath, - finishedcallback=finished, - delete=True,) - - def _report_send_file(self, gateway, modified_rel_path): - if self._verbose: - path = os.path.basename(self._sourcedir) + "/" + modified_rel_path - remotepath = gateway.spec.chdir - py.builtin.print_('%s:%s <= %s' % - (gateway.spec, remotepath, path)) --- a/testing/execnet/test_gateway.py +++ b/testing/execnet/test_gateway.py @@ -391,6 +391,7 @@ class TestChannelFile: def test_join_blocked_execution_gateway(): gateway = py.execnet.PopenGateway() channel = gateway.remote_exec(""" + import time time.sleep(5.0) """) def doit(): --- /dev/null +++ b/py/test/dist/gwmanage.py @@ -0,0 +1,123 @@ +""" + instantiating, managing and rsyncing to test hosts +""" + +import py +import sys, os +from py.__.execnet.gateway_base import RemoteError + +class GatewayManager: + RemoteError = RemoteError + def __init__(self, specs, hook, defaultchdir="pyexecnetcache"): + self.gateways = [] + self.specs = [] + self.hook = hook + for spec in specs: + if not isinstance(spec, py.execnet.XSpec): + spec = py.execnet.XSpec(spec) + if not spec.chdir and not spec.popen: + spec.chdir = defaultchdir + self.specs.append(spec) + + def makegateways(self): + assert not self.gateways + for spec in self.specs: + gw = py.execnet.makegateway(spec) + self.gateways.append(gw) + gw.id = "[%s]" % len(self.gateways) + self.hook.pytest_gwmanage_newgateway( + gateway=gw, platinfo=gw._rinfo()) + + def getgateways(self, remote=True, inplacelocal=True): + if not self.gateways and self.specs: + self.makegateways() + l = [] + for gw in self.gateways: + if gw.spec._samefilesystem(): + if inplacelocal: + l.append(gw) + else: + if remote: + l.append(gw) + return py.execnet.MultiGateway(gateways=l) + + def multi_exec(self, source, inplacelocal=True): + """ remote execute code on all gateways. + @param inplacelocal=False: don't send code to inplacelocal hosts. + """ + multigw = self.getgateways(inplacelocal=inplacelocal) + return multigw.remote_exec(source) + + def multi_chdir(self, basename, inplacelocal=True): + """ perform a remote chdir to the given path, may be relative. + @param inplacelocal=False: don't send code to inplacelocal hosts. + """ + self.multi_exec("import os ; os.chdir(%r)" % basename, + inplacelocal=inplacelocal).waitclose() + + def rsync(self, source, notify=None, verbose=False, ignores=None): + """ perform rsync to all remote hosts. + """ + rsync = HostRSync(source, verbose=verbose, ignores=ignores) + seen = py.builtin.set() + gateways = [] + for gateway in self.gateways: + spec = gateway.spec + if not spec._samefilesystem(): + if spec not in seen: + def finished(): + if notify: + notify("rsyncrootready", spec, source) + rsync.add_target_host(gateway, finished=finished) + seen.add(spec) + gateways.append(gateway) + if seen: + self.hook.pytest_gwmanage_rsyncstart( + source=source, + gateways=gateways, + ) + rsync.send() + self.hook.pytest_gwmanage_rsyncfinish( + source=source, + gateways=gateways, + ) + + def exit(self): + while self.gateways: + gw = self.gateways.pop() + gw.exit() + +class HostRSync(py.execnet.RSync): + """ RSyncer that filters out common files + """ + def __init__(self, sourcedir, *args, **kwargs): + self._synced = {} + ignores= None + if 'ignores' in kwargs: + ignores = kwargs.pop('ignores') + self._ignores = ignores or [] + super(HostRSync, self).__init__(sourcedir=sourcedir, **kwargs) + + def filter(self, path): + path = py.path.local(path) + if not path.ext in ('.pyc', '.pyo'): + if not path.basename.endswith('~'): + if path.check(dotfile=0): + for x in self._ignores: + if path == x: + break + else: + return True + + def add_target_host(self, gateway, finished=None): + remotepath = os.path.basename(self._sourcedir) + super(HostRSync, self).add_target(gateway, remotepath, + finishedcallback=finished, + delete=True,) + + def _report_send_file(self, gateway, modified_rel_path): + if self._verbose: + path = os.path.basename(self._sourcedir) + "/" + modified_rel_path + remotepath = gateway.spec.chdir + py.builtin.print_('%s:%s <= %s' % + (gateway.spec, remotepath, path)) --- a/py/execnet/gateway_base.py +++ b/py/execnet/gateway_base.py @@ -590,15 +590,6 @@ class ExecnetAPI: def pyexecnet_gateway_exit(self, gateway): """ signal exitting of gateway. """ - def pyexecnet_gwmanage_newgateway(self, gateway, platinfo): - """ called when a manager has made a new gateway. """ - - def pyexecnet_gwmanage_rsyncstart(self, source, gateways): - """ called before rsyncing a directory to remote gateways takes place. """ - - def pyexecnet_gwmanage_rsyncfinish(self, source, gateways): - """ called after rsyncing a directory to remote gateways takes place. """ - class BaseGateway(object): hook = ExecnetAPI() --- a/testing/execnet/test_gwmanage.py +++ /dev/null @@ -1,151 +0,0 @@ -""" - tests for - - gateway management - - manage rsyncing of hosts - -""" - -import py -import os -from py.__.execnet.gwmanage import GatewayManager, HostRSync - -class TestGatewayManagerPopen: - def test_popen_no_default_chdir(self): - gm = GatewayManager(["popen"]) - assert gm.specs[0].chdir is None - - def test_default_chdir(self): - l = ["ssh=noco", "socket=xyz"] - for spec in GatewayManager(l).specs: - assert spec.chdir == "pyexecnetcache" - for spec in GatewayManager(l, defaultchdir="abc").specs: - assert spec.chdir == "abc" - - def test_popen_makegateway_events(self, _pytest): - rec = _pytest.gethookrecorder(py.execnet._HookSpecs) - hm = GatewayManager(["popen"] * 2) - hm.makegateways() - call = rec.popcall("pyexecnet_gwmanage_newgateway") - assert call.gateway.id == "[1]" - assert call.platinfo.executable == call.gateway._rinfo().executable - call = rec.popcall("pyexecnet_gwmanage_newgateway") - assert call.gateway.id == "[2]" - assert len(hm.gateways) == 2 - hm.exit() - assert not len(hm.gateways) - - def test_popens_rsync(self, mysetup): - source = mysetup.source - hm = GatewayManager(["popen"] * 2) - hm.makegateways() - assert len(hm.gateways) == 2 - for gw in hm.gateways: - gw.remote_exec = None - l = [] - hm.rsync(source, notify=lambda *args: l.append(args)) - assert not l - hm.exit() - assert not len(hm.gateways) - - def test_rsync_popen_with_path(self, mysetup): - source, dest = mysetup.source, mysetup.dest - hm = GatewayManager(["popen//chdir=%s" %dest] * 1) - hm.makegateways() - source.ensure("dir1", "dir2", "hello") - l = [] - hm.rsync(source, notify=lambda *args: l.append(args)) - assert len(l) == 1 - assert l[0] == ("rsyncrootready", hm.gateways[0].spec, source) - hm.exit() - dest = dest.join(source.basename) - assert dest.join("dir1").check() - assert dest.join("dir1", "dir2").check() - assert dest.join("dir1", "dir2", 'hello').check() - - def test_hostmanage_rsync_same_popen_twice(self, mysetup, _pytest): - source, dest = mysetup.source, mysetup.dest - rec = _pytest.gethookrecorder(py.execnet._HookSpecs) - hm = GatewayManager(["popen//chdir=%s" %dest] * 2) - hm.makegateways() - source.ensure("dir1", "dir2", "hello") - hm.rsync(source) - call = rec.popcall("pyexecnet_gwmanage_rsyncstart") - assert call.source == source - assert len(call.gateways) == 1 - assert hm.gateways[0] == call.gateways[0] - call = rec.popcall("pyexecnet_gwmanage_rsyncfinish") - - def test_multi_chdir_popen_with_path(self, testdir): - hm = GatewayManager(["popen//chdir=hello"] * 2) - testdir.tmpdir.chdir() - hellopath = testdir.tmpdir.mkdir("hello").realpath() - hm.makegateways() - l = hm.multi_exec( - "import os ; channel.send(os.getcwd())").receive_each() - paths = [x[1] for x in l] - assert l == [str(hellopath)] * 2 - py.test.raises(hm.RemoteError, - 'hm.multi_chdir("world", inplacelocal=False)') - worldpath = hellopath.mkdir("world") - hm.multi_chdir("world", inplacelocal=False) - l = hm.multi_exec( - "import os ; channel.send(os.getcwd())").receive_each() - assert len(l) == 2 - assert l[0] == l[1] - curwd = os.getcwd() - assert l[0].startswith(curwd) - assert l[0].endswith("world") - - def test_multi_chdir_popen(self, testdir): - import os - hm = GatewayManager(["popen"] * 2) - testdir.tmpdir.chdir() - hellopath = testdir.tmpdir.mkdir("hello") - hm.makegateways() - hm.multi_chdir("hello", inplacelocal=False) - l = hm.multi_exec("import os ; channel.send(os.getcwd())").receive_each() - assert len(l) == 2 - curwd = os.path.realpath(os.getcwd()) - assert l == [curwd] * 2 - - hm.multi_chdir("hello") - l = hm.multi_exec("import os ; channel.send(os.getcwd())").receive_each() - assert len(l) == 2 - assert l[0] == l[1] - assert l[0].startswith(curwd) - assert l[0].endswith("hello") - -class pytest_funcarg__mysetup: - def __init__(self, request): - tmp = request.getfuncargvalue('tmpdir') - self.source = tmp.mkdir("source") - self.dest = tmp.mkdir("dest") - request.getfuncargvalue("_pytest") # to have patching of py._com.comregistry - -class TestHRSync: - def test_hrsync_filter(self, mysetup): - source, dest = mysetup.source, mysetup.dest - source.ensure("dir", "file.txt") - source.ensure(".svn", "entries") - source.ensure(".somedotfile", "moreentries") - source.ensure("somedir", "editfile~") - syncer = HostRSync(source) - l = list(source.visit(rec=syncer.filter, - fil=syncer.filter)) - assert len(l) == 3 - basenames = [x.basename for x in l] - assert 'dir' in basenames - assert 'file.txt' in basenames - assert 'somedir' in basenames - - def test_hrsync_one_host(self, mysetup): - source, dest = mysetup.source, mysetup.dest - gw = py.execnet.makegateway("popen//chdir=%s" % dest) - finished = [] - rsync = HostRSync(source) - rsync.add_target_host(gw, finished=lambda: finished.append(1)) - source.join("hello.py").write("world") - rsync.send() - gw.exit() - assert dest.join(source.basename, "hello.py").check() - assert len(finished) == 1 --- a/testing/pytest/plugin/test_pytest_terminal.py +++ b/testing/pytest/plugin/test_pytest_terminal.py @@ -123,16 +123,16 @@ class TestTerminal: platform = "xyz" cwd = "qwe" - rep.pyexecnet_gwmanage_newgateway(gw1, rinfo) + rep.pytest_gwmanage_newgateway(gw1, rinfo) linecomp.assert_contains_lines([ "X1*popen*xyz*2.5*" ]) - rep.pyexecnet_gwmanage_rsyncstart(source="hello", gateways=[gw1, gw2]) + rep.pytest_gwmanage_rsyncstart(source="hello", gateways=[gw1, gw2]) linecomp.assert_contains_lines([ "rsyncstart: hello -> X1, X2" ]) - rep.pyexecnet_gwmanage_rsyncfinish(source="hello", gateways=[gw1, gw2]) + rep.pytest_gwmanage_rsyncfinish(source="hello", gateways=[gw1, gw2]) linecomp.assert_contains_lines([ "rsyncfinish: hello -> X1, X2" ]) --- a/py/test/dist/nodemanage.py +++ b/py/test/dist/nodemanage.py @@ -1,7 +1,7 @@ import py import sys, os from py.__.test.dist.txnode import TXNode -from py.__.execnet.gwmanage import GatewayManager +from py.__.test.dist.gwmanage import GatewayManager class NodeManager(object): @@ -10,7 +10,7 @@ class NodeManager(object): if specs is None: specs = self.config.getxspecs() self.roots = self.config.getrsyncdirs() - self.gwmanager = GatewayManager(specs) + self.gwmanager = GatewayManager(specs, config.hook) self.nodes = [] self._nodesready = py.std.threading.Event() --- a/py/test/plugin/hookspec.py +++ b/py/test/plugin/hookspec.py @@ -133,6 +133,15 @@ pytest_doctest_prepare_content.firstresu # distributed testing # ------------------------------------------------------------------------- +def pytest_gwmanage_newgateway(gateway, platinfo): + """ called on new raw gateway creation. """ + +def pytest_gwmanage_rsyncstart(source, gateways): + """ called before rsyncing a directory to remote gateways takes place. """ + +def pytest_gwmanage_rsyncfinish(source, gateways): + """ called after rsyncing a directory to remote gateways takes place. """ + def pytest_testnodeready(node): """ Test Node is ready to operate. """ --- /dev/null +++ b/testing/pytest/dist/test_gwmanage.py @@ -0,0 +1,160 @@ +""" + tests for + - gateway management + - manage rsyncing of hosts + +""" + +import py +import os +from py.__.test.dist.gwmanage import GatewayManager, HostRSync +from py.__.test.plugin import hookspec + +def pytest_funcarg__hookrecorder(request): + _pytest = request.getfuncargvalue('_pytest') + hook = request.getfuncargvalue('hook') + return _pytest.gethookrecorder(hook._hookspecs, hook._registry) + +def pytest_funcarg__hook(request): + registry = py._com.Registry() + return py._com.HookRelay(hookspec, registry) + +class TestGatewayManagerPopen: + def test_popen_no_default_chdir(self, hook): + gm = GatewayManager(["popen"], hook) + assert gm.specs[0].chdir is None + + def test_default_chdir(self, hook): + l = ["ssh=noco", "socket=xyz"] + for spec in GatewayManager(l, hook).specs: + assert spec.chdir == "pyexecnetcache" + for spec in GatewayManager(l, hook, defaultchdir="abc").specs: + assert spec.chdir == "abc" + + def test_popen_makegateway_events(self, hook, hookrecorder, _pytest): + hm = GatewayManager(["popen"] * 2, hook) + hm.makegateways() + call = hookrecorder.popcall("pytest_gwmanage_newgateway") + assert call.gateway.spec == py.execnet.XSpec("popen") + assert call.gateway.id == "[1]" + assert call.platinfo.executable == call.gateway._rinfo().executable + call = hookrecorder.popcall("pytest_gwmanage_newgateway") + assert call.gateway.id == "[2]" + assert len(hm.gateways) == 2 + hm.exit() + assert not len(hm.gateways) + + def test_popens_rsync(self, hook, mysetup): + source = mysetup.source + hm = GatewayManager(["popen"] * 2, hook) + hm.makegateways() + assert len(hm.gateways) == 2 + for gw in hm.gateways: + gw.remote_exec = None + l = [] + hm.rsync(source, notify=lambda *args: l.append(args)) + assert not l + hm.exit() + assert not len(hm.gateways) + + def test_rsync_popen_with_path(self, hook, mysetup): + source, dest = mysetup.source, mysetup.dest + hm = GatewayManager(["popen//chdir=%s" %dest] * 1, hook) + hm.makegateways() + source.ensure("dir1", "dir2", "hello") + l = [] + hm.rsync(source, notify=lambda *args: l.append(args)) + assert len(l) == 1 + assert l[0] == ("rsyncrootready", hm.gateways[0].spec, source) + hm.exit() + dest = dest.join(source.basename) + assert dest.join("dir1").check() + assert dest.join("dir1", "dir2").check() + assert dest.join("dir1", "dir2", 'hello').check() + + def test_rsync_same_popen_twice(self, hook, mysetup, hookrecorder): + source, dest = mysetup.source, mysetup.dest + hm = GatewayManager(["popen//chdir=%s" %dest] * 2, hook) + hm.makegateways() + source.ensure("dir1", "dir2", "hello") + hm.rsync(source) + call = hookrecorder.popcall("pytest_gwmanage_rsyncstart") + assert call.source == source + assert len(call.gateways) == 1 + assert hm.gateways[0] == call.gateways[0] + call = hookrecorder.popcall("pytest_gwmanage_rsyncfinish") + + def test_multi_chdir_popen_with_path(self, hook, testdir): + hm = GatewayManager(["popen//chdir=hello"] * 2, hook) + testdir.tmpdir.chdir() + hellopath = testdir.tmpdir.mkdir("hello").realpath() + hm.makegateways() + l = hm.multi_exec( + "import os ; channel.send(os.getcwd())").receive_each() + paths = [x[1] for x in l] + assert l == [str(hellopath)] * 2 + py.test.raises(hm.RemoteError, + 'hm.multi_chdir("world", inplacelocal=False)') + worldpath = hellopath.mkdir("world") + hm.multi_chdir("world", inplacelocal=False) + l = hm.multi_exec( + "import os ; channel.send(os.getcwd())").receive_each() + assert len(l) == 2 + assert l[0] == l[1] + curwd = os.getcwd() + assert l[0].startswith(curwd) + assert l[0].endswith("world") + + def test_multi_chdir_popen(self, testdir, hook): + import os + hm = GatewayManager(["popen"] * 2, hook) + testdir.tmpdir.chdir() + hellopath = testdir.tmpdir.mkdir("hello") + hm.makegateways() + hm.multi_chdir("hello", inplacelocal=False) + l = hm.multi_exec("import os ; channel.send(os.getcwd())").receive_each() + assert len(l) == 2 + curwd = os.path.realpath(os.getcwd()) + assert l == [curwd] * 2 + + hm.multi_chdir("hello") + l = hm.multi_exec("import os ; channel.send(os.getcwd())").receive_each() + assert len(l) == 2 + assert l[0] == l[1] + assert l[0].startswith(curwd) + assert l[0].endswith("hello") + +class pytest_funcarg__mysetup: + def __init__(self, request): + tmp = request.getfuncargvalue('tmpdir') + self.source = tmp.mkdir("source") + self.dest = tmp.mkdir("dest") + request.getfuncargvalue("_pytest") # to have patching of py._com.comregistry + +class TestHRSync: + def test_hrsync_filter(self, mysetup): + source, dest = mysetup.source, mysetup.dest + source.ensure("dir", "file.txt") + source.ensure(".svn", "entries") + source.ensure(".somedotfile", "moreentries") + source.ensure("somedir", "editfile~") + syncer = HostRSync(source) + l = list(source.visit(rec=syncer.filter, + fil=syncer.filter)) + assert len(l) == 3 + basenames = [x.basename for x in l] + assert 'dir' in basenames + assert 'file.txt' in basenames + assert 'somedir' in basenames + + def test_hrsync_one_host(self, mysetup): + source, dest = mysetup.source, mysetup.dest + gw = py.execnet.makegateway("popen//chdir=%s" % dest) + finished = [] + rsync = HostRSync(source) + rsync.add_target_host(gw, finished=lambda: finished.append(1)) + source.join("hello.py").write("world") + rsync.send() + gw.exit() + assert dest.join(source.basename, "hello.py").check() + assert len(finished) == 1 --- a/py/test/plugin/pytest_terminal.py +++ b/py/test/plugin/pytest_terminal.py @@ -107,7 +107,7 @@ class TerminalReporter: for line in str(excrepr).split("\n"): self.write_line("INTERNALERROR> " + line) - def pyexecnet_gwmanage_newgateway(self, gateway, platinfo): + def pytest_gwmanage_newgateway(self, gateway, platinfo): #self.write_line("%s instantiated gateway from spec %r" %(gateway.id, gateway.spec._spec)) d = {} d['version'] = repr_pythonversion(platinfo.version_info) @@ -126,14 +126,14 @@ class TerminalReporter: self.write_line(infoline) self.gateway2info[gateway] = infoline - def pyexecnet_gwmanage_rsyncstart(self, source, gateways): + def pytest_gwmanage_rsyncstart(self, source, gateways): targets = ", ".join([gw.id for gw in gateways]) msg = "rsyncstart: %s -> %s" %(source, targets) if not self.config.option.verbose: msg += " # use --verbose to see rsync progress" self.write_line(msg) - def pyexecnet_gwmanage_rsyncfinish(self, source, gateways): + def pytest_gwmanage_rsyncfinish(self, source, gateways): targets = ", ".join([gw.id for gw in gateways]) self.write_line("rsyncfinish: %s -> %s" %(source, targets)) From commits-noreply at bitbucket.org Wed Sep 9 20:50:01 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 9 Sep 2009 18:50:01 +0000 (UTC) Subject: [py-svn] py-trunk commit 3db27a84416e: some doc about the experiemntal pytest_gwmanage_newgateway hook. Message-ID: <20090909185001.11E3571102@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252521951 -7200 # Node ID 3db27a84416eeebdae025198ef3b8c150b6014bb # Parent 860b0708077350a60c1b100ef6460c0a086dff2b some doc about the experiemntal pytest_gwmanage_newgateway hook. and use process-scope for execnet test funcargs because of weird setup/teardown issues when running distributedly itself. --- a/doc/test/customize.txt +++ b/doc/test/customize.txt @@ -353,6 +353,26 @@ Python module. The return value is a cu .. XXX or ``False`` if you want to indicate that the given item should not be collected. +Gateway initialization (distributed testing) +---------------------------------------------------- + +(alpha) For distributed testing it can be useful to prepare the +remote environment. For this you can implement the newgateway hook: + +.. sourcecode:: python + + def pytest_gwmanage_newgateway(gateway, platinfo): + """ called after a gateway is instantiated. """ + +The ``gateway`` object here has a ``spec`` attribute which is an ``py.execnet.XSpec`` +object, which has attributes that map key/values as specified from a ``--txspec`` +option. The platinfo object is a dictionary with information about the remote process: + +* ``version``: remote python's ``sys.version_info`` +* ``platform``: remote ``sys.platform`` +* ``cwd``: remote ``os.getcwd`` + + .. _`collection process`: .. _`collection node`: .. _`test collection`: --- a/testing/execnet/conftest.py +++ b/testing/execnet/conftest.py @@ -10,7 +10,7 @@ def pytest_generate_tests(metafunc): metafunc.addcall(id=gwtype, param=gwtype) def pytest_funcarg__gw(request): - scope = "module" + scope = "session" # XXX module causes problems with -n 3! if request.param == "popen": return request.cached_setup( setup=py.execnet.PopenGateway, From commits-noreply at bitbucket.org Wed Sep 9 23:08:42 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 9 Sep 2009 21:08:42 +0000 (UTC) Subject: [py-svn] py-trunk commit df0286f1be06: fix a bug with funcarg setup and remove XXX comment because "scope=module" now would work but leaving it as session for now. Message-ID: <20090909210842.B567B71107@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252530462 -7200 # Node ID df0286f1be06adef6ad9f814093876ccdb615f39 # Parent 3db27a84416eeebdae025198ef3b8c150b6014bb fix a bug with funcarg setup and remove XXX comment because "scope=module" now would work but leaving it as session for now. --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,6 +1,9 @@ Changes between 1.0.x and 'trunk' ===================================== +* fix a funcarg cached_setup bug probably only occuring + in distributed testing and "module" scope with teardown. + * consolidate builtins implementation to be compatible with >=2.3, add helpers to ease keeping 2 and 3k compatible code --- a/testing/execnet/conftest.py +++ b/testing/execnet/conftest.py @@ -10,7 +10,7 @@ def pytest_generate_tests(metafunc): metafunc.addcall(id=gwtype, param=gwtype) def pytest_funcarg__gw(request): - scope = "session" # XXX module causes problems with -n 3! + scope = "session" if request.param == "popen": return request.cached_setup( setup=py.execnet.PopenGateway, --- a/py/test/funcargs.py +++ b/py/test/funcargs.py @@ -126,7 +126,10 @@ class FuncargRequest: val = setup() cache[cachekey] = val if teardown is not None: - self._addfinalizer(lambda: teardown(val), scope=scope) + def finalizer(): + del cache[cachekey] + teardown(val) + self._addfinalizer(finalizer, scope=scope) return val def getfuncargvalue(self, argname): @@ -157,7 +160,8 @@ class FuncargRequest: def _addfinalizer(self, finalizer, scope): colitem = self._getscopeitem(scope) - self.config._setupstate.addfinalizer(finalizer=finalizer, colitem=colitem) + self.config._setupstate.addfinalizer( + finalizer=finalizer, colitem=colitem) def addfinalizer(self, finalizer): """ call the given finalizer after test function finished execution. """ @@ -179,6 +183,3 @@ class FuncargRequest: msg = "funcargument %r not found for: %s" %(argname, line) msg += "\n available funcargs: %s" %(", ".join(available),) raise self.Error(msg) - - - --- a/testing/pytest/test_funcargs.py +++ b/testing/pytest/test_funcargs.py @@ -240,6 +240,24 @@ class TestRequestCachedSetup: assert ret1 == ret1b assert ret2 == ret2b + def test_request_cachedsetup_cache_deletion(self, testdir): + item1 = testdir.getitem("def test_func(): pass") + req1 = funcargs.FuncargRequest(item1) + l = [] + def setup(): + l.append("setup") + def teardown(val): + l.append("teardown") + ret1 = req1.cached_setup(setup, teardown, scope="function") + assert l == ['setup'] + # artificial call of finalizer + req1.config._setupstate._callfinalizers(item1) + assert l == ["setup", "teardown"] + ret2 = req1.cached_setup(setup, teardown, scope="function") + assert l == ["setup", "teardown", "setup"] + req1.config._setupstate._callfinalizers(item1) + assert l == ["setup", "teardown", "setup", "teardown"] + def test_request_cached_setup_functional(self, testdir): testdir.makepyfile(test_0=""" l = [] From commits-noreply at bitbucket.org Fri Sep 11 19:19:52 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 11 Sep 2009 17:19:52 +0000 (UTC) Subject: [py-svn] py-trunk commit 641eadd1db8d: added another funcarg example i had lying around Message-ID: <20090911171952.5FACB7113B@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252663506 -7200 # Node ID 641eadd1db8d1110ff439133f2da0a3cc127d711 # Parent df0286f1be06adef6ad9f814093876ccdb615f39 added another funcarg example i had lying around --- /dev/null +++ b/example/assertion/global_testmodule_config/test_hello.py @@ -0,0 +1,5 @@ + +hello = "world" + +def test_func(): + pass --- /dev/null +++ b/example/assertion/global_testmodule_config/conftest.py @@ -0,0 +1,7 @@ +import py + +def pytest_runtest_setup(item): + if isinstance(item, py.test.collect.Function): + mod = item.getparent(py.test.collect.Module).obj + if hasattr(mod, 'hello'): + py.builtin.print_("mod.hello", mod.hello) --- /dev/null +++ b/example/funcarg/urloption/conftest.py @@ -0,0 +1,15 @@ +# conftest.py +import py + + +def pytest_addoption(parser): + grp = parser.addgroup("testserver options") + grp.addoption("--url", action="store", default=None, + help="url for testserver") + +def pytest_funcarg__url(request): + url = request.config.getvalue("url") + if url is None: + py.test.skip("need --url") + return url + From commits-noreply at bitbucket.org Fri Sep 11 19:19:59 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 11 Sep 2009 17:19:59 +0000 (UTC) Subject: [py-svn] py-trunk commit 71a55baebef0: * various cleanups and detailed doc string for gateway_base module Message-ID: <20090911171959.EDFEF7113C@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1252679179 -7200 # Node ID 71a55baebef055c44c2837a8ae6166905227618a # Parent 641eadd1db8d1110ff439133f2da0a3cc127d711 * various cleanups and detailed doc string for gateway_base module * remove old multi-file-send mechanism/tests now that only gateway_base is send to the other side. * adding some (c) notices where i am pretty sure about them. --- a/py/execnet/gateway.py +++ b/py/execnet/gateway.py @@ -1,22 +1,15 @@ +""" +gateway code for initiating popen, socket and ssh connections. +(c) 2004-2009, Holger Krekel and others +""" + import sys, os, inspect, socket, atexit, weakref import py -from py.__.execnet.gateway_base import BaseGateway, Message, Popen2IO, SocketIO -from py.__.execnet.gateway_base import ExecnetAPI - -# the list of modules that must be send to the other side -# for bootstrapping gateways -# XXX we'd like to have a leaner and meaner bootstrap mechanism - -startup_modules = [ - 'py.__.execnet.gateway_base', -] +from py.__.execnet.gateway_base import Message, Popen2IO, SocketIO +from py.__.execnet import gateway_base debug = False -def getsource(dottedname): - mod = __import__(dottedname, None, None, ['__doc__']) - return inspect.getsource(mod) - class GatewayCleanup: def __init__(self): self._activegateways = weakref.WeakKeyDictionary() @@ -37,15 +30,22 @@ class GatewayCleanup: gw.exit() #gw.join() # should work as well +class ExecnetAPI: + def pyexecnet_gateway_init(self, gateway): + """ signal initialisation of new gateway. """ + def pyexecnet_gateway_exit(self, gateway): + """ signal exitting of gateway. """ -class InitiatingGateway(BaseGateway): +class InitiatingGateway(gateway_base.BaseGateway): """ initialize gateways on both sides of a inputoutput object. """ + # XXX put the next two global variables into an Execnet object + # which intiaties gateways and passes in appropriate values. _cleanup = GatewayCleanup() + hook = ExecnetAPI() def __init__(self, io): self._remote_bootstrap_gateway(io) super(InitiatingGateway, self).__init__(io=io, _startcount=1) - # XXX we dissallow execution form the other side self._initreceive() self.hook = py._com.HookRelay(ExecnetAPI, py._com.comregistry) self.hook.pyexecnet_gateway_init(gateway=self) @@ -87,10 +87,10 @@ class InitiatingGateway(BaseGateway): uniquely identify channels across both sides. """ bootstrap = [extra] - bootstrap += [getsource(x) for x in startup_modules] + bootstrap += [inspect.getsource(gateway_base)] bootstrap += [io.server_stmt, "io.write('1'.encode('ascii'))", - "BaseGateway(io=io, _startcount=2)._servemain()", + "SlaveGateway(io=io, _startcount=2).serve()", ] source = "\n".join(bootstrap) self._trace("sending gateway bootstrap code") @@ -136,7 +136,7 @@ class InitiatingGateway(BaseGateway): execpool.shutdown() execpool.join() raise gw._StopExecLoop - execpool.dispatch(gw._executetask, task) + execpool.dispatch(gw.executetask, task) """ % num) self._remotechannelthread = self.remote_exec(source) --- a/py/execnet/xspec.py +++ b/py/execnet/xspec.py @@ -1,4 +1,6 @@ - +""" +(c) 2008-2009, holger krekel +""" import py class XSpec: @@ -9,7 +11,7 @@ class XSpec: * keys are not allowed to start with underscore * if no "=value" is given, assume a boolean True value """ - # XXX for now we are very restrictive about actually allowed key-values + # XXX allow customization, for only allow specific key names popen = ssh = socket = python = chdir = nice = None def __init__(self, string): --- a/py/execnet/multi.py +++ b/py/execnet/multi.py @@ -1,5 +1,7 @@ """ - Support for working with multiple channels and gateways +Support for working with multiple channels and gateways + +(c) 2008-2009, Holger Krekel and others """ import py try: --- a/py/execnet/gateway_base.py +++ b/py/execnet/gateway_base.py @@ -1,15 +1,37 @@ """ -base gateway code +base execnet gateway code, a quick overview. -# note that the whole code of this module (as well as some -# other modules) execute not only on the local side but -# also on any gateway's remote side. On such remote sides -# we cannot assume the py library to be there and -# InstallableGateway._remote_bootstrap_gateway() (located -# in register.py) will take care to send source fragments -# to the other side. Yes, it is fragile but we have a -# few tests that try to catch when we mess up. +the code of this module is sent to the "other side" +as a means of bootstrapping a Gateway object +capable of receiving and executing code, +and routing data through channels. +Gateways operate on InputOutput objects offering +a write and a read(n) method. + +Once bootstrapped a higher level protocol +based on Messages is used. Messages are serialized +to and from InputOutput objects. The details of this protocol +are locally defined in this module. There is no need +for standardizing or versioning the protocol. + +After bootstrapping the BaseGateway opens a receiver thread which +accepts encoded messages and triggers actions to interpret them. +Sending of channel data items happens directly through +write operations to InputOutput objects so there is no +separate thread. + +Code execution messages are put into an execqueue from +which they will be taken for execution. gateway.serve() +will take and execute such items, one by one. This means +that by incoming default execution is single-threaded. + +The receiver thread terminates if the remote side sends +a gateway termination message or if the IO-connection drops. +It puts an end symbol into the execqueue so +that serve() can cleanly finish as well. + +(C) 2004-2009 Holger Krekel, Armin Rigo and others """ import sys, os, weakref import threading, traceback, socket, struct @@ -89,7 +111,6 @@ class SocketIO: class Popen2IO: server_stmt = """ import os, sys, tempfile -#io = Popen2IO(os.fdopen(1, 'wb'), os.fdopen(0, 'rb')) io = Popen2IO(sys.stdout, sys.stdin) sys.stdout = tempfile.TemporaryFile('w') sys.stdin = tempfile.TemporaryFile('r') @@ -97,37 +118,36 @@ sys.stdin = tempfile.TemporaryFile('r') error = (IOError, OSError, EOFError) def __init__(self, outfile, infile): + # we need raw byte streams + if hasattr(infile, 'buffer'): + infile = infile.buffer + if hasattr(outfile, 'buffer'): + outfile = outfile.buffer self.outfile, self.infile = outfile, infile if sys.platform == "win32": import msvcrt msvcrt.setmode(infile.fileno(), os.O_BINARY) msvcrt.setmode(outfile.fileno(), os.O_BINARY) - self.readable = self.writeable = True def read(self, numbytes): - """Read exactly 'bytes' bytes from the pipe. """ - infile = self.infile - if hasattr(infile, 'buffer'): - infile = infile.buffer - data = infile.read(numbytes) + """Read exactly 'numbytes' bytes from the pipe. """ + data = self.infile.read(numbytes) if len(data) < numbytes: raise EOFError return data def write(self, data): - """write out all bytes to the pipe. """ + """write out all data bytes. """ assert isinstance(data, bytes) - outfile = self.outfile - if hasattr(outfile, 'buffer'): - outfile = outfile.buffer - outfile.write(data) - outfile.flush() + self.outfile.write(data) + self.outfile.flush() def close_read(self): if self.readable: self.infile.close() self.readable = None + def close_write(self): try: self.outfile.close() @@ -201,7 +221,6 @@ class Message: return "" %(self.__class__.__name__, self.channelid, self.data) - def _setupmessages(): class CHANNEL_OPEN(Message): def received(self, gateway): @@ -234,7 +253,7 @@ def _setupmessages(): classes = [CHANNEL_OPEN, CHANNEL_NEW, CHANNEL_DATA, CHANNEL_CLOSE, CHANNEL_CLOSE_ERROR, CHANNEL_LAST_MESSAGE] - + for i, cls in enumerate(classes): Message._types[i] = cls cls.msgtype = i @@ -359,9 +378,9 @@ class Channel(object): def makefile(self, mode='w', proxyclose=False): """ return a file-like object. - mode: 'w' for binary writes, 'r' for binary reads - proxyclose: set to true if you want to have a - subsequent file.close() automatically close the channel. + mode: 'w' for writes, 'r' for reads + proxyclose: if true file.close() will + trigger a channel.close() call. """ if mode == "w": return ChannelFileWrite(channel=self, proxyclose=proxyclose) @@ -581,18 +600,8 @@ class ChannelFileRead(ChannelFile): break line += c return line - - - -class ExecnetAPI: - def pyexecnet_gateway_init(self, gateway): - """ signal initialisation of new gateway. """ - def pyexecnet_gateway_exit(self, gateway): - """ signal exitting of gateway. """ - class BaseGateway(object): - hook = ExecnetAPI() exc_info = sys.exc_info class _StopExecLoop(Exception): @@ -671,18 +680,37 @@ class BaseGateway(object): self._send(None) def _stopexec(self): - if hasattr(self, '_execqueue'): - self._execqueue.put(None) + pass def _local_schedulexec(self, channel, sourcetask): - if hasattr(self, '_execqueue'): - self._execqueue.put((channel, sourcetask)) - else: - # we will not execute, let's send back an error - # to inform the other side - channel.close("execution disallowed") + channel.close("execution disallowed") - def _servemain(self, joining=True): + # _____________________________________________________________________ + # + # High Level Interface + # _____________________________________________________________________ + # + def newchannel(self): + """ return new channel object. """ + return self._channelfactory.new() + + def join(self, joinexec=True): + """ Wait for all IO (and by default all execution activity) + to stop. the joinexec parameter is obsolete. + """ + current = threading.currentThread() + if self._receiverthread.isAlive(): + self._trace("joining receiver thread") + self._receiverthread.join() + +class SlaveGateway(BaseGateway): + def _stopexec(self): + self._execqueue.put(None) + + def _local_schedulexec(self, channel, sourcetask): + self._execqueue.put((channel, sourcetask)) + + def serve(self, joining=True): self._execqueue = queue.Queue() self._initreceive() try: @@ -692,15 +720,15 @@ class BaseGateway(object): self._stopsend() break try: - self._executetask(item) + self.executetask(item) except self._StopExecLoop: break finally: - self._trace("_servemain finished") + self._trace("serve") if joining: self.join() - def _executetask(self, item): + def executetask(self, item): """ execute channel/source items. """ channel, source = item try: @@ -725,22 +753,3 @@ class BaseGateway(object): else: channel.close() - # _____________________________________________________________________ - # - # High Level Interface - # _____________________________________________________________________ - # - - def newchannel(self): - """ return new channel object. """ - return self._channelfactory.new() - - def join(self, joinexec=True): - """ Wait for all IO (and by default all execution activity) - to stop. the joinexec parameter is obsolete. - """ - current = threading.currentThread() - if self._receiverthread.isAlive(): - self._trace("joining receiver thread") - self._receiverthread.join() - --- a/testing/execnet/test_basics.py +++ b/testing/execnet/test_basics.py @@ -143,23 +143,6 @@ def test_geterrortext(anypython, tmpdir) print (out) assert "all passed" in out -def test_getsource_import_modules(): - for dottedname in gateway.startup_modules: - yield gateway.getsource, dottedname - -def test_getsource_no_colision(): - seen = {} - for dottedname in gateway.startup_modules: - mod = __import__(dottedname, None, None, ['__doc__']) - for name, value in vars(mod).items(): - if py.std.inspect.isclass(value): - if name in seen: - olddottedname, oldval = seen[name] - if oldval is not value: - py.test.fail("duplicate class %r in %s and %s" % - (name, dottedname, olddottedname)) - seen[name] = (dottedname, value) - def test_stdouterrin_setnull(): cap = py.io.StdCaptureFD() from py.__.execnet.gateway import stdouterrin_setnull --- a/testing/execnet/test_gateway.py +++ b/testing/execnet/test_gateway.py @@ -449,7 +449,7 @@ class TestPopenGateway: assert rinfo.version_info == py.std.sys.version_info def test_gateway_init_event(self, _pytest): - rec = _pytest.gethookrecorder(gateway_base.ExecnetAPI) + rec = _pytest.gethookrecorder(gateway.ExecnetAPI) gw = py.execnet.PopenGateway() call = rec.popcall("pyexecnet_gateway_init") assert call.gateway == gw --- a/py/execnet/rsync_remote.py +++ b/py/execnet/rsync_remote.py @@ -1,4 +1,3 @@ - def f(): import os, stat, shutil try: --- a/py/execnet/rsync.py +++ b/py/execnet/rsync.py @@ -1,3 +1,8 @@ +""" +1:N rsync implemenation on top of execnet. + +(c) 2006-2009, Armin Rigo, Holger Krekel, Maciej Fijalkowski +""" import py, os, stat md5 = py.builtin._tryimport('hashlib', 'md5').md5 From commits-noreply at bitbucket.org Fri Sep 11 22:26:07 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 11 Sep 2009 20:26:07 +0000 (UTC) Subject: [py-svn] py-trunk commit 9928a903e699: compiling AST to code is new in python 2.6 Message-ID: <20090911202607.EFD7F71131@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1252700683 18000 # Node ID 9928a903e699748fc463bef0b36f64426df698d3 # Parent 71a55baebef055c44c2837a8ae6166905227618a compiling AST to code is new in python 2.6 --- a/testing/code/test_source.py +++ b/testing/code/test_source.py @@ -192,12 +192,12 @@ class TestSourceParsingAndCompiling: assert source.getstatementrange(5) == (0, 9) def test_compile_to_ast(self): - if sys.version_info < (2, 5): - py.test.skip("requires Python 2.5") - import _ast + if sys.version_info < (2, 6): + py.test.skip("requires Python 2.6") + import ast source = Source("x = 4") - mod = source.compile(flag=_ast.PyCF_ONLY_AST) - assert isinstance(mod, _ast.Module) + mod = source.compile(flag=ast.PyCF_ONLY_AST) + assert isinstance(mod, ast.Module) compile(mod, "", "exec") def test_compile_and_getsource(self): From commits-noreply at bitbucket.org Thu Sep 17 15:31:58 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 17 Sep 2009 13:31:58 +0000 (UTC) Subject: [py-svn] py-trunk commit c4b739c83e0c: (micke, pedronis) Message-ID: <20090917133158.75B4F7110A@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Samuele Pedroni # Date 1253194295 -7200 # Node ID c4b739c83e0ccf8ebc85b686735c5789e27c23ed # Parent 9928a903e699748fc463bef0b36f64426df698d3 (micke, pedronis) teach the resultlog plugin about the xfail tweaked outcomes --- a/testing/pytest/plugin/test_pytest_resultlog.py +++ b/testing/pytest/plugin/test_pytest_resultlog.py @@ -24,7 +24,7 @@ def test_generic_path(): assert res == 'test/a:B().c[1]' def test_write_log_entry(): - reslog = ResultLog(None) + reslog = ResultLog(None, None) reslog.logfile = py.io.TextIO() reslog.write_log_entry('name', '.', '') entry = reslog.logfile.getvalue() @@ -100,7 +100,13 @@ class TestWithFunctionIntegration: import py def test_pass(): pass def test_skip(): py.test.skip("hello") - def test_fail(): raise ValueError("val") + def test_fail(): raise ValueError("FAIL") + + @py.test.mark.xfail + def test_xfail(): raise ValueError("XFAIL") + @py.test.mark.xfail + def test_xpass(): pass + """) lines = self.getresultlog(testdir, mod) assert len(lines) >= 3 @@ -112,8 +118,15 @@ class TestWithFunctionIntegration: assert lines[3].startswith("F ") assert lines[3].endswith("test_fail") - tb = "".join(lines[4:]) - assert tb.find("ValueError") != -1 + tb = "".join(lines[4:8]) + assert tb.find('raise ValueError("FAIL")') != -1 + + assert lines[8].startswith('x ') + tb = "".join(lines[8:14]) + assert tb.find('raise ValueError("XFAIL")') != -1 + + assert lines[14].startswith('P ') + assert len(lines) == 15 def test_internal_exception(self): # they are produced for example by a teardown failing @@ -122,7 +135,7 @@ class TestWithFunctionIntegration: raise ValueError except ValueError: excinfo = py.code.ExceptionInfo() - reslog = ResultLog(py.io.TextIO()) + reslog = ResultLog(None, py.io.TextIO()) reslog.pytest_internalerror(excinfo.getrepr()) entry = reslog.logfile.getvalue() entry_lines = entry.splitlines() @@ -142,12 +155,16 @@ def test_generic(testdir, LineMatcher): assert 0 def test_skip(): py.test.skip("") + @py.test.mark.xfail + def test_xfail(): + assert 0 """) testdir.runpytest("--resultlog=result.log") lines = testdir.tmpdir.join("result.log").readlines(cr=0) LineMatcher(lines).fnmatch_lines([ ". *:test_pass", "F *:test_fail", - "s *:test_skip", + "s *:test_skip", + "x *:test_xfail", ]) --- a/py/test/plugin/pytest_resultlog.py +++ b/py/test/plugin/pytest_resultlog.py @@ -14,7 +14,7 @@ def pytest_configure(config): resultlog = config.option.resultlog if resultlog: logfile = open(resultlog, 'w', 1) # line buffered - config._resultlog = ResultLog(logfile) + config._resultlog = ResultLog(config, logfile) config.pluginmanager.register(config._resultlog) def pytest_unconfigure(config): @@ -48,7 +48,8 @@ def generic_path(item): return ''.join(gpath) class ResultLog(object): - def __init__(self, logfile): + def __init__(self, config, logfile): + self.config = config self.logfile = logfile # preferably line buffered def write_log_entry(self, testpath, shortrepr, longrepr): @@ -61,8 +62,16 @@ class ResultLog(object): self.write_log_entry(testpath, shortrepr, longrepr) def pytest_runtest_logreport(self, report): - code = report.shortrepr - if report.passed: + res = self.config.hook.pytest_report_teststatus(report=report) + if res is not None: + code = res[1] + else: + code = report.shortrepr + if code == 'x': + longrepr = str(report.longrepr) + elif code == 'P': + longrepr = '' + elif report.passed: longrepr = "" elif report.failed: longrepr = str(report.longrepr) From commits-noreply at bitbucket.org Tue Sep 22 19:13:59 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 22 Sep 2009 17:13:59 +0000 (UTC) Subject: [py-svn] py-trunk commit 917a59d062d5: visit() now returns paths in depth-first order. fixes issue #47 Message-ID: <20090922171359.924D07109D@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1253639613 -7200 # Node ID 917a59d062d50efafe444327f2986d2d6eb5dcd7 # Parent 852bdd2c8a7825903dc7bdfa6e7befe900e25f5f visit() now returns paths in depth-first order. fixes issue #47 --- a/py/path/local.py +++ b/py/path/local.py @@ -334,12 +334,12 @@ class LocalPath(FSBase): assert self!=target copychunked(self, target) else: - target.ensure(dir=1) def rec(p): return p.check(link=0) for x in self.visit(rec=rec): relpath = x.relto(self) newx = target.join(relpath) + newx.dirpath().ensure(dir=1) if x.check(link=1): newx.mksymlinkto(x.readlink()) elif x.check(file=1): --- a/testing/path/test_local.py +++ b/testing/path/test_local.py @@ -198,6 +198,15 @@ class TestLocalPath(common.CommonFSTests l2 = tmpdir.join(newfilename) assert l2.read() == 'foo' + def test_visit_depth_first(self, tmpdir): + p1 = tmpdir.ensure("a","1") + p2 = tmpdir.ensure("b","2") + p3 = tmpdir.ensure("breadth") + l = list(tmpdir.visit(lambda x: x.check(file=1))) + assert l[0] == p1 + assert l[1] == p2 + assert l[2] == p3 + class TestExecutionOnWindows: disabled = py.std.sys.platform != 'win32' --- a/py/path/common.py +++ b/py/path/common.py @@ -278,20 +278,20 @@ newline will be removed from the end of if rec: if isinstance(rec, str): rec = fnmatch(fil) - elif not py.builtin.callable(rec): - rec = lambda x: True - reclist = [self] - while reclist: - current = reclist.pop(0) - try: - dirlist = current.listdir() - except ignore: - return - 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) + elif not hasattr(rec, '__call__'): + rec = None + try: + entries = self.listdir() + except ignore: + return + dirs = [p for p in entries + if p.check(dir=1) and (rec is None or rec(p))] + for subdir in dirs: + for p in subdir.visit(fil=fil, rec=rec, ignore=ignore): + yield p + for p in entries: + if fil is None or fil(p): + yield p def _sortlist(self, res, sort): if sort: From commits-noreply at bitbucket.org Tue Sep 22 19:14:01 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 22 Sep 2009 17:14:01 +0000 (UTC) Subject: [py-svn] py-trunk commit 852bdd2c8a78: * allowing arbitrary keys for xspecs but adding some sanity checks to xspec-parsing and makegateway. Message-ID: <20090922171401.5F98F71125@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1253637620 -7200 # Node ID 852bdd2c8a7825903dc7bdfa6e7befe900e25f5f # Parent c4b739c83e0ccf8ebc85b686735c5789e27c23ed * allowing arbitrary keys for xspecs but adding some sanity checks to xspec-parsing and makegateway. * fixing a python3 IO issue - we need to retain sys.stdout/stdin references to keep the underlying byte stream open. --- a/py/execnet/gateway_base.py +++ b/py/execnet/gateway_base.py @@ -119,10 +119,6 @@ sys.stdin = tempfile.TemporaryFile('r') def __init__(self, outfile, infile): # we need raw byte streams - if hasattr(infile, 'buffer'): - infile = infile.buffer - if hasattr(outfile, 'buffer'): - outfile = outfile.buffer self.outfile, self.infile = outfile, infile if sys.platform == "win32": import msvcrt @@ -132,7 +128,10 @@ sys.stdin = tempfile.TemporaryFile('r') def read(self, numbytes): """Read exactly 'numbytes' bytes from the pipe. """ - data = self.infile.read(numbytes) + try: + data = self.infile.buffer.read(numbytes) + except AttributeError: + data = self.infile.read(numbytes) if len(data) < numbytes: raise EOFError return data @@ -140,7 +139,10 @@ sys.stdin = tempfile.TemporaryFile('r') def write(self, data): """write out all data bytes. """ assert isinstance(data, bytes) - self.outfile.write(data) + try: + self.outfile.buffer.write(data) + except AttributeError: + self.outfile.write(data) self.outfile.flush() def close_read(self): --- a/py/execnet/gateway.py +++ b/py/execnet/gateway.py @@ -226,7 +226,7 @@ class PopenGateway(PopenCmdGateway): s = "\n".join([extra, "import sys ; sys.path[:0] = %r" % (plist,), "import os ; os.environ['PYTHONPATH'] = %r" % ppath, - str(py.code.Source(stdouterrin_setnull)), + inspect.getsource(stdouterrin_setnull), "stdouterrin_setnull()", "" ]) --- a/py/execnet/xspec.py +++ b/py/execnet/xspec.py @@ -22,11 +22,17 @@ class XSpec: key, value = keyvalue, True else: key, value = keyvalue[:i], keyvalue[i+1:] - # XXX be restrictive for now - if key not in XSpec.__dict__: + if key[0] == "_": raise AttributeError("%r not a valid XSpec key" % key) + if key in self.__dict__: + raise ValueError("duplicate key: %r in %r" %(key, string)) setattr(self, key, value) + def __getattr__(self, name): + if name[0] == "_": + raise AttributeError(name) + return None + def __repr__(self): return "" %(self._spec,) def __str__(self): @@ -39,11 +45,6 @@ class XSpec: def __ne__(self, other): return self._spec != getattr(other, '_spec', None) - #def __getattr__(self, name): - # if name[0] == "_": - # raise AttributeError(name) - # return None - def _samefilesystem(self): return bool(self.popen and not self.chdir) @@ -58,6 +59,8 @@ def makegateway(spec): assert not spec.python, "socket: specifying python executables not supported" hostport = spec.socket.split(":") gw = py.execnet.SocketGateway(*hostport) + else: + raise ValueError("no gateway type found for %r" % (spec._spec,)) gw.spec = spec if spec.chdir or spec.nice: channel = gw.remote_exec(""" --- a/testing/execnet/test_xspec.py +++ b/testing/execnet/test_xspec.py @@ -9,7 +9,7 @@ class TestXSpec: assert spec.python == "c:/this/python2.5" assert spec.chdir == "d:\hello" assert spec.nice is None - assert not hasattr(spec, 'xyz') + assert not hasattr(spec, '_xyz') py.test.raises(AttributeError, "spec._hello") @@ -36,6 +36,14 @@ class TestXSpec: for x in ("popen", "popen//python=this"): assert XSpec(x)._spec == x + def test_samekeyword_twice_raises(self): + py.test.raises(ValueError, "XSpec('popen//popen')") + py.test.raises(ValueError, "XSpec('popen//popen=123')") + + def test_unknown_keys_allowed(self): + xspec = XSpec("hello=3") + assert xspec.hello == '3' + def test_repr_and_string(self): for x in ("popen", "popen//python=this"): assert repr(XSpec(x)).find("popen") != -1 @@ -48,6 +56,9 @@ class TestXSpec: assert hash(XSpec("socket=hello:8080")) != hash(XSpec("popen")) class TestMakegateway: + def test_no_type(self): + py.test.raises(ValueError, "py.execnet.makegateway('hello')") + def test_popen(self): gw = py.execnet.makegateway("popen") assert gw.spec.python == None @@ -76,20 +87,20 @@ class TestMakegateway: assert rinfo.cwd == py.std.os.getcwd() assert rinfo.version_info == py.std.sys.version_info - def test_popen_cpython24(self): - for trypath in ('python2.4', r'C:\Python24\python.exe'): - cpython24 = py.path.local.sysfind(trypath) - if cpython24 is not None: - cpython24 = cpython24.realpath() + def test_popen_cpython25(self): + for trypath in ('python2.5', r'C:\Python25\python.exe'): + cpython25 = py.path.local.sysfind(trypath) + if cpython25 is not None: + cpython25 = cpython25.realpath() break else: - py.test.skip("cpython2.4 not found") - gw = py.execnet.makegateway("popen//python=%s" % cpython24) + py.test.skip("cpython2.5 not found") + gw = py.execnet.makegateway("popen//python=%s" % cpython25) rinfo = gw._rinfo() if py.std.sys.platform != "darwin": # it's confusing there - assert rinfo.executable == cpython24 + assert rinfo.executable == cpython25 assert rinfo.cwd == py.std.os.getcwd() - assert rinfo.version_info[:2] == (2,4) + assert rinfo.version_info[:2] == (2,5) def test_popen_cpython26(self): for trypath in ('python2.6', r'C:\Python26\python.exe'): From commits-noreply at bitbucket.org Wed Sep 23 04:08:35 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 23 Sep 2009 02:08:35 +0000 (UTC) Subject: [py-svn] py-trunk commit 742f38d8eb11: allow a path to explicity given for py.lookup Message-ID: <20090923020835.324DC71127@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1253671465 18000 # Node ID 742f38d8eb11e1f32183b15f2de7c2997cd0ff9e # Parent 917a59d062d50efafe444327f2986d2d6eb5dcd7 allow a path to explicity given for py.lookup --- a/testing/cmdline/test_cmdline.py +++ b/testing/cmdline/test_cmdline.py @@ -15,4 +15,14 @@ class TestPyLookup: result.stdout.fnmatch_lines( ['*%s:*' %(p.basename)] ) - + + def test_with_explicit_path(self, testxbdir): + sub1 = testdir.mkdir("things") + sub2 = testdir.mkdir("foo") + sub1.join("pyfile.py").write("def stuff(): pass") + searched = sub2.join("other.py") + searched.write("stuff = x") + result = testdir.runpybin("py.lookup", sub2.basename, "stuff") + result.stdout.fnmatch_lines( + ["%s:1: stuff = x" % (searched.basename,)] + ) --- a/py/cmdline/pylookup.py +++ b/py/cmdline/pylookup.py @@ -12,7 +12,6 @@ import py from py.__.io.terminalwriter import ansi_print, terminal_width import re -curdir = py.path.local() def rec(p): return p.check(dotfile=0) @@ -35,12 +34,17 @@ def find_indexes(search_line, string): def main(): (options, args) = parser.parse_args() - string = args[0] + if len(args) == 2: + search_dir, string = args + search_dir = py.path.local(search_dir) + else: + search_dir = py.path.local() + string = args[0] if options.ignorecase: string = string.lower() - for x in curdir.visit('*.py', rec): + for x in search_dir.visit('*.py', rec): # match filename directly - s = x.relto(curdir) + s = x.relto(search_dir) if options.ignorecase: s = s.lower() if s.find(string) != -1: @@ -64,7 +68,7 @@ def main(): if not indexes: continue if not options.context: - sys.stdout.write("%s:%d: " %(x.relto(curdir), i+1)) + sys.stdout.write("%s:%d: " %(x.relto(search_dir), i+1)) last_index = 0 for index in indexes: sys.stdout.write(line[last_index: index]) @@ -75,5 +79,5 @@ def main(): else: context = (options.context)/2 for count in range(max(0, i-context), min(len(lines) - 1, i+context+1)): - print("%s:%d: %s" %(x.relto(curdir), count+1, lines[count].rstrip())) + print("%s:%d: %s" %(x.relto(search_dir), count+1, lines[count].rstrip())) print("-" * terminal_width) From commits-noreply at bitbucket.org Wed Sep 23 04:08:36 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 23 Sep 2009 02:08:36 +0000 (UTC) Subject: [py-svn] py-trunk commit ff0c24f55bb2: add changelog entry for last commit Message-ID: <20090923020836.C0BD371128@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1253671627 18000 # Node ID ff0c24f55bb2205ae999fc8d462c6fd73a391f33 # Parent 742f38d8eb11e1f32183b15f2de7c2997cd0ff9e add changelog entry for last commit --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,6 +1,8 @@ Changes between 1.0.x and 'trunk' ===================================== +* add the ability to specify a path for py.lookup to search in + * fix a funcarg cached_setup bug probably only occuring in distributed testing and "module" scope with teardown. From commits-noreply at bitbucket.org Wed Sep 23 04:08:38 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 23 Sep 2009 02:08:38 +0000 (UTC) Subject: [py-svn] py-trunk commit 3369fee9b19e: update docstring Message-ID: <20090923020838.69FA07112A@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1253671670 18000 # Node ID 3369fee9b19e8f1ccf2d5daf60ce046280698bd0 # Parent ff0c24f55bb2205ae999fc8d462c6fd73a391f33 update docstring --- a/py/cmdline/pylookup.py +++ b/py/cmdline/pylookup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """\ -py.lookup SEARCH_STRING [options] +py.lookup [search_directory] SEARCH_STRING [options] Looks recursively at Python files for a SEARCH_STRING, starting from the present working directory. Prints the line, with the filename and line-number From commits-noreply at bitbucket.org Wed Sep 23 04:08:40 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 23 Sep 2009 02:08:40 +0000 (UTC) Subject: [py-svn] py-trunk commit 31b6c51fab40: Add a simple (hopefully) cross-python marshaller Message-ID: <20090923020840.15C7971130@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1253671720 18000 # Node ID 31b6c51fab40ba0798c2726d799d3a3f631a2ef0 # Parent 3369fee9b19e8f1ccf2d5daf60ce046280698bd0 Add a simple (hopefully) cross-python marshaller Will rewrite the tests soon... --- /dev/null +++ b/testing/execnet/test_serializer.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +import shutil +import py +from py.__.execnet import serializer + +def setup_module(mod): + mod._save_python3 = serializer._INPY3 + +def teardown_module(mod): + serializer._setup_version_dependent_constants() + +def _dump(obj): + stream = py.io.BytesIO() + saver = serializer.Serializer(stream) + saver.save(obj) + return stream.getvalue() + +def _load(serialized, str_coerion): + stream = py.io.BytesIO(serialized) + opts = serializer.UnserializationOptions(str_coerion) + unserializer = serializer.Unserializer(stream, opts) + return unserializer.load() + +def _run_in_version(is_py3, func, *args): + serializer._INPY3 = is_py3 + serializer._setup_version_dependent_constants() + try: + return func(*args) + finally: + serializer._INPY3 = _save_python3 + +def dump_py2(obj): + return _run_in_version(False, _dump, obj) + +def dump_py3(obj): + return _run_in_version(True, _dump, obj) + +def load_py2(serialized, str_coercion=False): + return _run_in_version(False, _load, serialized, str_coercion) + +def load_py3(serialized, str_coercion=False): + return _run_in_version(True, _load, serialized, str_coercion) + +try: + bytes +except NameError: + bytes = str + + +def pytest_funcarg__py2(request): + return _py2_wrapper + +def pytest_funcarg__py3(request): + return _py3_wrapper + +class TestSerializer: + + def test_int(self): + for dump in dump_py2, dump_py3: + p = dump_py2(4) + for load in load_py2, load_py3: + i = load(p) + assert isinstance(i, int) + assert i == 4 + py.test.raises(serializer.SerializationError, dump, 123456678900) + + def test_bytes(self): + for dump in dump_py2, dump_py3: + p = dump(serializer._b('hi')) + for load in load_py2, load_py3: + s = load(p) + assert isinstance(s, serializer.bytes) + assert s == serializer._b('hi') + + def check_sequence(self, seq): + for dump in dump_py2, dump_py3: + p = dump(seq) + for load in load_py2, load_py3: + l = load(p) + assert l == seq + + def test_list(self): + self.check_sequence([1, 2, 3]) + + @py.test.mark.xfail + # I'm not sure if we need the complexity. + def test_recursive_list(self): + l = [1, 2, 3] + l.append(l) + self.check_sequence(l) + + def test_tuple(self): + self.check_sequence((1, 2, 3)) + + def test_dict(self): + for dump in dump_py2, dump_py3: + p = dump({"hi" : 2, (1, 2, 3) : 32}) + for load in load_py2, load_py3: + d = load(p, True) + assert d == {"hi" : 2, (1, 2, 3) : 32} + + def test_string(self): + py.test.skip("will rewrite") + p = dump_py2("xyz") + s = load_py2(p) + assert isinstance(s, str) + assert s == "xyz" + s = load_py3(p) + assert isinstance(s, bytes) + assert s == serializer.b("xyz") + p = dump_py2("xyz") + s = load_py3(p, True) + assert isinstance(s, serializer._unicode) + assert s == serializer.unicode("xyz") + p = dump_py3("xyz") + s = load_py2(p, True) + assert isinstance(s, str) + assert s == "xyz" + + def test_unicode(self): + py.test.skip("will rewrite") + for dump, uni in (dump_py2, serializer._unicode), (dump_py3, str): + p = dump(uni("xyz")) + for load in load_py2, load_py3: + s = load(p) + assert isinstance(s, serializer._unicode) + assert s == serializer._unicode("xyz") --- /dev/null +++ b/py/execnet/serializer.py @@ -0,0 +1,291 @@ +""" +Simple marshal format (based on pickle) designed to work across Python versions. +""" + +import sys +import struct + +import py + +_INPY3 = _REALLY_PY3 = sys.version_info > (3, 0) + +class SerializeError(Exception): + pass + +class SerializationError(SerializeError): + """Error while serializing an object.""" + +class UnserializableType(SerializationError): + """Can't serialize a type.""" + +class UnserializationError(SerializeError): + """Error while unserializing an object.""" + +class VersionMismatch(UnserializationError): + """Data from a previous or later format.""" + +class Corruption(UnserializationError): + """The pickle format appears to have been corrupted.""" + +if _INPY3: + def b(s): + return s.encode("ascii") + _b = b + class _unicode(str): + pass + bytes = bytes +else: + class bytes(str): + pass + b = str + _b = bytes + _unicode = unicode + +FOUR_BYTE_INT_MAX = 2147483647 + +_int4_format = struct.Struct("!i") + +# Protocol constants +VERSION_NUMBER = 1 +VERSION = b(chr(VERSION_NUMBER)) +PY2STRING = b('s') +PY3STRING = b('t') +UNICODE = b('u') +BYTES = b('b') +NEWLIST = b('l') +BUILDTUPLE = b('T') +SETITEM = b('m') +NEWDICT = b('d') +INT = b('i') +STOP = b('S') + +class CrossVersionOptions(object): + pass + +class Serializer(object): + + def __init__(self, stream): + self.stream = stream + + def save(self, obj): + self.stream.write(VERSION) + self._save(obj) + self.stream.write(STOP) + + def _save(self, obj): + tp = type(obj) + try: + dispatch = self.dispatch[tp] + except KeyError: + raise UnserializableType("can't serialize %s" % (tp,)) + dispatch(self, obj) + + def save_bytes(self, bytes_): + self.stream.write(BYTES) + self._write_byte_sequence(bytes_) + + def save_unicode(self, s): + self.stream.write(UNICODE) + self._write_unicode_string(s) + + def save_string(self, s): + if _INPY3: + self.stream.write(PY3STRING) + self._write_unicode_string(s) + else: + # Case for tests + if _REALLY_PY3 and isinstance(s, str): + s = s.encode("latin-1") + self.stream.write(PY2STRING) + self._write_byte_sequence(s) + + def _write_unicode_string(self, s): + try: + as_bytes = s.encode("utf-8") + except UnicodeEncodeError: + raise SerializationError("strings must be utf-8 encodable") + self._write_byte_sequence(as_bytes) + + def _write_byte_sequence(self, bytes_): + self._write_int4(len(bytes_), "string is too long") + self.stream.write(bytes_) + + def save_int(self, i): + self.stream.write(INT) + self._write_int4(i) + + def _write_int4(self, i, error="int must be less than %i" % + (FOUR_BYTE_INT_MAX,)): + if i > FOUR_BYTE_INT_MAX: + raise SerializationError(error) + self.stream.write(_int4_format.pack(i)) + + def save_list(self, L): + self.stream.write(NEWLIST) + self._write_int4(len(L), "list is too long") + for i, item in enumerate(L): + self._write_setitem(i, item) + + def _write_setitem(self, key, value): + self._save(key) + self._save(value) + self.stream.write(SETITEM) + + def save_dict(self, d): + self.stream.write(NEWDICT) + for key, value in d.items(): + self._write_setitem(key, value) + + def save_tuple(self, tup): + for item in tup: + self._save(item) + self.stream.write(BUILDTUPLE) + self._write_int4(len(tup), "tuple is too long") + + +class _UnserializationOptions(object): + pass + +class _Py2UnserializationOptions(_UnserializationOptions): + + def __init__(self, py3_strings_as_str=False): + self.py3_strings_as_str = py3_strings_as_str + +class _Py3UnserializationOptions(_UnserializationOptions): + + def __init__(self, py2_strings_as_str=False): + self.py2_strings_as_str = py2_strings_as_str + + +_unchanging_dispatch = {} +for tp in (dict, list, tuple, int): + name = "save_%s" % (tp.__name__,) + _unchanging_dispatch[tp] = getattr(Serializer, name) +del tp, name + +def _setup_dispatch(): + dispatch = _unchanging_dispatch.copy() + # This is sutble. bytes is aliased to str in 2.6, so + # dispatch[bytes] is overwritten. Additionally, we alias unicode + # to str in 3.x, so dispatch[unicode] is overwritten with + # save_string. + dispatch[bytes] = Serializer.save_bytes + dispatch[unicode] = Serializer.save_unicode + dispatch[str] = Serializer.save_string + Serializer.dispatch = dispatch + +def _setup_version_dependent_constants(leave_unicode_alone=False): + global unicode, UnserializationOptions + if _INPY3: + unicode = str + UnserializationOptions = _Py3UnserializationOptions + else: + UnserializationOptions = _Py2UnserializationOptions + unicode = _unicode + _setup_dispatch() +_setup_version_dependent_constants() + + +class _Stop(Exception): + pass + +class Unserializer(object): + + def __init__(self, stream, options=None): + self.stream = stream + if options is None: + options = UnserializationOptions() + self.options = options + + def load(self): + self.stack = [] + version = ord(self.stream.read(1)) + if version != VERSION_NUMBER: + raise VersionMismatch("%i != %i" % (version, VERSION_NUMBER)) + try: + while True: + opcode = self.stream.read(1) + if not opcode: + raise EOFError + try: + loader = self.opcodes[opcode] + except KeyError: + raise Corruption("unkown opcode %s" % (opcode,)) + loader(self) + except _Stop: + if len(self.stack) != 1: + raise UnserializationError("internal unserialization error") + return self.stack[0] + else: + raise Corruption("didn't get STOP") + + opcodes = {} + + def load_int(self): + i = self._read_int4() + self.stack.append(i) + opcodes[INT] = load_int + + def _read_int4(self): + return _int4_format.unpack(self.stream.read(4))[0] + + def _read_byte_string(self): + length = self._read_int4() + as_bytes = self.stream.read(length) + return as_bytes + + def load_py3string(self): + as_bytes = self._read_byte_string() + if (not _INPY3 and self.options.py3_strings_as_str) and not _REALLY_PY3: + # XXX Should we try to decode into latin-1? + self.stack.append(as_bytes) + else: + self.stack.append(as_bytes.decode("utf-8")) + opcodes[PY3STRING] = load_py3string + + def load_py2string(self): + as_bytes = self._read_byte_string() + if (_INPY3 and self.options.py2_strings_as_str) or \ + (_REALLY_PY3 and not _INPY3): + s = as_bytes.decode("latin-1") + else: + s = as_bytes + self.stack.append(s) + opcodes[PY2STRING] = load_py2string + + def load_bytes(self): + s = bytes(self._read_byte_string()) + self.stack.append(s) + opcodes[BYTES] = load_bytes + + def load_unicode(self): + self.stack.append(self._read_byte_string().decode("utf-8")) + opcodes[UNICODE] = load_unicode + + def load_newlist(self): + length = self._read_int4() + self.stack.append([None] * length) + opcodes[NEWLIST] = load_newlist + + def load_setitem(self): + if len(self.stack) < 3: + raise Corruption("not enough items for setitem") + value = self.stack.pop() + key = self.stack.pop() + self.stack[-1][key] = value + opcodes[SETITEM] = load_setitem + + def load_newdict(self): + self.stack.append({}) + opcodes[NEWDICT] = load_newdict + + def load_buildtuple(self): + length = self._read_int4() + tup = tuple(self.stack[-length:]) + del self.stack[-length:] + self.stack.append(tup) + opcodes[BUILDTUPLE] = load_buildtuple + + def load_stop(self): + raise _Stop + opcodes[STOP] = load_stop From commits-noreply at bitbucket.org Wed Sep 23 19:44:46 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 23 Sep 2009 17:44:46 +0000 (UTC) Subject: [py-svn] py-trunk commit 5e999fa934c1: Fixed a typo in error.py causing it to fail on Windows. Message-ID: <20090923174446.9B7B5710A1@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Jurko # Date 1252707373 -7200 # Node ID 5e999fa934c130c004da74a9ec54ae6e9b20d579 # Parent 71a55baebef055c44c2837a8ae6166905227618a Fixed a typo in error.py causing it to fail on Windows. --- a/py/error.py +++ b/py/error.py @@ -74,7 +74,7 @@ class ErrorMaker(object): cls = self._geterrnoclass(errno) else: try: - cls = self._geterrnoclass(_winerrnomap[eno]) + cls = self._geterrnoclass(_winerrnomap[errno]) except KeyError: raise value raise cls("%s%r" % (func.__name__, args)) From commits-noreply at bitbucket.org Wed Sep 23 19:44:48 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 23 Sep 2009 17:44:48 +0000 (UTC) Subject: [py-svn] py-trunk commit 7eb914ccf56c: Corrected the constructed system path value (broken by the env.cmd, env.sh & env.py file move in 4abc620bb044). Message-ID: <20090923174448.29F1471123@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Jurko # Date 1252708557 -7200 # Node ID 7eb914ccf56cccecfc6b3f28e726b2426442375e # Parent 5e999fa934c130c004da74a9ec54ae6e9b20d579 Corrected the constructed system path value (broken by the env.cmd, env.sh & env.py file move in 4abc620bb044). --- a/py/bin/env.py +++ b/py/bin/env.py @@ -3,7 +3,7 @@ import sys, os, os.path progpath = sys.argv[0] -packagedir = os.path.abspath(os.path.dirname(progpath)) +packagedir = os.path.dirname(os.path.dirname(os.path.abspath(progpath))) packagename = os.path.basename(packagedir) bindir = os.path.join(packagedir, 'bin') if sys.platform == 'win32': From commits-noreply at bitbucket.org Wed Sep 23 19:44:49 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 23 Sep 2009 17:44:49 +0000 (UTC) Subject: [py-svn] py-trunk commit 9facb0d433af: merging jarko'S fixes, resolves issue #45, resolves issue #46 Message-ID: <20090923174449.9E06E71130@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1253727823 -7200 # Node ID 9facb0d433af6a8b1567eac0af7cd7ffcb85d806 # Parent 31b6c51fab40ba0798c2726d799d3a3f631a2ef0 # Parent 7eb914ccf56cccecfc6b3f28e726b2426442375e merging jarko'S fixes, resolves issue #45, resolves issue #46 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,6 +1,8 @@ Changes between 1.0.x and 'trunk' ===================================== +* merge Jarko's fixes, issue #45 and #46 + * add the ability to specify a path for py.lookup to search in * fix a funcarg cached_setup bug probably only occuring --- a/doc/test/quickstart.txt +++ b/doc/test/quickstart.txt @@ -23,7 +23,7 @@ Now create a file ``test_sample.py`` wit def func(x): return x + 1 def test_answer(): - assert f(3) == 5 + assert func(3) == 5 You can now run the test file like this:: From commits-noreply at bitbucket.org Wed Sep 23 19:48:41 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 23 Sep 2009 17:48:41 +0000 (UTC) Subject: [py-svn] py-trunk commit e4800830de56: applying doc fix from jarko Message-ID: <20090923174841.E4B78710FB@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1253728047 -7200 # Node ID e4800830de5691a30721886de745061a16c6469d # Parent 7c30db1d80df509b3287b019af3db5cdf14c7368 applying doc fix from jarko --- a/doc/test/quickstart.txt +++ /dev/null @@ -1,71 +0,0 @@ -.. _`setuptools installation`: http://pypi.python.org/pypi/setuptools - - -================== -Quickstart -================== - -.. _here: ../download.html#no-setuptools - - -With a `setuptools installation`_ (otherwise see here_) you can type:: - - easy_install -U py - -On Linux systems you may need to execute this as the superuser and -on Windows you might need to write down the full path to ``easy_install``. - -Now create a file ``test_sample.py`` with the following content: - -.. sourcecode:: python - - # content of test_sample.py - def func(x): - return x + 1 - def test_answer(): - assert f(3) == 5 - -You can now run the test file like this:: - - py.test test_sample.py - -and will see output like this: - -.. sourcecode:: python - - =========================== test session starts ============================ - python: platform linux2 -- Python 2.6.2 - test object 1: test_sample.py - - test_sample.py F - - ================================= FAILURES ================================= - _______________________________ test_answer ________________________________ - - def test_answer(): - > assert func(3) == 5 - E assert 4 == 5 - E + where 4 = func(3) - - test_sample.py:6: AssertionError - ========================= 1 failed in 0.08 seconds ========================= - -This output contains Python interpreter information, a list of test objects, -a progress report and important details of the failure. - -**Where to go from here** - -`tutorials`_: a collection of starting points with code examples - -`features`_: overview and description of test features - -`contact`_: many ways for feedback and questions - -.. _`contact`: ../contact.html -.. _`automatically collected`: features.html#autocollect -.. _download: ../download.html -.. _features: features.html -.. _tutorials: talks.html - - - From commits-noreply at bitbucket.org Sat Sep 26 19:34:45 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 26 Sep 2009 17:34:45 +0000 (UTC) Subject: [py-svn] py-trunk commit f4aa7209a3eb: test cross version serialization by launching subprocesses; much cleaner! Message-ID: <20090926173445.A04B971126@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1253986524 18000 # Node ID f4aa7209a3eb719349aa971ac242b29e4ae80134 # Parent 9facb0d433af6a8b1567eac0af7cd7ffcb85d806 test cross version serialization by launching subprocesses; much cleaner! --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -1,50 +1,78 @@ # -*- coding: utf-8 -*- -import shutil +import sys +import os +import tempfile +import subprocess import py from py.__.execnet import serializer + +def _find_version(suffix=""): + name = "python" + suffix + executable = py.path.local.sysfind(name) + if executable is None: + py.test.skip("can't find a %r executable" % (name,)) + return executable + def setup_module(mod): - mod._save_python3 = serializer._INPY3 + mod.TEMPDIR = py.path.local(tempfile.mkdtemp()) + if sys.version_info > (3, 0): + mod._py3_wrapper = PythonWrapper(py.path.local(sys.executable)) + mod._py2_wrapper = PythonWrapper(_find_version()) + else: + mod._py3_wrapper = PythonWrapper(_find_version("3")) + mod._py2_wrapper = PythonWrapper(py.path.local(sys.executable)) + mod._old_pypath = os.environ.get("PYTHONPATH") + pylib = str(py.path.local(py.__file__).dirpath().join("..")) + os.environ["PYTHONPATH"] = pylib def teardown_module(mod): - serializer._setup_version_dependent_constants() + TEMPDIR.remove(True) + if _old_pypath is not None: + os.environ["PYTHONPATH"] = _old_pypath -def _dump(obj): - stream = py.io.BytesIO() - saver = serializer.Serializer(stream) - saver.save(obj) - return stream.getvalue() -def _load(serialized, str_coerion): - stream = py.io.BytesIO(serialized) - opts = serializer.UnserializationOptions(str_coerion) - unserializer = serializer.Unserializer(stream, opts) - return unserializer.load() +class PythonWrapper(object): -def _run_in_version(is_py3, func, *args): - serializer._INPY3 = is_py3 - serializer._setup_version_dependent_constants() - try: - return func(*args) - finally: - serializer._INPY3 = _save_python3 + def __init__(self, executable): + self.executable = executable -def dump_py2(obj): - return _run_in_version(False, _dump, obj) + def dump(self, obj_rep): + script_file = TEMPDIR.join("dump.py") + script_file.write(""" +from py.__.execnet import serializer +import sys +if sys.version_info > (3, 0): # Need binary output + sys.stdout = sys.stdout.detach() +saver = serializer.Serializer(sys.stdout) +saver.save(%s)""" % (obj_rep,)) + return self.executable.sysexec(script_file) -def dump_py3(obj): - return _run_in_version(True, _dump, obj) + def load(self, data, option_args=""): + script_file = TEMPDIR.join("load.py") + script_file.write(r""" +from py.__.execnet import serializer +import sys +if sys.version_info > (3, 0): + sys.stdin = sys.stdin.detach() +options = serializer.UnserializationOptions(%s) +loader = serializer.Unserializer(sys.stdin, options) +obj = loader.load() +sys.stdout.write(type(obj).__name__ + "\n") +sys.stdout.write(repr(obj))""" % (option_args,)) + popen = subprocess.Popen([str(self.executable), str(script_file)], + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE) + stdout, stderr = popen.communicate(data.encode("latin-1")) + ret = popen.returncode + if ret: + raise py.process.cmdexec.Error(ret, ret, str(self.executable), + stdout, stderr) + return [s.decode("ascii") for s in stdout.splitlines()] -def load_py2(serialized, str_coercion=False): - return _run_in_version(False, _load, serialized, str_coercion) - -def load_py3(serialized, str_coercion=False): - return _run_in_version(True, _load, serialized, str_coercion) - -try: - bytes -except NameError: - bytes = str + def __repr__(self): + return "" % (self.executable,) def pytest_funcarg__py2(request): @@ -55,73 +83,86 @@ def pytest_funcarg__py3(request): class TestSerializer: - def test_int(self): - for dump in dump_py2, dump_py3: - p = dump_py2(4) - for load in load_py2, load_py3: - i = load(p) - assert isinstance(i, int) - assert i == 4 - py.test.raises(serializer.SerializationError, dump, 123456678900) + def test_int(self, py2, py3): + for dump in py2.dump, py3.dump: + p = dump(4) + for load in py2.load, py3.load: + tp, v = load(p) + assert tp == "int" + assert int(v) == 4 + py.test.raises(serializer.SerializationError, + serializer.Serializer(py.io.BytesIO()).save, + 123456678900) - def test_bytes(self): - for dump in dump_py2, dump_py3: - p = dump(serializer._b('hi')) - for load in load_py2, load_py3: - s = load(p) - assert isinstance(s, serializer.bytes) - assert s == serializer._b('hi') + def test_bytes(self, py2, py3): + p = py3.dump("b'hi'") + tp, v = py2.load(p) + assert tp == "str" + assert v == "'hi'" + tp, v = py3.load(p) + assert tp == "bytes" + assert v == "b'hi'" - def check_sequence(self, seq): - for dump in dump_py2, dump_py3: + def check_sequence(self, seq, tp_name, rep, py2, py3): + for dump in py2.dump, py3.dump: p = dump(seq) - for load in load_py2, load_py3: - l = load(p) - assert l == seq + for load in py2.load, py3.load: + tp, v = load(p) + assert tp == tp_name + assert v == rep - def test_list(self): - self.check_sequence([1, 2, 3]) + def test_list(self, py2, py3): + self.check_sequence([1, 2, 3], "list", "[1, 2, 3]", py2, py3) @py.test.mark.xfail # I'm not sure if we need the complexity. - def test_recursive_list(self): + def test_recursive_list(self, py2, py3): l = [1, 2, 3] l.append(l) - self.check_sequence(l) + p = py2.dump(l) + tp, rep = py2.load(l) + assert tp == "list" - def test_tuple(self): - self.check_sequence((1, 2, 3)) + def test_tuple(self, py2, py3): + self.check_sequence((1, 2, 3), "tuple", "(1, 2, 3)", py2, py3) - def test_dict(self): - for dump in dump_py2, dump_py3: - p = dump({"hi" : 2, (1, 2, 3) : 32}) - for load in load_py2, load_py3: - d = load(p, True) - assert d == {"hi" : 2, (1, 2, 3) : 32} + def test_dict(self, py2, py3): + for dump in py2.dump, py3.dump: + p = dump({6 : 2, (1, 2, 3) : 32}) + for load in py2.load, py3.load: + tp, v = load(p) + assert tp == "dict" + # XXX comparing dict reprs + assert v == "{6: 2, (1, 2, 3): 32}" - def test_string(self): - py.test.skip("will rewrite") - p = dump_py2("xyz") - s = load_py2(p) - assert isinstance(s, str) - assert s == "xyz" - s = load_py3(p) - assert isinstance(s, bytes) - assert s == serializer.b("xyz") - p = dump_py2("xyz") - s = load_py3(p, True) - assert isinstance(s, serializer._unicode) - assert s == serializer.unicode("xyz") - p = dump_py3("xyz") - s = load_py2(p, True) - assert isinstance(s, str) - assert s == "xyz" + def test_string(self, py2, py3): + p = py2.dump("'xyz'") + tp, s = py2.load(p) + assert tp == "str" + assert s == "'xyz'" + tp, s = py3.load(p) + assert tp == "bytes" + assert s == "b'xyz'" + tp, s = py3.load(p, "True") + assert tp == "str" + assert s == "'xyz'" + p = py3.dump("'xyz'") + tp, s = py2.load(p, True) + assert tp == "str" + assert s == "'xyz'" - def test_unicode(self): - py.test.skip("will rewrite") - for dump, uni in (dump_py2, serializer._unicode), (dump_py3, str): - p = dump(uni("xyz")) - for load in load_py2, load_py3: - s = load(p) - assert isinstance(s, serializer._unicode) - assert s == serializer._unicode("xyz") + def test_unicode(self, py2, py3): + p = py2.dump("u'hi'") + tp, s = py2.load(p) + assert tp == "unicode" + assert s == "u'hi'" + tp, s = py3.load(p) + assert tp == "str" + assert s == "'hi'" + p = py3.dump("'hi'") + tp, s = py3.load(p) + assert tp == "str" + assert s == "'hi'" + tp, s = py2.load(p) + assert tp == "unicode" + assert s == "u'hi'" --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -35,8 +35,6 @@ if _INPY3: pass bytes = bytes else: - class bytes(str): - pass b = str _b = bytes _unicode = unicode @@ -80,25 +78,28 @@ class Serializer(object): raise UnserializableType("can't serialize %s" % (tp,)) dispatch(self, obj) + dispatch = {} + def save_bytes(self, bytes_): self.stream.write(BYTES) self._write_byte_sequence(bytes_) + dispatch[bytes] = save_bytes - def save_unicode(self, s): - self.stream.write(UNICODE) - self._write_unicode_string(s) - - def save_string(self, s): - if _INPY3: + if _INPY3: + def save_string(self, s): self.stream.write(PY3STRING) self._write_unicode_string(s) - else: - # Case for tests - if _REALLY_PY3 and isinstance(s, str): - s = s.encode("latin-1") + else: + def save_string(self, s): self.stream.write(PY2STRING) self._write_byte_sequence(s) + def save_unicode(self, s): + self.stream.write(UNICODE) + self._write_unicode_string(s) + dispatch[unicode] = save_unicode + dispatch[str] = save_string + def _write_unicode_string(self, s): try: as_bytes = s.encode("utf-8") @@ -113,6 +114,7 @@ class Serializer(object): def save_int(self, i): self.stream.write(INT) self._write_int4(i) + dispatch[int] = save_int def _write_int4(self, i, error="int must be less than %i" % (FOUR_BYTE_INT_MAX,)): @@ -125,6 +127,7 @@ class Serializer(object): self._write_int4(len(L), "list is too long") for i, item in enumerate(L): self._write_setitem(i, item) + dispatch[list] = save_list def _write_setitem(self, key, value): self._save(key) @@ -135,12 +138,14 @@ class Serializer(object): self.stream.write(NEWDICT) for key, value in d.items(): self._write_setitem(key, value) + dispatch[dict] = save_dict def save_tuple(self, tup): for item in tup: self._save(item) self.stream.write(BUILDTUPLE) self._write_int4(len(tup), "tuple is too long") + dispatch[tuple] = save_tuple class _UnserializationOptions(object): @@ -156,35 +161,10 @@ class _Py3UnserializationOptions(_Unseri def __init__(self, py2_strings_as_str=False): self.py2_strings_as_str = py2_strings_as_str - -_unchanging_dispatch = {} -for tp in (dict, list, tuple, int): - name = "save_%s" % (tp.__name__,) - _unchanging_dispatch[tp] = getattr(Serializer, name) -del tp, name - -def _setup_dispatch(): - dispatch = _unchanging_dispatch.copy() - # This is sutble. bytes is aliased to str in 2.6, so - # dispatch[bytes] is overwritten. Additionally, we alias unicode - # to str in 3.x, so dispatch[unicode] is overwritten with - # save_string. - dispatch[bytes] = Serializer.save_bytes - dispatch[unicode] = Serializer.save_unicode - dispatch[str] = Serializer.save_string - Serializer.dispatch = dispatch - -def _setup_version_dependent_constants(leave_unicode_alone=False): - global unicode, UnserializationOptions - if _INPY3: - unicode = str - UnserializationOptions = _Py3UnserializationOptions - else: - UnserializationOptions = _Py2UnserializationOptions - unicode = _unicode - _setup_dispatch() -_setup_version_dependent_constants() - +if _INPY3: + UnserializationOptions = _Py3UnserializationOptions +else: + UnserializationOptions = _Py2UnserializationOptions class _Stop(Exception): pass @@ -236,7 +216,7 @@ class Unserializer(object): def load_py3string(self): as_bytes = self._read_byte_string() - if (not _INPY3 and self.options.py3_strings_as_str) and not _REALLY_PY3: + if not _INPY3 and self.options.py3_strings_as_str: # XXX Should we try to decode into latin-1? self.stack.append(as_bytes) else: @@ -245,8 +225,7 @@ class Unserializer(object): def load_py2string(self): as_bytes = self._read_byte_string() - if (_INPY3 and self.options.py2_strings_as_str) or \ - (_REALLY_PY3 and not _INPY3): + if _INPY3 and self.options.py2_strings_as_str: s = as_bytes.decode("latin-1") else: s = as_bytes @@ -254,7 +233,7 @@ class Unserializer(object): opcodes[PY2STRING] = load_py2string def load_bytes(self): - s = bytes(self._read_byte_string()) + s = self._read_byte_string() self.stack.append(s) opcodes[BYTES] = load_bytes From commits-noreply at bitbucket.org Sun Sep 27 01:11:20 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 26 Sep 2009 23:11:20 +0000 (UTC) Subject: [py-svn] py-trunk commit 24c4fa1656bc: use default argument Message-ID: <20090926231120.DB5EF71127@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1253992896 18000 # Node ID 24c4fa1656bc03dbd51841bc803d02526afeb758 # Parent 1cba43c6180ca40ecc6315d8805a4b4714931a69 use default argument --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -165,10 +165,8 @@ class _Stop(Exception): class Unserializer(object): - def __init__(self, stream, options=None): + def __init__(self, stream, options=UnserializationOptions()): self.stream = stream - if options is None: - options = UnserializationOptions() self.options = options def load(self): From commits-noreply at bitbucket.org Sun Sep 27 01:11:22 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 26 Sep 2009 23:11:22 +0000 (UTC) Subject: [py-svn] py-trunk commit f6e6462f2f95: don't need to import py Message-ID: <20090926231122.EB2BE71129@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1253992921 18000 # Node ID f6e6462f2f95abdeab1d83729feb736635743bf0 # Parent 24c4fa1656bc03dbd51841bc803d02526afeb758 don't need to import py --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -5,8 +5,6 @@ Simple marshal format (based on pickle) import sys import struct -import py - _INPY3 = _REALLY_PY3 = sys.version_info > (3, 0) class SerializeError(Exception): From commits-noreply at bitbucket.org Sun Sep 27 01:11:19 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 26 Sep 2009 23:11:19 +0000 (UTC) Subject: [py-svn] py-trunk commit 1cba43c6180c: clean up unused compatibility code Message-ID: <20090926231119.192D671126@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1253992836 18000 # Node ID 1cba43c6180ca40ecc6315d8805a4b4714931a69 # Parent f4aa7209a3eb719349aa971ac242b29e4ae80134 clean up unused compatibility code --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -30,14 +30,8 @@ class Corruption(UnserializationError): if _INPY3: def b(s): return s.encode("ascii") - _b = b - class _unicode(str): - pass - bytes = bytes else: b = str - _b = bytes - _unicode = unicode FOUR_BYTE_INT_MAX = 2147483647 From commits-noreply at bitbucket.org Sun Sep 27 01:25:46 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Sat, 26 Sep 2009 23:25:46 +0000 (UTC) Subject: [py-svn] py-trunk commit 4d6f55850786: support floats Message-ID: <20090926232546.B3D1371126@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1254007592 18000 # Node ID 4d6f55850786cb0752e26efa3e7bd538b5090fe9 # Parent f6e6462f2f95abdeab1d83729feb736635743bf0 support floats --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -94,6 +94,14 @@ class TestSerializer: serializer.Serializer(py.io.BytesIO()).save, 123456678900) + def test_float(self, py2, py3): + for dump in py2.dump, py3.dump: + p = dump(3.25) + for load in py2.load, py3.load: + tp, v = load(p) + assert tp == "float" + assert v == "3.25" + def test_bytes(self, py2, py3): p = py3.dump("b'hi'") tp, v = py2.load(p) --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -34,6 +34,7 @@ else: FOUR_BYTE_INT_MAX = 2147483647 _int4_format = struct.Struct("!i") +_float_format = struct.Struct("!d") # Protocol constants VERSION_NUMBER = 1 @@ -47,6 +48,7 @@ BUILDTUPLE = b('T') SETITEM = b('m') NEWDICT = b('d') INT = b('i') +FLOAT = b('f') STOP = b('S') class CrossVersionOptions(object): @@ -108,6 +110,11 @@ class Serializer(object): self._write_int4(i) dispatch[int] = save_int + def save_float(self, flt): + self.stream.write(FLOAT) + self.stream.write(_float_format.pack(flt)) + dispatch[float] = save_float + def _write_int4(self, i, error="int must be less than %i" % (FOUR_BYTE_INT_MAX,)): if i > FOUR_BYTE_INT_MAX: @@ -196,6 +203,11 @@ class Unserializer(object): self.stack.append(i) opcodes[INT] = load_int + def load_float(self): + binary = self.stream.read(_float_format.size) + self.stack.append(_float_format.unpack(binary)[0]) + opcodes[FLOAT] = load_float + def _read_int4(self): return _int4_format.unpack(self.stream.read(4))[0] From commits-noreply at bitbucket.org Mon Sep 28 22:46:50 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:50 +0000 (UTC) Subject: [py-svn] py-virtualenv commit e4800830de56: applying doc fix from jarko Message-ID: <20090928204650.C3A34710B1@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User holger krekel # Date 1253728047 -7200 # Node ID e4800830de5691a30721886de745061a16c6469d # Parent 7c30db1d80df509b3287b019af3db5cdf14c7368 applying doc fix from jarko --- a/doc/test/quickstart.txt +++ /dev/null @@ -1,71 +0,0 @@ -.. _`setuptools installation`: http://pypi.python.org/pypi/setuptools - - -================== -Quickstart -================== - -.. _here: ../download.html#no-setuptools - - -With a `setuptools installation`_ (otherwise see here_) you can type:: - - easy_install -U py - -On Linux systems you may need to execute this as the superuser and -on Windows you might need to write down the full path to ``easy_install``. - -Now create a file ``test_sample.py`` with the following content: - -.. sourcecode:: python - - # content of test_sample.py - def func(x): - return x + 1 - def test_answer(): - assert f(3) == 5 - -You can now run the test file like this:: - - py.test test_sample.py - -and will see output like this: - -.. sourcecode:: python - - =========================== test session starts ============================ - python: platform linux2 -- Python 2.6.2 - test object 1: test_sample.py - - test_sample.py F - - ================================= FAILURES ================================= - _______________________________ test_answer ________________________________ - - def test_answer(): - > assert func(3) == 5 - E assert 4 == 5 - E + where 4 = func(3) - - test_sample.py:6: AssertionError - ========================= 1 failed in 0.08 seconds ========================= - -This output contains Python interpreter information, a list of test objects, -a progress report and important details of the failure. - -**Where to go from here** - -`tutorials`_: a collection of starting points with code examples - -`features`_: overview and description of test features - -`contact`_: many ways for feedback and questions - -.. _`contact`: ../contact.html -.. _`automatically collected`: features.html#autocollect -.. _download: ../download.html -.. _features: features.html -.. _tutorials: talks.html - - - From commits-noreply at bitbucket.org Mon Sep 28 22:46:52 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:52 +0000 (UTC) Subject: [py-svn] py-virtualenv commit f4aa7209a3eb: test cross version serialization by launching subprocesses; much cleaner! Message-ID: <20090928204652.8DD4C710AF@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Benjamin Peterson # Date 1253986524 18000 # Node ID f4aa7209a3eb719349aa971ac242b29e4ae80134 # Parent 9facb0d433af6a8b1567eac0af7cd7ffcb85d806 test cross version serialization by launching subprocesses; much cleaner! --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -1,50 +1,78 @@ # -*- coding: utf-8 -*- -import shutil +import sys +import os +import tempfile +import subprocess import py from py.__.execnet import serializer + +def _find_version(suffix=""): + name = "python" + suffix + executable = py.path.local.sysfind(name) + if executable is None: + py.test.skip("can't find a %r executable" % (name,)) + return executable + def setup_module(mod): - mod._save_python3 = serializer._INPY3 + mod.TEMPDIR = py.path.local(tempfile.mkdtemp()) + if sys.version_info > (3, 0): + mod._py3_wrapper = PythonWrapper(py.path.local(sys.executable)) + mod._py2_wrapper = PythonWrapper(_find_version()) + else: + mod._py3_wrapper = PythonWrapper(_find_version("3")) + mod._py2_wrapper = PythonWrapper(py.path.local(sys.executable)) + mod._old_pypath = os.environ.get("PYTHONPATH") + pylib = str(py.path.local(py.__file__).dirpath().join("..")) + os.environ["PYTHONPATH"] = pylib def teardown_module(mod): - serializer._setup_version_dependent_constants() + TEMPDIR.remove(True) + if _old_pypath is not None: + os.environ["PYTHONPATH"] = _old_pypath -def _dump(obj): - stream = py.io.BytesIO() - saver = serializer.Serializer(stream) - saver.save(obj) - return stream.getvalue() -def _load(serialized, str_coerion): - stream = py.io.BytesIO(serialized) - opts = serializer.UnserializationOptions(str_coerion) - unserializer = serializer.Unserializer(stream, opts) - return unserializer.load() +class PythonWrapper(object): -def _run_in_version(is_py3, func, *args): - serializer._INPY3 = is_py3 - serializer._setup_version_dependent_constants() - try: - return func(*args) - finally: - serializer._INPY3 = _save_python3 + def __init__(self, executable): + self.executable = executable -def dump_py2(obj): - return _run_in_version(False, _dump, obj) + def dump(self, obj_rep): + script_file = TEMPDIR.join("dump.py") + script_file.write(""" +from py.__.execnet import serializer +import sys +if sys.version_info > (3, 0): # Need binary output + sys.stdout = sys.stdout.detach() +saver = serializer.Serializer(sys.stdout) +saver.save(%s)""" % (obj_rep,)) + return self.executable.sysexec(script_file) -def dump_py3(obj): - return _run_in_version(True, _dump, obj) + def load(self, data, option_args=""): + script_file = TEMPDIR.join("load.py") + script_file.write(r""" +from py.__.execnet import serializer +import sys +if sys.version_info > (3, 0): + sys.stdin = sys.stdin.detach() +options = serializer.UnserializationOptions(%s) +loader = serializer.Unserializer(sys.stdin, options) +obj = loader.load() +sys.stdout.write(type(obj).__name__ + "\n") +sys.stdout.write(repr(obj))""" % (option_args,)) + popen = subprocess.Popen([str(self.executable), str(script_file)], + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE) + stdout, stderr = popen.communicate(data.encode("latin-1")) + ret = popen.returncode + if ret: + raise py.process.cmdexec.Error(ret, ret, str(self.executable), + stdout, stderr) + return [s.decode("ascii") for s in stdout.splitlines()] -def load_py2(serialized, str_coercion=False): - return _run_in_version(False, _load, serialized, str_coercion) - -def load_py3(serialized, str_coercion=False): - return _run_in_version(True, _load, serialized, str_coercion) - -try: - bytes -except NameError: - bytes = str + def __repr__(self): + return "" % (self.executable,) def pytest_funcarg__py2(request): @@ -55,73 +83,86 @@ def pytest_funcarg__py3(request): class TestSerializer: - def test_int(self): - for dump in dump_py2, dump_py3: - p = dump_py2(4) - for load in load_py2, load_py3: - i = load(p) - assert isinstance(i, int) - assert i == 4 - py.test.raises(serializer.SerializationError, dump, 123456678900) + def test_int(self, py2, py3): + for dump in py2.dump, py3.dump: + p = dump(4) + for load in py2.load, py3.load: + tp, v = load(p) + assert tp == "int" + assert int(v) == 4 + py.test.raises(serializer.SerializationError, + serializer.Serializer(py.io.BytesIO()).save, + 123456678900) - def test_bytes(self): - for dump in dump_py2, dump_py3: - p = dump(serializer._b('hi')) - for load in load_py2, load_py3: - s = load(p) - assert isinstance(s, serializer.bytes) - assert s == serializer._b('hi') + def test_bytes(self, py2, py3): + p = py3.dump("b'hi'") + tp, v = py2.load(p) + assert tp == "str" + assert v == "'hi'" + tp, v = py3.load(p) + assert tp == "bytes" + assert v == "b'hi'" - def check_sequence(self, seq): - for dump in dump_py2, dump_py3: + def check_sequence(self, seq, tp_name, rep, py2, py3): + for dump in py2.dump, py3.dump: p = dump(seq) - for load in load_py2, load_py3: - l = load(p) - assert l == seq + for load in py2.load, py3.load: + tp, v = load(p) + assert tp == tp_name + assert v == rep - def test_list(self): - self.check_sequence([1, 2, 3]) + def test_list(self, py2, py3): + self.check_sequence([1, 2, 3], "list", "[1, 2, 3]", py2, py3) @py.test.mark.xfail # I'm not sure if we need the complexity. - def test_recursive_list(self): + def test_recursive_list(self, py2, py3): l = [1, 2, 3] l.append(l) - self.check_sequence(l) + p = py2.dump(l) + tp, rep = py2.load(l) + assert tp == "list" - def test_tuple(self): - self.check_sequence((1, 2, 3)) + def test_tuple(self, py2, py3): + self.check_sequence((1, 2, 3), "tuple", "(1, 2, 3)", py2, py3) - def test_dict(self): - for dump in dump_py2, dump_py3: - p = dump({"hi" : 2, (1, 2, 3) : 32}) - for load in load_py2, load_py3: - d = load(p, True) - assert d == {"hi" : 2, (1, 2, 3) : 32} + def test_dict(self, py2, py3): + for dump in py2.dump, py3.dump: + p = dump({6 : 2, (1, 2, 3) : 32}) + for load in py2.load, py3.load: + tp, v = load(p) + assert tp == "dict" + # XXX comparing dict reprs + assert v == "{6: 2, (1, 2, 3): 32}" - def test_string(self): - py.test.skip("will rewrite") - p = dump_py2("xyz") - s = load_py2(p) - assert isinstance(s, str) - assert s == "xyz" - s = load_py3(p) - assert isinstance(s, bytes) - assert s == serializer.b("xyz") - p = dump_py2("xyz") - s = load_py3(p, True) - assert isinstance(s, serializer._unicode) - assert s == serializer.unicode("xyz") - p = dump_py3("xyz") - s = load_py2(p, True) - assert isinstance(s, str) - assert s == "xyz" + def test_string(self, py2, py3): + p = py2.dump("'xyz'") + tp, s = py2.load(p) + assert tp == "str" + assert s == "'xyz'" + tp, s = py3.load(p) + assert tp == "bytes" + assert s == "b'xyz'" + tp, s = py3.load(p, "True") + assert tp == "str" + assert s == "'xyz'" + p = py3.dump("'xyz'") + tp, s = py2.load(p, True) + assert tp == "str" + assert s == "'xyz'" - def test_unicode(self): - py.test.skip("will rewrite") - for dump, uni in (dump_py2, serializer._unicode), (dump_py3, str): - p = dump(uni("xyz")) - for load in load_py2, load_py3: - s = load(p) - assert isinstance(s, serializer._unicode) - assert s == serializer._unicode("xyz") + def test_unicode(self, py2, py3): + p = py2.dump("u'hi'") + tp, s = py2.load(p) + assert tp == "unicode" + assert s == "u'hi'" + tp, s = py3.load(p) + assert tp == "str" + assert s == "'hi'" + p = py3.dump("'hi'") + tp, s = py3.load(p) + assert tp == "str" + assert s == "'hi'" + tp, s = py2.load(p) + assert tp == "unicode" + assert s == "u'hi'" --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -35,8 +35,6 @@ if _INPY3: pass bytes = bytes else: - class bytes(str): - pass b = str _b = bytes _unicode = unicode @@ -80,25 +78,28 @@ class Serializer(object): raise UnserializableType("can't serialize %s" % (tp,)) dispatch(self, obj) + dispatch = {} + def save_bytes(self, bytes_): self.stream.write(BYTES) self._write_byte_sequence(bytes_) + dispatch[bytes] = save_bytes - def save_unicode(self, s): - self.stream.write(UNICODE) - self._write_unicode_string(s) - - def save_string(self, s): - if _INPY3: + if _INPY3: + def save_string(self, s): self.stream.write(PY3STRING) self._write_unicode_string(s) - else: - # Case for tests - if _REALLY_PY3 and isinstance(s, str): - s = s.encode("latin-1") + else: + def save_string(self, s): self.stream.write(PY2STRING) self._write_byte_sequence(s) + def save_unicode(self, s): + self.stream.write(UNICODE) + self._write_unicode_string(s) + dispatch[unicode] = save_unicode + dispatch[str] = save_string + def _write_unicode_string(self, s): try: as_bytes = s.encode("utf-8") @@ -113,6 +114,7 @@ class Serializer(object): def save_int(self, i): self.stream.write(INT) self._write_int4(i) + dispatch[int] = save_int def _write_int4(self, i, error="int must be less than %i" % (FOUR_BYTE_INT_MAX,)): @@ -125,6 +127,7 @@ class Serializer(object): self._write_int4(len(L), "list is too long") for i, item in enumerate(L): self._write_setitem(i, item) + dispatch[list] = save_list def _write_setitem(self, key, value): self._save(key) @@ -135,12 +138,14 @@ class Serializer(object): self.stream.write(NEWDICT) for key, value in d.items(): self._write_setitem(key, value) + dispatch[dict] = save_dict def save_tuple(self, tup): for item in tup: self._save(item) self.stream.write(BUILDTUPLE) self._write_int4(len(tup), "tuple is too long") + dispatch[tuple] = save_tuple class _UnserializationOptions(object): @@ -156,35 +161,10 @@ class _Py3UnserializationOptions(_Unseri def __init__(self, py2_strings_as_str=False): self.py2_strings_as_str = py2_strings_as_str - -_unchanging_dispatch = {} -for tp in (dict, list, tuple, int): - name = "save_%s" % (tp.__name__,) - _unchanging_dispatch[tp] = getattr(Serializer, name) -del tp, name - -def _setup_dispatch(): - dispatch = _unchanging_dispatch.copy() - # This is sutble. bytes is aliased to str in 2.6, so - # dispatch[bytes] is overwritten. Additionally, we alias unicode - # to str in 3.x, so dispatch[unicode] is overwritten with - # save_string. - dispatch[bytes] = Serializer.save_bytes - dispatch[unicode] = Serializer.save_unicode - dispatch[str] = Serializer.save_string - Serializer.dispatch = dispatch - -def _setup_version_dependent_constants(leave_unicode_alone=False): - global unicode, UnserializationOptions - if _INPY3: - unicode = str - UnserializationOptions = _Py3UnserializationOptions - else: - UnserializationOptions = _Py2UnserializationOptions - unicode = _unicode - _setup_dispatch() -_setup_version_dependent_constants() - +if _INPY3: + UnserializationOptions = _Py3UnserializationOptions +else: + UnserializationOptions = _Py2UnserializationOptions class _Stop(Exception): pass @@ -236,7 +216,7 @@ class Unserializer(object): def load_py3string(self): as_bytes = self._read_byte_string() - if (not _INPY3 and self.options.py3_strings_as_str) and not _REALLY_PY3: + if not _INPY3 and self.options.py3_strings_as_str: # XXX Should we try to decode into latin-1? self.stack.append(as_bytes) else: @@ -245,8 +225,7 @@ class Unserializer(object): def load_py2string(self): as_bytes = self._read_byte_string() - if (_INPY3 and self.options.py2_strings_as_str) or \ - (_REALLY_PY3 and not _INPY3): + if _INPY3 and self.options.py2_strings_as_str: s = as_bytes.decode("latin-1") else: s = as_bytes @@ -254,7 +233,7 @@ class Unserializer(object): opcodes[PY2STRING] = load_py2string def load_bytes(self): - s = bytes(self._read_byte_string()) + s = self._read_byte_string() self.stack.append(s) opcodes[BYTES] = load_bytes From commits-noreply at bitbucket.org Mon Sep 28 22:46:54 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:54 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 1cba43c6180c: clean up unused compatibility code Message-ID: <20090928204654.AD1CD710B5@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Benjamin Peterson # Date 1253992836 18000 # Node ID 1cba43c6180ca40ecc6315d8805a4b4714931a69 # Parent f4aa7209a3eb719349aa971ac242b29e4ae80134 clean up unused compatibility code --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -30,14 +30,8 @@ class Corruption(UnserializationError): if _INPY3: def b(s): return s.encode("ascii") - _b = b - class _unicode(str): - pass - bytes = bytes else: b = str - _b = bytes - _unicode = unicode FOUR_BYTE_INT_MAX = 2147483647 From commits-noreply at bitbucket.org Mon Sep 28 22:46:59 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:59 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 917a59d062d5: visit() now returns paths in depth-first order. fixes issue #47 Message-ID: <20090928204659.A4BF771106@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User holger krekel # Date 1253639613 -7200 # Node ID 917a59d062d50efafe444327f2986d2d6eb5dcd7 # Parent 852bdd2c8a7825903dc7bdfa6e7befe900e25f5f visit() now returns paths in depth-first order. fixes issue #47 --- a/py/path/local.py +++ b/py/path/local.py @@ -334,12 +334,12 @@ class LocalPath(FSBase): assert self!=target copychunked(self, target) else: - target.ensure(dir=1) def rec(p): return p.check(link=0) for x in self.visit(rec=rec): relpath = x.relto(self) newx = target.join(relpath) + newx.dirpath().ensure(dir=1) if x.check(link=1): newx.mksymlinkto(x.readlink()) elif x.check(file=1): --- a/testing/path/test_local.py +++ b/testing/path/test_local.py @@ -198,6 +198,15 @@ class TestLocalPath(common.CommonFSTests l2 = tmpdir.join(newfilename) assert l2.read() == 'foo' + def test_visit_depth_first(self, tmpdir): + p1 = tmpdir.ensure("a","1") + p2 = tmpdir.ensure("b","2") + p3 = tmpdir.ensure("breadth") + l = list(tmpdir.visit(lambda x: x.check(file=1))) + assert l[0] == p1 + assert l[1] == p2 + assert l[2] == p3 + class TestExecutionOnWindows: disabled = py.std.sys.platform != 'win32' --- a/py/path/common.py +++ b/py/path/common.py @@ -278,20 +278,20 @@ newline will be removed from the end of if rec: if isinstance(rec, str): rec = fnmatch(fil) - elif not py.builtin.callable(rec): - rec = lambda x: True - reclist = [self] - while reclist: - current = reclist.pop(0) - try: - dirlist = current.listdir() - except ignore: - return - 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) + elif not hasattr(rec, '__call__'): + rec = None + try: + entries = self.listdir() + except ignore: + return + dirs = [p for p in entries + if p.check(dir=1) and (rec is None or rec(p))] + for subdir in dirs: + for p in subdir.visit(fil=fil, rec=rec, ignore=ignore): + yield p + for p in entries: + if fil is None or fil(p): + yield p def _sortlist(self, res, sort): if sort: From commits-noreply at bitbucket.org Mon Sep 28 22:46:59 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:59 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 852bdd2c8a78: * allowing arbitrary keys for xspecs but adding some sanity checks to xspec-parsing and makegateway. Message-ID: <20090928204659.8F87F71105@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User holger krekel # Date 1253637620 -7200 # Node ID 852bdd2c8a7825903dc7bdfa6e7befe900e25f5f # Parent c4b739c83e0ccf8ebc85b686735c5789e27c23ed * allowing arbitrary keys for xspecs but adding some sanity checks to xspec-parsing and makegateway. * fixing a python3 IO issue - we need to retain sys.stdout/stdin references to keep the underlying byte stream open. --- a/py/execnet/gateway_base.py +++ b/py/execnet/gateway_base.py @@ -119,10 +119,6 @@ sys.stdin = tempfile.TemporaryFile('r') def __init__(self, outfile, infile): # we need raw byte streams - if hasattr(infile, 'buffer'): - infile = infile.buffer - if hasattr(outfile, 'buffer'): - outfile = outfile.buffer self.outfile, self.infile = outfile, infile if sys.platform == "win32": import msvcrt @@ -132,7 +128,10 @@ sys.stdin = tempfile.TemporaryFile('r') def read(self, numbytes): """Read exactly 'numbytes' bytes from the pipe. """ - data = self.infile.read(numbytes) + try: + data = self.infile.buffer.read(numbytes) + except AttributeError: + data = self.infile.read(numbytes) if len(data) < numbytes: raise EOFError return data @@ -140,7 +139,10 @@ sys.stdin = tempfile.TemporaryFile('r') def write(self, data): """write out all data bytes. """ assert isinstance(data, bytes) - self.outfile.write(data) + try: + self.outfile.buffer.write(data) + except AttributeError: + self.outfile.write(data) self.outfile.flush() def close_read(self): --- a/py/execnet/gateway.py +++ b/py/execnet/gateway.py @@ -226,7 +226,7 @@ class PopenGateway(PopenCmdGateway): s = "\n".join([extra, "import sys ; sys.path[:0] = %r" % (plist,), "import os ; os.environ['PYTHONPATH'] = %r" % ppath, - str(py.code.Source(stdouterrin_setnull)), + inspect.getsource(stdouterrin_setnull), "stdouterrin_setnull()", "" ]) --- a/py/execnet/xspec.py +++ b/py/execnet/xspec.py @@ -22,11 +22,17 @@ class XSpec: key, value = keyvalue, True else: key, value = keyvalue[:i], keyvalue[i+1:] - # XXX be restrictive for now - if key not in XSpec.__dict__: + if key[0] == "_": raise AttributeError("%r not a valid XSpec key" % key) + if key in self.__dict__: + raise ValueError("duplicate key: %r in %r" %(key, string)) setattr(self, key, value) + def __getattr__(self, name): + if name[0] == "_": + raise AttributeError(name) + return None + def __repr__(self): return "" %(self._spec,) def __str__(self): @@ -39,11 +45,6 @@ class XSpec: def __ne__(self, other): return self._spec != getattr(other, '_spec', None) - #def __getattr__(self, name): - # if name[0] == "_": - # raise AttributeError(name) - # return None - def _samefilesystem(self): return bool(self.popen and not self.chdir) @@ -58,6 +59,8 @@ def makegateway(spec): assert not spec.python, "socket: specifying python executables not supported" hostport = spec.socket.split(":") gw = py.execnet.SocketGateway(*hostport) + else: + raise ValueError("no gateway type found for %r" % (spec._spec,)) gw.spec = spec if spec.chdir or spec.nice: channel = gw.remote_exec(""" --- a/testing/execnet/test_xspec.py +++ b/testing/execnet/test_xspec.py @@ -9,7 +9,7 @@ class TestXSpec: assert spec.python == "c:/this/python2.5" assert spec.chdir == "d:\hello" assert spec.nice is None - assert not hasattr(spec, 'xyz') + assert not hasattr(spec, '_xyz') py.test.raises(AttributeError, "spec._hello") @@ -36,6 +36,14 @@ class TestXSpec: for x in ("popen", "popen//python=this"): assert XSpec(x)._spec == x + def test_samekeyword_twice_raises(self): + py.test.raises(ValueError, "XSpec('popen//popen')") + py.test.raises(ValueError, "XSpec('popen//popen=123')") + + def test_unknown_keys_allowed(self): + xspec = XSpec("hello=3") + assert xspec.hello == '3' + def test_repr_and_string(self): for x in ("popen", "popen//python=this"): assert repr(XSpec(x)).find("popen") != -1 @@ -48,6 +56,9 @@ class TestXSpec: assert hash(XSpec("socket=hello:8080")) != hash(XSpec("popen")) class TestMakegateway: + def test_no_type(self): + py.test.raises(ValueError, "py.execnet.makegateway('hello')") + def test_popen(self): gw = py.execnet.makegateway("popen") assert gw.spec.python == None @@ -76,20 +87,20 @@ class TestMakegateway: assert rinfo.cwd == py.std.os.getcwd() assert rinfo.version_info == py.std.sys.version_info - def test_popen_cpython24(self): - for trypath in ('python2.4', r'C:\Python24\python.exe'): - cpython24 = py.path.local.sysfind(trypath) - if cpython24 is not None: - cpython24 = cpython24.realpath() + def test_popen_cpython25(self): + for trypath in ('python2.5', r'C:\Python25\python.exe'): + cpython25 = py.path.local.sysfind(trypath) + if cpython25 is not None: + cpython25 = cpython25.realpath() break else: - py.test.skip("cpython2.4 not found") - gw = py.execnet.makegateway("popen//python=%s" % cpython24) + py.test.skip("cpython2.5 not found") + gw = py.execnet.makegateway("popen//python=%s" % cpython25) rinfo = gw._rinfo() if py.std.sys.platform != "darwin": # it's confusing there - assert rinfo.executable == cpython24 + assert rinfo.executable == cpython25 assert rinfo.cwd == py.std.os.getcwd() - assert rinfo.version_info[:2] == (2,4) + assert rinfo.version_info[:2] == (2,5) def test_popen_cpython26(self): for trypath in ('python2.6', r'C:\Python26\python.exe'): From commits-noreply at bitbucket.org Mon Sep 28 22:46:59 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:59 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 742f38d8eb11: allow a path to explicity given for py.lookup Message-ID: <20090928204659.B3E2271107@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Benjamin Peterson # Date 1253671465 18000 # Node ID 742f38d8eb11e1f32183b15f2de7c2997cd0ff9e # Parent 917a59d062d50efafe444327f2986d2d6eb5dcd7 allow a path to explicity given for py.lookup --- a/testing/cmdline/test_cmdline.py +++ b/testing/cmdline/test_cmdline.py @@ -15,4 +15,14 @@ class TestPyLookup: result.stdout.fnmatch_lines( ['*%s:*' %(p.basename)] ) - + + def test_with_explicit_path(self, testxbdir): + sub1 = testdir.mkdir("things") + sub2 = testdir.mkdir("foo") + sub1.join("pyfile.py").write("def stuff(): pass") + searched = sub2.join("other.py") + searched.write("stuff = x") + result = testdir.runpybin("py.lookup", sub2.basename, "stuff") + result.stdout.fnmatch_lines( + ["%s:1: stuff = x" % (searched.basename,)] + ) --- a/py/cmdline/pylookup.py +++ b/py/cmdline/pylookup.py @@ -12,7 +12,6 @@ import py from py.__.io.terminalwriter import ansi_print, terminal_width import re -curdir = py.path.local() def rec(p): return p.check(dotfile=0) @@ -35,12 +34,17 @@ def find_indexes(search_line, string): def main(): (options, args) = parser.parse_args() - string = args[0] + if len(args) == 2: + search_dir, string = args + search_dir = py.path.local(search_dir) + else: + search_dir = py.path.local() + string = args[0] if options.ignorecase: string = string.lower() - for x in curdir.visit('*.py', rec): + for x in search_dir.visit('*.py', rec): # match filename directly - s = x.relto(curdir) + s = x.relto(search_dir) if options.ignorecase: s = s.lower() if s.find(string) != -1: @@ -64,7 +68,7 @@ def main(): if not indexes: continue if not options.context: - sys.stdout.write("%s:%d: " %(x.relto(curdir), i+1)) + sys.stdout.write("%s:%d: " %(x.relto(search_dir), i+1)) last_index = 0 for index in indexes: sys.stdout.write(line[last_index: index]) @@ -75,5 +79,5 @@ def main(): else: context = (options.context)/2 for count in range(max(0, i-context), min(len(lines) - 1, i+context+1)): - print("%s:%d: %s" %(x.relto(curdir), count+1, lines[count].rstrip())) + print("%s:%d: %s" %(x.relto(search_dir), count+1, lines[count].rstrip())) print("-" * terminal_width) From commits-noreply at bitbucket.org Mon Sep 28 22:47:03 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:47:03 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 3369fee9b19e: update docstring Message-ID: <20090928204703.A2E497110D@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Benjamin Peterson # Date 1253671670 18000 # Node ID 3369fee9b19e8f1ccf2d5daf60ce046280698bd0 # Parent ff0c24f55bb2205ae999fc8d462c6fd73a391f33 update docstring --- a/py/cmdline/pylookup.py +++ b/py/cmdline/pylookup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """\ -py.lookup SEARCH_STRING [options] +py.lookup [search_directory] SEARCH_STRING [options] Looks recursively at Python files for a SEARCH_STRING, starting from the present working directory. Prints the line, with the filename and line-number From commits-noreply at bitbucket.org Mon Sep 28 22:47:03 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:47:03 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 5e999fa934c1: Fixed a typo in error.py causing it to fail on Windows. Message-ID: <20090928204703.BD4B571112@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Jurko # Date 1252707373 -7200 # Node ID 5e999fa934c130c004da74a9ec54ae6e9b20d579 # Parent 71a55baebef055c44c2837a8ae6166905227618a Fixed a typo in error.py causing it to fail on Windows. --- a/py/error.py +++ b/py/error.py @@ -74,7 +74,7 @@ class ErrorMaker(object): cls = self._geterrnoclass(errno) else: try: - cls = self._geterrnoclass(_winerrnomap[eno]) + cls = self._geterrnoclass(_winerrnomap[errno]) except KeyError: raise value raise cls("%s%r" % (func.__name__, args)) From commits-noreply at bitbucket.org Mon Sep 28 22:47:03 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:47:03 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 7eb914ccf56c: Corrected the constructed system path value (broken by the env.cmd, env.sh & env.py file move in 4abc620bb044). Message-ID: <20090928204703.C890571114@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Jurko # Date 1252708557 -7200 # Node ID 7eb914ccf56cccecfc6b3f28e726b2426442375e # Parent 5e999fa934c130c004da74a9ec54ae6e9b20d579 Corrected the constructed system path value (broken by the env.cmd, env.sh & env.py file move in 4abc620bb044). --- a/py/bin/env.py +++ b/py/bin/env.py @@ -3,7 +3,7 @@ import sys, os, os.path progpath = sys.argv[0] -packagedir = os.path.abspath(os.path.dirname(progpath)) +packagedir = os.path.dirname(os.path.dirname(os.path.abspath(progpath))) packagename = os.path.basename(packagedir) bindir = os.path.join(packagedir, 'bin') if sys.platform == 'win32': From commits-noreply at bitbucket.org Mon Sep 28 22:46:56 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:56 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 24c4fa1656bc: use default argument Message-ID: <20090928204656.D0EB0710BA@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Benjamin Peterson # Date 1253992896 18000 # Node ID 24c4fa1656bc03dbd51841bc803d02526afeb758 # Parent 1cba43c6180ca40ecc6315d8805a4b4714931a69 use default argument --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -165,10 +165,8 @@ class _Stop(Exception): class Unserializer(object): - def __init__(self, stream, options=None): + def __init__(self, stream, options=UnserializationOptions()): self.stream = stream - if options is None: - options = UnserializationOptions() self.options = options def load(self): From commits-noreply at bitbucket.org Mon Sep 28 22:46:58 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:58 +0000 (UTC) Subject: [py-svn] py-virtualenv commit f6e6462f2f95: don't need to import py Message-ID: <20090928204658.F2983710FB@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Benjamin Peterson # Date 1253992921 18000 # Node ID f6e6462f2f95abdeab1d83729feb736635743bf0 # Parent 24c4fa1656bc03dbd51841bc803d02526afeb758 don't need to import py --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -5,8 +5,6 @@ Simple marshal format (based on pickle) import sys import struct -import py - _INPY3 = _REALLY_PY3 = sys.version_info > (3, 0) class SerializeError(Exception): From commits-noreply at bitbucket.org Mon Sep 28 22:46:59 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:59 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 4d6f55850786: support floats Message-ID: <20090928204659.5C622710FD@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Benjamin Peterson # Date 1254007592 18000 # Node ID 4d6f55850786cb0752e26efa3e7bd538b5090fe9 # Parent f6e6462f2f95abdeab1d83729feb736635743bf0 support floats --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -94,6 +94,14 @@ class TestSerializer: serializer.Serializer(py.io.BytesIO()).save, 123456678900) + def test_float(self, py2, py3): + for dump in py2.dump, py3.dump: + p = dump(3.25) + for load in py2.load, py3.load: + tp, v = load(p) + assert tp == "float" + assert v == "3.25" + def test_bytes(self, py2, py3): p = py3.dump("b'hi'") tp, v = py2.load(p) --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -34,6 +34,7 @@ else: FOUR_BYTE_INT_MAX = 2147483647 _int4_format = struct.Struct("!i") +_float_format = struct.Struct("!d") # Protocol constants VERSION_NUMBER = 1 @@ -47,6 +48,7 @@ BUILDTUPLE = b('T') SETITEM = b('m') NEWDICT = b('d') INT = b('i') +FLOAT = b('f') STOP = b('S') class CrossVersionOptions(object): @@ -108,6 +110,11 @@ class Serializer(object): self._write_int4(i) dispatch[int] = save_int + def save_float(self, flt): + self.stream.write(FLOAT) + self.stream.write(_float_format.pack(flt)) + dispatch[float] = save_float + def _write_int4(self, i, error="int must be less than %i" % (FOUR_BYTE_INT_MAX,)): if i > FOUR_BYTE_INT_MAX: @@ -196,6 +203,11 @@ class Unserializer(object): self.stack.append(i) opcodes[INT] = load_int + def load_float(self): + binary = self.stream.read(_float_format.size) + self.stack.append(_float_format.unpack(binary)[0]) + opcodes[FLOAT] = load_float + def _read_int4(self): return _int4_format.unpack(self.stream.read(4))[0] From commits-noreply at bitbucket.org Mon Sep 28 22:46:59 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:59 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 40fab66c01bc: add separate test for the serializer bigint fail Message-ID: <20090928204659.698EE710FE@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Ronny Pfannschmidt # Date 1254170556 -7200 # Node ID 40fab66c01bc2bc379e24168a02be62f55e5c2d4 # Parent 4d6f55850786cb0752e26efa3e7bd538b5090fe9 add separate test for the serializer bigint fail --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -90,6 +90,8 @@ class TestSerializer: tp, v = load(p) assert tp == "int" assert int(v) == 4 + + def test_bigint_should_fail(self): py.test.raises(serializer.SerializationError, serializer.Serializer(py.io.BytesIO()).save, 123456678900) From commits-noreply at bitbucket.org Mon Sep 28 22:46:59 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:59 +0000 (UTC) Subject: [py-svn] py-virtualenv commit c4b739c83e0c: (micke, pedronis) Message-ID: <20090928204659.81A7B71104@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Samuele Pedroni # Date 1253194295 -7200 # Node ID c4b739c83e0ccf8ebc85b686735c5789e27c23ed # Parent 9928a903e699748fc463bef0b36f64426df698d3 (micke, pedronis) teach the resultlog plugin about the xfail tweaked outcomes --- a/testing/pytest/plugin/test_pytest_resultlog.py +++ b/testing/pytest/plugin/test_pytest_resultlog.py @@ -24,7 +24,7 @@ def test_generic_path(): assert res == 'test/a:B().c[1]' def test_write_log_entry(): - reslog = ResultLog(None) + reslog = ResultLog(None, None) reslog.logfile = py.io.TextIO() reslog.write_log_entry('name', '.', '') entry = reslog.logfile.getvalue() @@ -100,7 +100,13 @@ class TestWithFunctionIntegration: import py def test_pass(): pass def test_skip(): py.test.skip("hello") - def test_fail(): raise ValueError("val") + def test_fail(): raise ValueError("FAIL") + + @py.test.mark.xfail + def test_xfail(): raise ValueError("XFAIL") + @py.test.mark.xfail + def test_xpass(): pass + """) lines = self.getresultlog(testdir, mod) assert len(lines) >= 3 @@ -112,8 +118,15 @@ class TestWithFunctionIntegration: assert lines[3].startswith("F ") assert lines[3].endswith("test_fail") - tb = "".join(lines[4:]) - assert tb.find("ValueError") != -1 + tb = "".join(lines[4:8]) + assert tb.find('raise ValueError("FAIL")') != -1 + + assert lines[8].startswith('x ') + tb = "".join(lines[8:14]) + assert tb.find('raise ValueError("XFAIL")') != -1 + + assert lines[14].startswith('P ') + assert len(lines) == 15 def test_internal_exception(self): # they are produced for example by a teardown failing @@ -122,7 +135,7 @@ class TestWithFunctionIntegration: raise ValueError except ValueError: excinfo = py.code.ExceptionInfo() - reslog = ResultLog(py.io.TextIO()) + reslog = ResultLog(None, py.io.TextIO()) reslog.pytest_internalerror(excinfo.getrepr()) entry = reslog.logfile.getvalue() entry_lines = entry.splitlines() @@ -142,12 +155,16 @@ def test_generic(testdir, LineMatcher): assert 0 def test_skip(): py.test.skip("") + @py.test.mark.xfail + def test_xfail(): + assert 0 """) testdir.runpytest("--resultlog=result.log") lines = testdir.tmpdir.join("result.log").readlines(cr=0) LineMatcher(lines).fnmatch_lines([ ". *:test_pass", "F *:test_fail", - "s *:test_skip", + "s *:test_skip", + "x *:test_xfail", ]) --- a/py/test/plugin/pytest_resultlog.py +++ b/py/test/plugin/pytest_resultlog.py @@ -14,7 +14,7 @@ def pytest_configure(config): resultlog = config.option.resultlog if resultlog: logfile = open(resultlog, 'w', 1) # line buffered - config._resultlog = ResultLog(logfile) + config._resultlog = ResultLog(config, logfile) config.pluginmanager.register(config._resultlog) def pytest_unconfigure(config): @@ -48,7 +48,8 @@ def generic_path(item): return ''.join(gpath) class ResultLog(object): - def __init__(self, logfile): + def __init__(self, config, logfile): + self.config = config self.logfile = logfile # preferably line buffered def write_log_entry(self, testpath, shortrepr, longrepr): @@ -61,8 +62,16 @@ class ResultLog(object): self.write_log_entry(testpath, shortrepr, longrepr) def pytest_runtest_logreport(self, report): - code = report.shortrepr - if report.passed: + res = self.config.hook.pytest_report_teststatus(report=report) + if res is not None: + code = res[1] + else: + code = report.shortrepr + if code == 'x': + longrepr = str(report.longrepr) + elif code == 'P': + longrepr = '' + elif report.passed: longrepr = "" elif report.failed: longrepr = str(report.longrepr) From commits-noreply at bitbucket.org Mon Sep 28 22:46:59 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:46:59 +0000 (UTC) Subject: [py-svn] py-virtualenv commit b9b44ad50490: enhance the serializer tests Message-ID: <20090928204659.74D5F710FF@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Ronny Pfannschmidt # Date 1254170792 -7200 # Node ID b9b44ad50490d3f87546ab6124ed0dd7cf42d75f # Parent 40fab66c01bc2bc379e24168a02be62f55e5c2d4 enhance the serializer tests * use generate_tests hook to generate the serialize deserialize combinations * add dump/load funcargs to simplify the tests --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -81,28 +81,40 @@ def pytest_funcarg__py2(request): def pytest_funcarg__py3(request): return _py3_wrapper +def pytest_funcarg__dump(request): + py_dump = request.getfuncargvalue(request.param[0]) + return py_dump.dump + +def pytest_funcarg__load(request): + py_dump = request.getfuncargvalue(request.param[1]) + return py_dump.load + +def pytest_generate_tests(metafunc): + if 'dump' in metafunc.funcargnames and 'load' in metafunc.funcargnames: + pys = 'py2', 'py3' + for dump in pys: + for load in pys: + metafunc.addcall(id='%s to %s'%(dump, load), param=(dump, load)) + + class TestSerializer: - def test_int(self, py2, py3): - for dump in py2.dump, py3.dump: - p = dump(4) - for load in py2.load, py3.load: - tp, v = load(p) - assert tp == "int" - assert int(v) == 4 + def test_int(self, dump, load): + p = dump(4) + tp, v = load(p) + assert tp == "int" + assert int(v) == 4 def test_bigint_should_fail(self): py.test.raises(serializer.SerializationError, serializer.Serializer(py.io.BytesIO()).save, 123456678900) - def test_float(self, py2, py3): - for dump in py2.dump, py3.dump: - p = dump(3.25) - for load in py2.load, py3.load: - tp, v = load(p) - assert tp == "float" - assert v == "3.25" + def test_float(self, dump, load): + p = dump(3.25) + tp, v = load(p) + assert tp == "float" + assert v == "3.25" def test_bytes(self, py2, py3): p = py3.dump("b'hi'") @@ -113,16 +125,15 @@ class TestSerializer: assert tp == "bytes" assert v == "b'hi'" - def check_sequence(self, seq, tp_name, rep, py2, py3): - for dump in py2.dump, py3.dump: - p = dump(seq) - for load in py2.load, py3.load: - tp, v = load(p) - assert tp == tp_name - assert v == rep + def check(self, val, tp_name, rep, dump, load): + p = dump(val) + tp , v = load(p) + assert tp == tp_name + assert v == rep - def test_list(self, py2, py3): - self.check_sequence([1, 2, 3], "list", "[1, 2, 3]", py2, py3) + + def test_list(self, dump, load): + self.check([1, 2, 3], "list", "[1, 2, 3]", dump, load) @py.test.mark.xfail # I'm not sure if we need the complexity. @@ -133,17 +144,15 @@ class TestSerializer: tp, rep = py2.load(l) assert tp == "list" - def test_tuple(self, py2, py3): - self.check_sequence((1, 2, 3), "tuple", "(1, 2, 3)", py2, py3) + def test_tuple(self, dump, load): + self.check((1, 2, 3), "tuple", "(1, 2, 3)", dump, load) - def test_dict(self, py2, py3): - for dump in py2.dump, py3.dump: - p = dump({6 : 2, (1, 2, 3) : 32}) - for load in py2.load, py3.load: - tp, v = load(p) - assert tp == "dict" - # XXX comparing dict reprs - assert v == "{6: 2, (1, 2, 3): 32}" + def test_dict(self, dump, load): + p = dump({6 : 2, (1, 2, 3) : 32}) + tp, v = load(p) + assert tp == "dict" + # XXX comparing dict reprs + assert v == "{6: 2, (1, 2, 3): 32}" def test_string(self, py2, py3): p = py2.dump("'xyz'") From commits-noreply at bitbucket.org Mon Sep 28 22:47:01 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:47:01 +0000 (UTC) Subject: [py-svn] py-virtualenv commit ff0c24f55bb2: add changelog entry for last commit Message-ID: <20090928204701.A444671108@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Benjamin Peterson # Date 1253671627 18000 # Node ID ff0c24f55bb2205ae999fc8d462c6fd73a391f33 # Parent 742f38d8eb11e1f32183b15f2de7c2997cd0ff9e add changelog entry for last commit --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,6 +1,8 @@ Changes between 1.0.x and 'trunk' ===================================== +* add the ability to specify a path for py.lookup to search in + * fix a funcarg cached_setup bug probably only occuring in distributed testing and "module" scope with teardown. From commits-noreply at bitbucket.org Mon Sep 28 22:47:03 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:47:03 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 31b6c51fab40: Add a simple (hopefully) cross-python marshaller Message-ID: <20090928204703.B2F957110F@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Benjamin Peterson # Date 1253671720 18000 # Node ID 31b6c51fab40ba0798c2726d799d3a3f631a2ef0 # Parent 3369fee9b19e8f1ccf2d5daf60ce046280698bd0 Add a simple (hopefully) cross-python marshaller Will rewrite the tests soon... --- /dev/null +++ b/testing/execnet/test_serializer.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +import shutil +import py +from py.__.execnet import serializer + +def setup_module(mod): + mod._save_python3 = serializer._INPY3 + +def teardown_module(mod): + serializer._setup_version_dependent_constants() + +def _dump(obj): + stream = py.io.BytesIO() + saver = serializer.Serializer(stream) + saver.save(obj) + return stream.getvalue() + +def _load(serialized, str_coerion): + stream = py.io.BytesIO(serialized) + opts = serializer.UnserializationOptions(str_coerion) + unserializer = serializer.Unserializer(stream, opts) + return unserializer.load() + +def _run_in_version(is_py3, func, *args): + serializer._INPY3 = is_py3 + serializer._setup_version_dependent_constants() + try: + return func(*args) + finally: + serializer._INPY3 = _save_python3 + +def dump_py2(obj): + return _run_in_version(False, _dump, obj) + +def dump_py3(obj): + return _run_in_version(True, _dump, obj) + +def load_py2(serialized, str_coercion=False): + return _run_in_version(False, _load, serialized, str_coercion) + +def load_py3(serialized, str_coercion=False): + return _run_in_version(True, _load, serialized, str_coercion) + +try: + bytes +except NameError: + bytes = str + + +def pytest_funcarg__py2(request): + return _py2_wrapper + +def pytest_funcarg__py3(request): + return _py3_wrapper + +class TestSerializer: + + def test_int(self): + for dump in dump_py2, dump_py3: + p = dump_py2(4) + for load in load_py2, load_py3: + i = load(p) + assert isinstance(i, int) + assert i == 4 + py.test.raises(serializer.SerializationError, dump, 123456678900) + + def test_bytes(self): + for dump in dump_py2, dump_py3: + p = dump(serializer._b('hi')) + for load in load_py2, load_py3: + s = load(p) + assert isinstance(s, serializer.bytes) + assert s == serializer._b('hi') + + def check_sequence(self, seq): + for dump in dump_py2, dump_py3: + p = dump(seq) + for load in load_py2, load_py3: + l = load(p) + assert l == seq + + def test_list(self): + self.check_sequence([1, 2, 3]) + + @py.test.mark.xfail + # I'm not sure if we need the complexity. + def test_recursive_list(self): + l = [1, 2, 3] + l.append(l) + self.check_sequence(l) + + def test_tuple(self): + self.check_sequence((1, 2, 3)) + + def test_dict(self): + for dump in dump_py2, dump_py3: + p = dump({"hi" : 2, (1, 2, 3) : 32}) + for load in load_py2, load_py3: + d = load(p, True) + assert d == {"hi" : 2, (1, 2, 3) : 32} + + def test_string(self): + py.test.skip("will rewrite") + p = dump_py2("xyz") + s = load_py2(p) + assert isinstance(s, str) + assert s == "xyz" + s = load_py3(p) + assert isinstance(s, bytes) + assert s == serializer.b("xyz") + p = dump_py2("xyz") + s = load_py3(p, True) + assert isinstance(s, serializer._unicode) + assert s == serializer.unicode("xyz") + p = dump_py3("xyz") + s = load_py2(p, True) + assert isinstance(s, str) + assert s == "xyz" + + def test_unicode(self): + py.test.skip("will rewrite") + for dump, uni in (dump_py2, serializer._unicode), (dump_py3, str): + p = dump(uni("xyz")) + for load in load_py2, load_py3: + s = load(p) + assert isinstance(s, serializer._unicode) + assert s == serializer._unicode("xyz") --- /dev/null +++ b/py/execnet/serializer.py @@ -0,0 +1,291 @@ +""" +Simple marshal format (based on pickle) designed to work across Python versions. +""" + +import sys +import struct + +import py + +_INPY3 = _REALLY_PY3 = sys.version_info > (3, 0) + +class SerializeError(Exception): + pass + +class SerializationError(SerializeError): + """Error while serializing an object.""" + +class UnserializableType(SerializationError): + """Can't serialize a type.""" + +class UnserializationError(SerializeError): + """Error while unserializing an object.""" + +class VersionMismatch(UnserializationError): + """Data from a previous or later format.""" + +class Corruption(UnserializationError): + """The pickle format appears to have been corrupted.""" + +if _INPY3: + def b(s): + return s.encode("ascii") + _b = b + class _unicode(str): + pass + bytes = bytes +else: + class bytes(str): + pass + b = str + _b = bytes + _unicode = unicode + +FOUR_BYTE_INT_MAX = 2147483647 + +_int4_format = struct.Struct("!i") + +# Protocol constants +VERSION_NUMBER = 1 +VERSION = b(chr(VERSION_NUMBER)) +PY2STRING = b('s') +PY3STRING = b('t') +UNICODE = b('u') +BYTES = b('b') +NEWLIST = b('l') +BUILDTUPLE = b('T') +SETITEM = b('m') +NEWDICT = b('d') +INT = b('i') +STOP = b('S') + +class CrossVersionOptions(object): + pass + +class Serializer(object): + + def __init__(self, stream): + self.stream = stream + + def save(self, obj): + self.stream.write(VERSION) + self._save(obj) + self.stream.write(STOP) + + def _save(self, obj): + tp = type(obj) + try: + dispatch = self.dispatch[tp] + except KeyError: + raise UnserializableType("can't serialize %s" % (tp,)) + dispatch(self, obj) + + def save_bytes(self, bytes_): + self.stream.write(BYTES) + self._write_byte_sequence(bytes_) + + def save_unicode(self, s): + self.stream.write(UNICODE) + self._write_unicode_string(s) + + def save_string(self, s): + if _INPY3: + self.stream.write(PY3STRING) + self._write_unicode_string(s) + else: + # Case for tests + if _REALLY_PY3 and isinstance(s, str): + s = s.encode("latin-1") + self.stream.write(PY2STRING) + self._write_byte_sequence(s) + + def _write_unicode_string(self, s): + try: + as_bytes = s.encode("utf-8") + except UnicodeEncodeError: + raise SerializationError("strings must be utf-8 encodable") + self._write_byte_sequence(as_bytes) + + def _write_byte_sequence(self, bytes_): + self._write_int4(len(bytes_), "string is too long") + self.stream.write(bytes_) + + def save_int(self, i): + self.stream.write(INT) + self._write_int4(i) + + def _write_int4(self, i, error="int must be less than %i" % + (FOUR_BYTE_INT_MAX,)): + if i > FOUR_BYTE_INT_MAX: + raise SerializationError(error) + self.stream.write(_int4_format.pack(i)) + + def save_list(self, L): + self.stream.write(NEWLIST) + self._write_int4(len(L), "list is too long") + for i, item in enumerate(L): + self._write_setitem(i, item) + + def _write_setitem(self, key, value): + self._save(key) + self._save(value) + self.stream.write(SETITEM) + + def save_dict(self, d): + self.stream.write(NEWDICT) + for key, value in d.items(): + self._write_setitem(key, value) + + def save_tuple(self, tup): + for item in tup: + self._save(item) + self.stream.write(BUILDTUPLE) + self._write_int4(len(tup), "tuple is too long") + + +class _UnserializationOptions(object): + pass + +class _Py2UnserializationOptions(_UnserializationOptions): + + def __init__(self, py3_strings_as_str=False): + self.py3_strings_as_str = py3_strings_as_str + +class _Py3UnserializationOptions(_UnserializationOptions): + + def __init__(self, py2_strings_as_str=False): + self.py2_strings_as_str = py2_strings_as_str + + +_unchanging_dispatch = {} +for tp in (dict, list, tuple, int): + name = "save_%s" % (tp.__name__,) + _unchanging_dispatch[tp] = getattr(Serializer, name) +del tp, name + +def _setup_dispatch(): + dispatch = _unchanging_dispatch.copy() + # This is sutble. bytes is aliased to str in 2.6, so + # dispatch[bytes] is overwritten. Additionally, we alias unicode + # to str in 3.x, so dispatch[unicode] is overwritten with + # save_string. + dispatch[bytes] = Serializer.save_bytes + dispatch[unicode] = Serializer.save_unicode + dispatch[str] = Serializer.save_string + Serializer.dispatch = dispatch + +def _setup_version_dependent_constants(leave_unicode_alone=False): + global unicode, UnserializationOptions + if _INPY3: + unicode = str + UnserializationOptions = _Py3UnserializationOptions + else: + UnserializationOptions = _Py2UnserializationOptions + unicode = _unicode + _setup_dispatch() +_setup_version_dependent_constants() + + +class _Stop(Exception): + pass + +class Unserializer(object): + + def __init__(self, stream, options=None): + self.stream = stream + if options is None: + options = UnserializationOptions() + self.options = options + + def load(self): + self.stack = [] + version = ord(self.stream.read(1)) + if version != VERSION_NUMBER: + raise VersionMismatch("%i != %i" % (version, VERSION_NUMBER)) + try: + while True: + opcode = self.stream.read(1) + if not opcode: + raise EOFError + try: + loader = self.opcodes[opcode] + except KeyError: + raise Corruption("unkown opcode %s" % (opcode,)) + loader(self) + except _Stop: + if len(self.stack) != 1: + raise UnserializationError("internal unserialization error") + return self.stack[0] + else: + raise Corruption("didn't get STOP") + + opcodes = {} + + def load_int(self): + i = self._read_int4() + self.stack.append(i) + opcodes[INT] = load_int + + def _read_int4(self): + return _int4_format.unpack(self.stream.read(4))[0] + + def _read_byte_string(self): + length = self._read_int4() + as_bytes = self.stream.read(length) + return as_bytes + + def load_py3string(self): + as_bytes = self._read_byte_string() + if (not _INPY3 and self.options.py3_strings_as_str) and not _REALLY_PY3: + # XXX Should we try to decode into latin-1? + self.stack.append(as_bytes) + else: + self.stack.append(as_bytes.decode("utf-8")) + opcodes[PY3STRING] = load_py3string + + def load_py2string(self): + as_bytes = self._read_byte_string() + if (_INPY3 and self.options.py2_strings_as_str) or \ + (_REALLY_PY3 and not _INPY3): + s = as_bytes.decode("latin-1") + else: + s = as_bytes + self.stack.append(s) + opcodes[PY2STRING] = load_py2string + + def load_bytes(self): + s = bytes(self._read_byte_string()) + self.stack.append(s) + opcodes[BYTES] = load_bytes + + def load_unicode(self): + self.stack.append(self._read_byte_string().decode("utf-8")) + opcodes[UNICODE] = load_unicode + + def load_newlist(self): + length = self._read_int4() + self.stack.append([None] * length) + opcodes[NEWLIST] = load_newlist + + def load_setitem(self): + if len(self.stack) < 3: + raise Corruption("not enough items for setitem") + value = self.stack.pop() + key = self.stack.pop() + self.stack[-1][key] = value + opcodes[SETITEM] = load_setitem + + def load_newdict(self): + self.stack.append({}) + opcodes[NEWDICT] = load_newdict + + def load_buildtuple(self): + length = self._read_int4() + tup = tuple(self.stack[-length:]) + del self.stack[-length:] + self.stack.append(tup) + opcodes[BUILDTUPLE] = load_buildtuple + + def load_stop(self): + raise _Stop + opcodes[STOP] = load_stop From commits-noreply at bitbucket.org Mon Sep 28 22:47:03 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:47:03 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 9facb0d433af: merging jarko'S fixes, resolves issue #45, resolves issue #46 Message-ID: <20090928204703.D426C7111B@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User holger krekel # Date 1253727823 -7200 # Node ID 9facb0d433af6a8b1567eac0af7cd7ffcb85d806 # Parent 31b6c51fab40ba0798c2726d799d3a3f631a2ef0 # Parent 7eb914ccf56cccecfc6b3f28e726b2426442375e merging jarko'S fixes, resolves issue #45, resolves issue #46 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,6 +1,8 @@ Changes between 1.0.x and 'trunk' ===================================== +* merge Jarko's fixes, issue #45 and #46 + * add the ability to specify a path for py.lookup to search in * fix a funcarg cached_setup bug probably only occuring --- a/doc/test/quickstart.txt +++ b/doc/test/quickstart.txt @@ -23,7 +23,7 @@ Now create a file ``test_sample.py`` wit def func(x): return x + 1 def test_answer(): - assert f(3) == 5 + assert func(3) == 5 You can now run the test file like this:: From commits-noreply at bitbucket.org Mon Sep 28 22:50:28 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:50:28 +0000 (UTC) Subject: [py-svn] py-trunk commit b9b44ad50490: enhance the serializer tests Message-ID: <20090928205028.5E2EA710B5@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Ronny Pfannschmidt # Date 1254170792 -7200 # Node ID b9b44ad50490d3f87546ab6124ed0dd7cf42d75f # Parent 40fab66c01bc2bc379e24168a02be62f55e5c2d4 enhance the serializer tests * use generate_tests hook to generate the serialize deserialize combinations * add dump/load funcargs to simplify the tests --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -81,28 +81,40 @@ def pytest_funcarg__py2(request): def pytest_funcarg__py3(request): return _py3_wrapper +def pytest_funcarg__dump(request): + py_dump = request.getfuncargvalue(request.param[0]) + return py_dump.dump + +def pytest_funcarg__load(request): + py_dump = request.getfuncargvalue(request.param[1]) + return py_dump.load + +def pytest_generate_tests(metafunc): + if 'dump' in metafunc.funcargnames and 'load' in metafunc.funcargnames: + pys = 'py2', 'py3' + for dump in pys: + for load in pys: + metafunc.addcall(id='%s to %s'%(dump, load), param=(dump, load)) + + class TestSerializer: - def test_int(self, py2, py3): - for dump in py2.dump, py3.dump: - p = dump(4) - for load in py2.load, py3.load: - tp, v = load(p) - assert tp == "int" - assert int(v) == 4 + def test_int(self, dump, load): + p = dump(4) + tp, v = load(p) + assert tp == "int" + assert int(v) == 4 def test_bigint_should_fail(self): py.test.raises(serializer.SerializationError, serializer.Serializer(py.io.BytesIO()).save, 123456678900) - def test_float(self, py2, py3): - for dump in py2.dump, py3.dump: - p = dump(3.25) - for load in py2.load, py3.load: - tp, v = load(p) - assert tp == "float" - assert v == "3.25" + def test_float(self, dump, load): + p = dump(3.25) + tp, v = load(p) + assert tp == "float" + assert v == "3.25" def test_bytes(self, py2, py3): p = py3.dump("b'hi'") @@ -113,16 +125,15 @@ class TestSerializer: assert tp == "bytes" assert v == "b'hi'" - def check_sequence(self, seq, tp_name, rep, py2, py3): - for dump in py2.dump, py3.dump: - p = dump(seq) - for load in py2.load, py3.load: - tp, v = load(p) - assert tp == tp_name - assert v == rep + def check(self, val, tp_name, rep, dump, load): + p = dump(val) + tp , v = load(p) + assert tp == tp_name + assert v == rep - def test_list(self, py2, py3): - self.check_sequence([1, 2, 3], "list", "[1, 2, 3]", py2, py3) + + def test_list(self, dump, load): + self.check([1, 2, 3], "list", "[1, 2, 3]", dump, load) @py.test.mark.xfail # I'm not sure if we need the complexity. @@ -133,17 +144,15 @@ class TestSerializer: tp, rep = py2.load(l) assert tp == "list" - def test_tuple(self, py2, py3): - self.check_sequence((1, 2, 3), "tuple", "(1, 2, 3)", py2, py3) + def test_tuple(self, dump, load): + self.check((1, 2, 3), "tuple", "(1, 2, 3)", dump, load) - def test_dict(self, py2, py3): - for dump in py2.dump, py3.dump: - p = dump({6 : 2, (1, 2, 3) : 32}) - for load in py2.load, py3.load: - tp, v = load(p) - assert tp == "dict" - # XXX comparing dict reprs - assert v == "{6: 2, (1, 2, 3): 32}" + def test_dict(self, dump, load): + p = dump({6 : 2, (1, 2, 3) : 32}) + tp, v = load(p) + assert tp == "dict" + # XXX comparing dict reprs + assert v == "{6: 2, (1, 2, 3): 32}" def test_string(self, py2, py3): p = py2.dump("'xyz'") From commits-noreply at bitbucket.org Mon Sep 28 22:50:26 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:50:26 +0000 (UTC) Subject: [py-svn] py-trunk commit 40fab66c01bc: add separate test for the serializer bigint fail Message-ID: <20090928205026.63989710B1@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Ronny Pfannschmidt # Date 1254170556 -7200 # Node ID 40fab66c01bc2bc379e24168a02be62f55e5c2d4 # Parent 4d6f55850786cb0752e26efa3e7bd538b5090fe9 add separate test for the serializer bigint fail --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -90,6 +90,8 @@ class TestSerializer: tp, v = load(p) assert tp == "int" assert int(v) == 4 + + def test_bigint_should_fail(self): py.test.raises(serializer.SerializationError, serializer.Serializer(py.io.BytesIO()).save, 123456678900) From commits-noreply at bitbucket.org Mon Sep 28 22:54:17 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 20:54:17 +0000 (UTC) Subject: [py-svn] py-trunk commit 7aac1c673218: the check_sequence name is more specific Message-ID: <20090928205417.59EDE710AF@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Benjamin Peterson # Date 1254171309 18000 # Node ID 7aac1c673218b968edbbc0d324d4a25696b5e166 # Parent b9b44ad50490d3f87546ab6124ed0dd7cf42d75f the check_sequence name is more specific --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -125,15 +125,14 @@ class TestSerializer: assert tp == "bytes" assert v == "b'hi'" - def check(self, val, tp_name, rep, dump, load): + def check_sequence(self, val, tp_name, rep, dump, load): p = dump(val) tp , v = load(p) assert tp == tp_name assert v == rep - def test_list(self, dump, load): - self.check([1, 2, 3], "list", "[1, 2, 3]", dump, load) + self.check_sequence([1, 2, 3], "list", "[1, 2, 3]", dump, load) @py.test.mark.xfail # I'm not sure if we need the complexity. @@ -145,7 +144,7 @@ class TestSerializer: assert tp == "list" def test_tuple(self, dump, load): - self.check((1, 2, 3), "tuple", "(1, 2, 3)", dump, load) + self.check_sequence((1, 2, 3), "tuple", "(1, 2, 3)", dump, load) def test_dict(self, dump, load): p = dump({6 : 2, (1, 2, 3) : 32}) From commits-noreply at bitbucket.org Mon Sep 28 23:48:56 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 21:48:56 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 7aac1c673218: the check_sequence name is more specific Message-ID: <20090928214856.AC14F710AC@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Benjamin Peterson # Date 1254171309 18000 # Node ID 7aac1c673218b968edbbc0d324d4a25696b5e166 # Parent b9b44ad50490d3f87546ab6124ed0dd7cf42d75f the check_sequence name is more specific --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -125,15 +125,14 @@ class TestSerializer: assert tp == "bytes" assert v == "b'hi'" - def check(self, val, tp_name, rep, dump, load): + def check_sequence(self, val, tp_name, rep, dump, load): p = dump(val) tp , v = load(p) assert tp == tp_name assert v == rep - def test_list(self, dump, load): - self.check([1, 2, 3], "list", "[1, 2, 3]", dump, load) + self.check_sequence([1, 2, 3], "list", "[1, 2, 3]", dump, load) @py.test.mark.xfail # I'm not sure if we need the complexity. @@ -145,7 +144,7 @@ class TestSerializer: assert tp == "list" def test_tuple(self, dump, load): - self.check((1, 2, 3), "tuple", "(1, 2, 3)", dump, load) + self.check_sequence((1, 2, 3), "tuple", "(1, 2, 3)", dump, load) def test_dict(self, dump, load): p = dump({6 : 2, (1, 2, 3) : 32}) From commits-noreply at bitbucket.org Mon Sep 28 23:48:58 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 21:48:58 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 9d49aabf372c: simplify serializer tests Message-ID: <20090928214858.32647710B0@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Ronny Pfannschmidt # Date 1254174218 -7200 # Node ID 9d49aabf372cd2977efe0ff82dca8ceb42965465 # Parent 7aac1c673218b968edbbc0d324d4a25696b5e166 simplify serializer tests * use generate_tests to generate the simple non-string checks * get rid of the TestSerializer class --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -94,93 +94,86 @@ def pytest_generate_tests(metafunc): pys = 'py2', 'py3' for dump in pys: for load in pys: - metafunc.addcall(id='%s to %s'%(dump, load), param=(dump, load)) + param = (dump, load) + conversion = '%s to %s'%param + if 'repr' not in metafunc.funcargnames: + metafunc.addcall(id=conversion, param=param) + else: + for tp, repr in simple_tests.items(): + metafunc.addcall( + id='%s:%s'%(tp, conversion), + param=param, + funcargs={'tp_name':tp, 'repr':repr}, + ) -class TestSerializer: +simple_tests = { +# type: expected before/after repr + 'int': '4', + 'float':'3.25', + 'list': '[1, 2, 3]', + 'tuple': '(1, 2, 3)', + 'dict': '{6: 2, (1, 2, 3): 32}', +} - def test_int(self, dump, load): - p = dump(4) - tp, v = load(p) - assert tp == "int" - assert int(v) == 4 +def test_simple(tp_name, repr, dump, load): + p = dump(repr) + tp , v = load(p) + assert tp == tp_name + assert v == repr - def test_bigint_should_fail(self): - py.test.raises(serializer.SerializationError, - serializer.Serializer(py.io.BytesIO()).save, - 123456678900) - def test_float(self, dump, load): - p = dump(3.25) - tp, v = load(p) - assert tp == "float" - assert v == "3.25" + at py.test.mark.xfail +# I'm not sure if we need the complexity. +def test_recursive_list(py2, py3): + l = [1, 2, 3] + l.append(l) + p = py2.dump(l) + tp, rep = py2.load(l) + assert tp == "list" - def test_bytes(self, py2, py3): - p = py3.dump("b'hi'") - tp, v = py2.load(p) - assert tp == "str" - assert v == "'hi'" - tp, v = py3.load(p) - assert tp == "bytes" - assert v == "b'hi'" +def test_bigint_should_fail(): + py.test.raises(serializer.SerializationError, + serializer.Serializer(py.io.BytesIO()).save, + 123456678900) - def check_sequence(self, val, tp_name, rep, dump, load): - p = dump(val) - tp , v = load(p) - assert tp == tp_name - assert v == rep +def test_bytes(py2, py3): + p = py3.dump("b'hi'") + tp, v = py2.load(p) + assert tp == "str" + assert v == "'hi'" + tp, v = py3.load(p) + assert tp == "bytes" + assert v == "b'hi'" - def test_list(self, dump, load): - self.check_sequence([1, 2, 3], "list", "[1, 2, 3]", dump, load) +def test_string(py2, py3): + p = py2.dump("'xyz'") + tp, s = py2.load(p) + assert tp == "str" + assert s == "'xyz'" + tp, s = py3.load(p) + assert tp == "bytes" + assert s == "b'xyz'" + tp, s = py3.load(p, "True") + assert tp == "str" + assert s == "'xyz'" + p = py3.dump("'xyz'") + tp, s = py2.load(p, True) + assert tp == "str" + assert s == "'xyz'" - @py.test.mark.xfail - # I'm not sure if we need the complexity. - def test_recursive_list(self, py2, py3): - l = [1, 2, 3] - l.append(l) - p = py2.dump(l) - tp, rep = py2.load(l) - assert tp == "list" - - def test_tuple(self, dump, load): - self.check_sequence((1, 2, 3), "tuple", "(1, 2, 3)", dump, load) - - def test_dict(self, dump, load): - p = dump({6 : 2, (1, 2, 3) : 32}) - tp, v = load(p) - assert tp == "dict" - # XXX comparing dict reprs - assert v == "{6: 2, (1, 2, 3): 32}" - - def test_string(self, py2, py3): - p = py2.dump("'xyz'") - tp, s = py2.load(p) - assert tp == "str" - assert s == "'xyz'" - tp, s = py3.load(p) - assert tp == "bytes" - assert s == "b'xyz'" - tp, s = py3.load(p, "True") - assert tp == "str" - assert s == "'xyz'" - p = py3.dump("'xyz'") - tp, s = py2.load(p, True) - assert tp == "str" - assert s == "'xyz'" - - def test_unicode(self, py2, py3): - p = py2.dump("u'hi'") - tp, s = py2.load(p) - assert tp == "unicode" - assert s == "u'hi'" - tp, s = py3.load(p) - assert tp == "str" - assert s == "'hi'" - p = py3.dump("'hi'") - tp, s = py3.load(p) - assert tp == "str" - assert s == "'hi'" - tp, s = py2.load(p) - assert tp == "unicode" - assert s == "u'hi'" +def test_unicode(py2, py3): + p = py2.dump("u'hi'") + tp, s = py2.load(p) + assert tp == "unicode" + assert s == "u'hi'" + tp, s = py3.load(p) + assert tp == "str" + assert s == "'hi'" + p = py3.dump("'hi'") + tp, s = py3.load(p) + assert tp == "str" + assert s == "'hi'" + tp, s = py2.load(p) + assert tp == "unicode" + assert s == "u'hi'" From commits-noreply at bitbucket.org Mon Sep 28 23:52:10 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Mon, 28 Sep 2009 21:52:10 +0000 (UTC) Subject: [py-svn] py-trunk commit 9d49aabf372c: simplify serializer tests Message-ID: <20090928215210.8DA91710AC@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User Ronny Pfannschmidt # Date 1254174218 -7200 # Node ID 9d49aabf372cd2977efe0ff82dca8ceb42965465 # Parent 7aac1c673218b968edbbc0d324d4a25696b5e166 simplify serializer tests * use generate_tests to generate the simple non-string checks * get rid of the TestSerializer class --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -94,93 +94,86 @@ def pytest_generate_tests(metafunc): pys = 'py2', 'py3' for dump in pys: for load in pys: - metafunc.addcall(id='%s to %s'%(dump, load), param=(dump, load)) + param = (dump, load) + conversion = '%s to %s'%param + if 'repr' not in metafunc.funcargnames: + metafunc.addcall(id=conversion, param=param) + else: + for tp, repr in simple_tests.items(): + metafunc.addcall( + id='%s:%s'%(tp, conversion), + param=param, + funcargs={'tp_name':tp, 'repr':repr}, + ) -class TestSerializer: +simple_tests = { +# type: expected before/after repr + 'int': '4', + 'float':'3.25', + 'list': '[1, 2, 3]', + 'tuple': '(1, 2, 3)', + 'dict': '{6: 2, (1, 2, 3): 32}', +} - def test_int(self, dump, load): - p = dump(4) - tp, v = load(p) - assert tp == "int" - assert int(v) == 4 +def test_simple(tp_name, repr, dump, load): + p = dump(repr) + tp , v = load(p) + assert tp == tp_name + assert v == repr - def test_bigint_should_fail(self): - py.test.raises(serializer.SerializationError, - serializer.Serializer(py.io.BytesIO()).save, - 123456678900) - def test_float(self, dump, load): - p = dump(3.25) - tp, v = load(p) - assert tp == "float" - assert v == "3.25" + at py.test.mark.xfail +# I'm not sure if we need the complexity. +def test_recursive_list(py2, py3): + l = [1, 2, 3] + l.append(l) + p = py2.dump(l) + tp, rep = py2.load(l) + assert tp == "list" - def test_bytes(self, py2, py3): - p = py3.dump("b'hi'") - tp, v = py2.load(p) - assert tp == "str" - assert v == "'hi'" - tp, v = py3.load(p) - assert tp == "bytes" - assert v == "b'hi'" +def test_bigint_should_fail(): + py.test.raises(serializer.SerializationError, + serializer.Serializer(py.io.BytesIO()).save, + 123456678900) - def check_sequence(self, val, tp_name, rep, dump, load): - p = dump(val) - tp , v = load(p) - assert tp == tp_name - assert v == rep +def test_bytes(py2, py3): + p = py3.dump("b'hi'") + tp, v = py2.load(p) + assert tp == "str" + assert v == "'hi'" + tp, v = py3.load(p) + assert tp == "bytes" + assert v == "b'hi'" - def test_list(self, dump, load): - self.check_sequence([1, 2, 3], "list", "[1, 2, 3]", dump, load) +def test_string(py2, py3): + p = py2.dump("'xyz'") + tp, s = py2.load(p) + assert tp == "str" + assert s == "'xyz'" + tp, s = py3.load(p) + assert tp == "bytes" + assert s == "b'xyz'" + tp, s = py3.load(p, "True") + assert tp == "str" + assert s == "'xyz'" + p = py3.dump("'xyz'") + tp, s = py2.load(p, True) + assert tp == "str" + assert s == "'xyz'" - @py.test.mark.xfail - # I'm not sure if we need the complexity. - def test_recursive_list(self, py2, py3): - l = [1, 2, 3] - l.append(l) - p = py2.dump(l) - tp, rep = py2.load(l) - assert tp == "list" - - def test_tuple(self, dump, load): - self.check_sequence((1, 2, 3), "tuple", "(1, 2, 3)", dump, load) - - def test_dict(self, dump, load): - p = dump({6 : 2, (1, 2, 3) : 32}) - tp, v = load(p) - assert tp == "dict" - # XXX comparing dict reprs - assert v == "{6: 2, (1, 2, 3): 32}" - - def test_string(self, py2, py3): - p = py2.dump("'xyz'") - tp, s = py2.load(p) - assert tp == "str" - assert s == "'xyz'" - tp, s = py3.load(p) - assert tp == "bytes" - assert s == "b'xyz'" - tp, s = py3.load(p, "True") - assert tp == "str" - assert s == "'xyz'" - p = py3.dump("'xyz'") - tp, s = py2.load(p, True) - assert tp == "str" - assert s == "'xyz'" - - def test_unicode(self, py2, py3): - p = py2.dump("u'hi'") - tp, s = py2.load(p) - assert tp == "unicode" - assert s == "u'hi'" - tp, s = py3.load(p) - assert tp == "str" - assert s == "'hi'" - p = py3.dump("'hi'") - tp, s = py3.load(p) - assert tp == "str" - assert s == "'hi'" - tp, s = py2.load(p) - assert tp == "unicode" - assert s == "u'hi'" +def test_unicode(py2, py3): + p = py2.dump("u'hi'") + tp, s = py2.load(p) + assert tp == "unicode" + assert s == "u'hi'" + tp, s = py3.load(p) + assert tp == "str" + assert s == "'hi'" + p = py3.dump("'hi'") + tp, s = py3.load(p) + assert tp == "str" + assert s == "'hi'" + tp, s = py2.load(p) + assert tp == "unicode" + assert s == "u'hi'" From commits-noreply at bitbucket.org Wed Sep 30 13:01:46 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 30 Sep 2009 11:01:46 +0000 (UTC) Subject: [py-svn] py-trunk commit cbbfed07e234: fix cached_setup to deal properly for test_functions Message-ID: <20090930110146.5CD4D710A9@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1254307960 -7200 # Node ID cbbfed07e2349c1043bb4dbf57caba5cfbede7a2 # Parent 9d49aabf372cd2977efe0ff82dca8ceb42965465 fix cached_setup to deal properly for test_functions with multiple args. closes #50 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,6 +1,9 @@ Changes between 1.0.x and 'trunk' ===================================== +* fix issue50 - cached_setup now caches more to expectations + for test functions with multiple arguments. + * merge Jarko's fixes, issue #45 and #46 * add the ability to specify a path for py.lookup to search in --- a/py/test/funcargs.py +++ b/py/test/funcargs.py @@ -96,6 +96,7 @@ class FuncargRequest: self._plugins.append(self.instance) self._funcargs = self._pyfuncitem.funcargs.copy() self._provider = {} + self._currentarg = None def _fillfuncargs(self): argnames = getfuncargnames(self.function) @@ -109,16 +110,16 @@ class FuncargRequest: def cached_setup(self, setup, teardown=None, scope="module", extrakey=None): """ cache and return result of calling setup(). - The scope and the ``extrakey`` determine the cache key. - The scope also determines when teardown(result) - will be called. valid scopes are: + The requested argument name, the scope and the ``extrakey`` + determine the cache key. The scope also determines when + teardown(result) will be called. valid scopes are: scope == 'function': when the single test function run finishes. scope == 'module': when tests in a different module are run scope == 'session': when tests of the session have run. """ if not hasattr(self.config, '_setupcache'): self.config._setupcache = {} # XXX weakref? - cachekey = (self._getscopeitem(scope), extrakey) + cachekey = (self._currentarg, self._getscopeitem(scope), extrakey) cache = self.config._setupcache try: val = cache[cachekey] @@ -146,7 +147,12 @@ class FuncargRequest: if not self._provider[argname]: self._raiselookupfailed(argname) funcargprovider = self._provider[argname].pop() - self._funcargs[argname] = res = funcargprovider(request=self) + oldarg = self._currentarg + self._currentarg = argname + try: + self._funcargs[argname] = res = funcargprovider(request=self) + finally: + self._currentarg = oldarg return res def _getscopeitem(self, scope): --- a/doc/test/funcargs.txt +++ b/doc/test/funcargs.txt @@ -388,9 +388,9 @@ managing fixtures across test modules an def cached_setup(setup, teardown=None, scope="module", extrakey=None): """ cache and return result of calling setup(). - The scope and the ``extrakey`` determine the cache key. - The scope also determines when teardown(result) - will be called. valid scopes are: + The requested argument name, the scope and the ``extrakey`` + determine the cache key. The scope also determines when + teardown(result) will be called. valid scopes are: scope == 'function': when the single test function run finishes. scope == 'module': when tests in a different module are run scope == 'session': when tests of the session have run. --- a/testing/pytest/test_funcargs.py +++ b/testing/pytest/test_funcargs.py @@ -258,6 +258,35 @@ class TestRequestCachedSetup: req1.config._setupstate._callfinalizers(item1) assert l == ["setup", "teardown", "setup", "teardown"] + def test_request_cached_setup_two_args(self, testdir): + testdir.makepyfile(""" + def pytest_funcarg__arg1(request): + return request.cached_setup(lambda: 42) + def pytest_funcarg__arg2(request): + return request.cached_setup(lambda: 17) + def test_two_different_setups(arg1, arg2): + assert arg1 != arg2 + """) + result = testdir.runpytest("-v") + result.stdout.fnmatch_lines([ + "*1 passed*" + ]) + + def test_request_cached_setup_getfuncargvalue(self, testdir): + testdir.makepyfile(""" + def pytest_funcarg__arg1(request): + arg1 = request.getfuncargvalue("arg2") + return request.cached_setup(lambda: arg1 + 1) + def pytest_funcarg__arg2(request): + return request.cached_setup(lambda: 10) + def test_two_funcarg(arg1): + assert arg1 == 11 + """) + result = testdir.runpytest("-v") + result.stdout.fnmatch_lines([ + "*1 passed*" + ]) + def test_request_cached_setup_functional(self, testdir): testdir.makepyfile(test_0=""" l = [] From commits-noreply at bitbucket.org Wed Sep 30 13:01:48 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 30 Sep 2009 11:01:48 +0000 (UTC) Subject: [py-svn] py-trunk commit 2d0ca4835bd1: internally rename "provider" to "factory" to be consistent Message-ID: <20090930110148.1C0EB710A4@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1254308387 -7200 # Node ID 2d0ca4835bd14c2a679b5a6b916a9a255da404a1 # Parent cbbfed07e2349c1043bb4dbf57caba5cfbede7a2 internally rename "provider" to "factory" to be consistent with documentation. --- a/py/test/funcargs.py +++ b/py/test/funcargs.py @@ -95,7 +95,7 @@ class FuncargRequest: if self.instance is not None: self._plugins.append(self.instance) self._funcargs = self._pyfuncitem.funcargs.copy() - self._provider = {} + self._name2factory = {} self._currentarg = None def _fillfuncargs(self): @@ -138,19 +138,19 @@ class FuncargRequest: return self._funcargs[argname] except KeyError: pass - if argname not in self._provider: - self._provider[argname] = self.config.pluginmanager.listattr( + if argname not in self._name2factory: + self._name2factory[argname] = self.config.pluginmanager.listattr( plugins=self._plugins, attrname=self._argprefix + str(argname) ) #else: we are called recursively - if not self._provider[argname]: + if not self._name2factory[argname]: self._raiselookupfailed(argname) - funcargprovider = self._provider[argname].pop() + funcargfactory = self._name2factory[argname].pop() oldarg = self._currentarg self._currentarg = argname try: - self._funcargs[argname] = res = funcargprovider(request=self) + self._funcargs[argname] = res = funcargfactory(request=self) finally: self._currentarg = oldarg return res --- a/testing/pytest/test_funcargs.py +++ b/testing/pytest/test_funcargs.py @@ -115,7 +115,7 @@ class TestRequest: assert req.cls.__name__ == "TestB" assert req.instance.__class__ == req.cls - def XXXtest_request_contains_funcargs_provider(self, testdir): + def XXXtest_request_contains_funcarg_name2factory(self, testdir): modcol = testdir.getmodulecol(""" def pytest_funcarg__something(request): pass @@ -125,9 +125,9 @@ class TestRequest: """) item1, = testdir.genitems([modcol]) assert item1.name == "test_method" - provider = funcargs.FuncargRequest(item1)._provider - assert len(provider) == 1 - assert provider[0].__name__ == "pytest_funcarg__something" + name2factory = funcargs.FuncargRequest(item1)._name2factory + assert len(name2factory) == 1 + assert name2factory[0].__name__ == "pytest_funcarg__something" def test_getfuncargvalue_recursive(self, testdir): testdir.makeconftest(""" From commits-noreply at bitbucket.org Wed Sep 30 16:21:16 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 30 Sep 2009 14:21:16 +0000 (UTC) Subject: [py-svn] py-virtualenv commit cbbfed07e234: fix cached_setup to deal properly for test_functions Message-ID: <20090930142116.178FC7109D@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User holger krekel # Date 1254307960 -7200 # Node ID cbbfed07e2349c1043bb4dbf57caba5cfbede7a2 # Parent 9d49aabf372cd2977efe0ff82dca8ceb42965465 fix cached_setup to deal properly for test_functions with multiple args. closes #50 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,6 +1,9 @@ Changes between 1.0.x and 'trunk' ===================================== +* fix issue50 - cached_setup now caches more to expectations + for test functions with multiple arguments. + * merge Jarko's fixes, issue #45 and #46 * add the ability to specify a path for py.lookup to search in --- a/py/test/funcargs.py +++ b/py/test/funcargs.py @@ -96,6 +96,7 @@ class FuncargRequest: self._plugins.append(self.instance) self._funcargs = self._pyfuncitem.funcargs.copy() self._provider = {} + self._currentarg = None def _fillfuncargs(self): argnames = getfuncargnames(self.function) @@ -109,16 +110,16 @@ class FuncargRequest: def cached_setup(self, setup, teardown=None, scope="module", extrakey=None): """ cache and return result of calling setup(). - The scope and the ``extrakey`` determine the cache key. - The scope also determines when teardown(result) - will be called. valid scopes are: + The requested argument name, the scope and the ``extrakey`` + determine the cache key. The scope also determines when + teardown(result) will be called. valid scopes are: scope == 'function': when the single test function run finishes. scope == 'module': when tests in a different module are run scope == 'session': when tests of the session have run. """ if not hasattr(self.config, '_setupcache'): self.config._setupcache = {} # XXX weakref? - cachekey = (self._getscopeitem(scope), extrakey) + cachekey = (self._currentarg, self._getscopeitem(scope), extrakey) cache = self.config._setupcache try: val = cache[cachekey] @@ -146,7 +147,12 @@ class FuncargRequest: if not self._provider[argname]: self._raiselookupfailed(argname) funcargprovider = self._provider[argname].pop() - self._funcargs[argname] = res = funcargprovider(request=self) + oldarg = self._currentarg + self._currentarg = argname + try: + self._funcargs[argname] = res = funcargprovider(request=self) + finally: + self._currentarg = oldarg return res def _getscopeitem(self, scope): --- a/doc/test/funcargs.txt +++ b/doc/test/funcargs.txt @@ -388,9 +388,9 @@ managing fixtures across test modules an def cached_setup(setup, teardown=None, scope="module", extrakey=None): """ cache and return result of calling setup(). - The scope and the ``extrakey`` determine the cache key. - The scope also determines when teardown(result) - will be called. valid scopes are: + The requested argument name, the scope and the ``extrakey`` + determine the cache key. The scope also determines when + teardown(result) will be called. valid scopes are: scope == 'function': when the single test function run finishes. scope == 'module': when tests in a different module are run scope == 'session': when tests of the session have run. --- a/testing/pytest/test_funcargs.py +++ b/testing/pytest/test_funcargs.py @@ -258,6 +258,35 @@ class TestRequestCachedSetup: req1.config._setupstate._callfinalizers(item1) assert l == ["setup", "teardown", "setup", "teardown"] + def test_request_cached_setup_two_args(self, testdir): + testdir.makepyfile(""" + def pytest_funcarg__arg1(request): + return request.cached_setup(lambda: 42) + def pytest_funcarg__arg2(request): + return request.cached_setup(lambda: 17) + def test_two_different_setups(arg1, arg2): + assert arg1 != arg2 + """) + result = testdir.runpytest("-v") + result.stdout.fnmatch_lines([ + "*1 passed*" + ]) + + def test_request_cached_setup_getfuncargvalue(self, testdir): + testdir.makepyfile(""" + def pytest_funcarg__arg1(request): + arg1 = request.getfuncargvalue("arg2") + return request.cached_setup(lambda: arg1 + 1) + def pytest_funcarg__arg2(request): + return request.cached_setup(lambda: 10) + def test_two_funcarg(arg1): + assert arg1 == 11 + """) + result = testdir.runpytest("-v") + result.stdout.fnmatch_lines([ + "*1 passed*" + ]) + def test_request_cached_setup_functional(self, testdir): testdir.makepyfile(test_0=""" l = [] From commits-noreply at bitbucket.org Wed Sep 30 16:21:18 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 30 Sep 2009 14:21:18 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 2d0ca4835bd1: internally rename "provider" to "factory" to be consistent Message-ID: <20090930142118.5D85E710A4@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User holger krekel # Date 1254308387 -7200 # Node ID 2d0ca4835bd14c2a679b5a6b916a9a255da404a1 # Parent cbbfed07e2349c1043bb4dbf57caba5cfbede7a2 internally rename "provider" to "factory" to be consistent with documentation. --- a/py/test/funcargs.py +++ b/py/test/funcargs.py @@ -95,7 +95,7 @@ class FuncargRequest: if self.instance is not None: self._plugins.append(self.instance) self._funcargs = self._pyfuncitem.funcargs.copy() - self._provider = {} + self._name2factory = {} self._currentarg = None def _fillfuncargs(self): @@ -138,19 +138,19 @@ class FuncargRequest: return self._funcargs[argname] except KeyError: pass - if argname not in self._provider: - self._provider[argname] = self.config.pluginmanager.listattr( + if argname not in self._name2factory: + self._name2factory[argname] = self.config.pluginmanager.listattr( plugins=self._plugins, attrname=self._argprefix + str(argname) ) #else: we are called recursively - if not self._provider[argname]: + if not self._name2factory[argname]: self._raiselookupfailed(argname) - funcargprovider = self._provider[argname].pop() + funcargfactory = self._name2factory[argname].pop() oldarg = self._currentarg self._currentarg = argname try: - self._funcargs[argname] = res = funcargprovider(request=self) + self._funcargs[argname] = res = funcargfactory(request=self) finally: self._currentarg = oldarg return res --- a/testing/pytest/test_funcargs.py +++ b/testing/pytest/test_funcargs.py @@ -115,7 +115,7 @@ class TestRequest: assert req.cls.__name__ == "TestB" assert req.instance.__class__ == req.cls - def XXXtest_request_contains_funcargs_provider(self, testdir): + def XXXtest_request_contains_funcarg_name2factory(self, testdir): modcol = testdir.getmodulecol(""" def pytest_funcarg__something(request): pass @@ -125,9 +125,9 @@ class TestRequest: """) item1, = testdir.genitems([modcol]) assert item1.name == "test_method" - provider = funcargs.FuncargRequest(item1)._provider - assert len(provider) == 1 - assert provider[0].__name__ == "pytest_funcarg__something" + name2factory = funcargs.FuncargRequest(item1)._name2factory + assert len(name2factory) == 1 + assert name2factory[0].__name__ == "pytest_funcarg__something" def test_getfuncargvalue_recursive(self, testdir): testdir.makeconftest(""" From commits-noreply at bitbucket.org Wed Sep 30 16:21:18 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 30 Sep 2009 14:21:18 +0000 (UTC) Subject: [py-svn] py-virtualenv commit 11b209bb3b00: add dump/load(s) convience functions to the serializer Message-ID: <20090930142118.B3407710A9@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-virtualenv # URL http://bitbucket.org/RonnyPfannschmidt/py-virtualenv/overview/ # User Ronny Pfannschmidt # Date 1254320470 -7200 # Node ID 11b209bb3b00ab5a9083f1cb9dd6c520c1bedc67 # Parent 2d0ca4835bd14c2a679b5a6b916a9a255da404a1 add dump/load(s) convience functions to the serializer --- a/testing/execnet/test_serializer.py +++ b/testing/execnet/test_serializer.py @@ -44,8 +44,8 @@ from py.__.execnet import serializer import sys if sys.version_info > (3, 0): # Need binary output sys.stdout = sys.stdout.detach() -saver = serializer.Serializer(sys.stdout) -saver.save(%s)""" % (obj_rep,)) +sys.stdout.write(serializer.dumps(%s)) +""" % (obj_rep,)) return self.executable.sysexec(script_file) def load(self, data, option_args=""): @@ -55,9 +55,7 @@ from py.__.execnet import serializer import sys if sys.version_info > (3, 0): sys.stdin = sys.stdin.detach() -options = serializer.UnserializationOptions(%s) -loader = serializer.Unserializer(sys.stdin, options) -obj = loader.load() +obj = serializer.loads(sys.stdin.read(), %s) sys.stdout.write(type(obj).__name__ + "\n") sys.stdout.write(repr(obj))""" % (option_args,)) popen = subprocess.Popen([str(self.executable), str(script_file)], --- a/py/execnet/serializer.py +++ b/py/execnet/serializer.py @@ -270,3 +270,24 @@ class Unserializer(object): def load_stop(self): raise _Stop opcodes[STOP] = load_stop + +def dump(fd, object): + serializer = Serializer(fd) + serializer.save(object) + +def dumps(object): + from py.io import BytesIO #XXX: fallback to non-pylib? + io = BytesIO() + dump(io, object) + return io.getvalue() + +def load(fd, *k, **kw): + options = UnserializationOptions(*k, **kw) + unserializer = Unserializer(fd, options) + return unserializer.load() + +def loads(s, *k, **kw): + from py.io import BytesIO #XXX: fallback to non-pylib? + io = BytesIO(s) + return load(io, *k, **kw) + From commits-noreply at bitbucket.org Wed Sep 30 18:00:11 2009 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 30 Sep 2009 16:00:11 +0000 (UTC) Subject: [py-svn] py-trunk commit 48444c100e15: fix typo, add ronny to authors, normalize email addresses Message-ID: <20090930160011.9973F710AC@bitbucket.org> # HG changeset patch -- Bitbucket.org # Project py-trunk # URL http://bitbucket.org/hpk42/py-trunk/overview/ # User holger krekel # Date 1254326343 -7200 # Node ID 48444c100e15b2acc3ffd1c515dbb7d41d928e92 # Parent 2d0ca4835bd14c2a679b5a6b916a9a255da404a1 fix typo, add ronny to authors, normalize email addresses --- a/testing/cmdline/test_cmdline.py +++ b/testing/cmdline/test_cmdline.py @@ -16,7 +16,7 @@ class TestPyLookup: ['*%s:*' %(p.basename)] ) - def test_with_explicit_path(self, testxbdir): + def test_with_explicit_path(self, testdir): sub1 = testdir.mkdir("things") sub2 = testdir.mkdir("foo") sub1.join("pyfile.py").write("def stuff(): pass") --- a/AUTHORS +++ b/AUTHORS @@ -2,9 +2,9 @@ Holger Krekel, holger at merlinux eu Guido Wesdorp, johnny at johnnydebris net Samuele Pedroni, pedronis at openend se Carl Friedrich Bolz, cfbolz at gmx de -Benjamin Peterson, benjamin at python.org +Benjamin Peterson, benjamin at python org +Ronny Pfannschmidt, Ronny.Pfannschmidt at gmx de Armin Rigo, arigo at tunes org -Maciek Fijalkowski, fijal at genesilico.pl +Maciek Fijalkowski, fijal at genesilico pl Brian Dorsey, briandorsey at gmail com merlinux GmbH, Germany, office at merlinux eu -