From e3b34c9da3078725a054ceac6a37f529a48012c3 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Tue, 22 Sep 2009 18:40:20 +0200 Subject: [PATCH] * 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. --HG-- branch : trunk --- py/execnet/gateway.py | 2 +- py/execnet/gateway_base.py | 14 ++++++++------ py/execnet/xspec.py | 17 ++++++++++------- testing/execnet/test_xspec.py | 31 +++++++++++++++++++++---------- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/py/execnet/gateway.py b/py/execnet/gateway.py index c978ffdef..29d9608e3 100644 --- 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()", "" ]) diff --git a/py/execnet/gateway_base.py b/py/execnet/gateway_base.py index 0125412e5..fbb9ff8e7 100644 --- 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): diff --git a/py/execnet/xspec.py b/py/execnet/xspec.py index da741de16..9c5497df3 100644 --- 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(""" diff --git a/testing/execnet/test_xspec.py b/testing/execnet/test_xspec.py index 205cb1c6d..5ccf16dd7 100644 --- 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'):