From 783e6aeb4d899038d7f086f722b865a1cbfb44e2 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Fri, 28 Aug 2009 19:16:15 +0200 Subject: [PATCH] temporary checking towards 3.1 compatibility introduced some helpers to py.builtin namespace which need some review after things begin to work more nicely --HG-- branch : trunk --- py/__init__.py | 3 ++ py/_com.py | 8 ++-- py/bin/_findpy.py | 4 +- py/builtin/builtin31.py | 5 +++ py/builtin/testing/test_builtin.py | 2 +- py/code/{assertion.py => _assertion.py} | 0 py/code/code.py | 55 +++++++++++++++---------- py/code/source.py | 25 ++++++----- py/code/testing/test_assertion.py | 28 +++++++++---- py/code/testing/test_code.py | 23 +++++++---- py/code/testing/test_excinfo.py | 26 +++++------- py/code/testing/test_source.py | 28 +++++++------ py/io/capture.py | 9 ++-- py/io/terminalwriter.py | 4 +- py/path/common.py | 2 +- py/path/local.py | 26 +++++++----- py/test/cmdline.py | 8 ++-- py/test/collect.py | 5 ++- py/test/config.py | 6 ++- py/test/conftesthandle.py | 2 +- py/test/funcargs.py | 8 ++-- py/test/outcome.py | 3 +- py/test/plugin/pytest__pytest.py | 4 +- py/test/plugin/pytest_assertion.py | 11 +++-- py/test/plugin/pytest_capture.py | 14 ++++--- py/test/plugin/pytest_default.py | 8 +--- py/test/plugin/pytest_keyword.py | 2 +- py/test/plugin/pytest_pdb.py | 6 +-- py/test/plugin/pytest_pytester.py | 20 ++++----- py/test/plugin/pytest_runner.py | 2 +- py/test/plugin/pytest_unittest.py | 1 - py/test/pluginmanager.py | 21 ++++++---- py/test/pycollect.py | 13 +++--- 33 files changed, 218 insertions(+), 164 deletions(-) rename py/code/{assertion.py => _assertion.py} (100%) diff --git a/py/__init__.py b/py/__init__.py index 2d2f54601..ad9d6c2a4 100644 --- a/py/__init__.py +++ b/py/__init__.py @@ -130,6 +130,7 @@ initpkg(__name__, 'code.ExceptionInfo' : ('./code/code.py', 'ExceptionInfo'), 'code.Traceback' : ('./code/code.py', 'Traceback'), 'code.getfslineno' : ('./code/source.py', 'getfslineno'), + 'code.getrawcode' : ('./code/code.py', 'getrawcode'), 'code.patch_builtins' : ('./code/code.py', 'patch_builtins'), 'code.unpatch_builtins' : ('./code/code.py', 'unpatch_builtins'), 'code._AssertionError' : ('./code/assertion.py', 'AssertionError'), @@ -146,6 +147,8 @@ initpkg(__name__, 'builtin.print_' : ('./builtin/builtin31.py', 'print_'), 'builtin._reraise' : ('./builtin/builtin31.py', '_reraise'), 'builtin.exec_' : ('./builtin/builtin31.py', 'exec_'), + 'builtin.basestring' : ('./builtin/builtin31.py', 'basestring'), + 'builtin.builtins' : ('./builtin/builtin31.py', 'builtins'), # gateways into remote contexts 'execnet.__doc__' : ('./execnet/__init__.py', '__doc__'), diff --git a/py/_com.py b/py/_com.py index 43976ad43..98104043e 100644 --- a/py/_com.py +++ b/py/_com.py @@ -3,6 +3,7 @@ py lib plugins and plugin call management """ import py +import inspect class MultiCall: """ execute a call into multiple python functions/methods. """ @@ -39,10 +40,9 @@ class MultiCall: pass # might be optional param return kwargs -def varnames(rawcode): - ismethod = hasattr(rawcode, 'im_self') - rawcode = getattr(rawcode, 'im_func', rawcode) - rawcode = getattr(rawcode, 'func_code', rawcode) +def varnames(func): + ismethod = inspect.ismethod(func) + rawcode = py.code.getrawcode(func) try: return rawcode.co_varnames[ismethod:] except AttributeError: diff --git a/py/bin/_findpy.py b/py/bin/_findpy.py index c1e208fae..c0c64581e 100755 --- a/py/bin/_findpy.py +++ b/py/bin/_findpy.py @@ -19,7 +19,7 @@ def searchpy(current): # if p == current: # return True if current != sys.path[0]: # if we are already first, then ok - print >>sys.stderr, "inserting into sys.path:", current + sys.stderr.write("inserting into sys.path: %s\n" % current) sys.path.insert(0, current) return True current = opd(current) @@ -34,4 +34,4 @@ if not searchpy(abspath(os.curdir)): import py if __name__ == '__main__': - print "py lib is at", py.__file__ + print ("py lib is at %s" % py.__file__) diff --git a/py/builtin/builtin31.py b/py/builtin/builtin31.py index ab867ec5f..a2703af25 100644 --- a/py/builtin/builtin31.py +++ b/py/builtin/builtin31.py @@ -2,7 +2,12 @@ import sys if sys.version_info >= (3, 0): exec ("print_ = print ; exec_=exec") + import builtins + basestring = str + else: + basestring = basestring + import __builtin__ as builtins def print_(*args, **kwargs): """ minimal backport of py3k print statement. """ sep = 'sep' in kwargs and kwargs.pop('sep') or ' ' diff --git a/py/builtin/testing/test_builtin.py b/py/builtin/testing/test_builtin.py index 673b25404..9ca01e8c3 100644 --- a/py/builtin/testing/test_builtin.py +++ b/py/builtin/testing/test_builtin.py @@ -75,7 +75,7 @@ def test_print_simple(): f = py.io.TextIO() print_("hello", "world", file=f) s = f.getvalue() - assert s == u"hello world\n" + assert s == "hello world\n" py.test.raises(TypeError, "print_(hello=3)") def test_reraise(): diff --git a/py/code/assertion.py b/py/code/_assertion.py similarity index 100% rename from py/code/assertion.py rename to py/code/_assertion.py diff --git a/py/code/code.py b/py/code/code.py index 97d7221dc..2581a978c 100644 --- a/py/code/code.py +++ b/py/code/code.py @@ -1,19 +1,17 @@ import py import sys + +builtin_repr = repr try: import repr except ImportError: import reprlib as repr -import __builtin__ as cpy_builtin - -builtin_repr = cpy_builtin.repr class Code(object): """ wrapper around Python code objects """ def __init__(self, rawcode): - rawcode = getattr(rawcode, 'im_func', rawcode) - rawcode = getattr(rawcode, 'func_code', rawcode) + rawcode = py.code.getrawcode(rawcode) self.raw = rawcode try: self.filename = rawcode.co_filename @@ -49,7 +47,7 @@ class Code(object): for name in names: if name not in kwargs: kwargs[name] = getattr(self.raw, name) - return py.std.new.code( + arglist = [ kwargs['co_argcount'], kwargs['co_nlocals'], kwargs['co_stacksize'], @@ -64,7 +62,10 @@ class Code(object): kwargs['co_lnotab'], kwargs['co_freevars'], kwargs['co_cellvars'], - ) + ] + if sys.version_info >= (3,0): + arglist.insert(1, kwargs['co_kwonlyargcount']) + return self.raw.__class__(*arglist) def path(self): """ return a py.path.local object pointing to the source code """ @@ -139,7 +140,7 @@ class Frame(object): """ f_locals = self.f_locals.copy() f_locals.update(vars) - exec code in self.f_globals, f_locals + py.builtin.exec_(code, self.f_globals, f_locals ) def repr(self, object): """ return a 'safe' (non-recursive, one-line) string repr for 'object' @@ -196,11 +197,11 @@ class TracebackEntry(object): """Reinterpret the failing statement and returns a detailed information about what operations are performed.""" if self.exprinfo is None: - from py.__.code import assertion + from py.__.code import _assertion source = str(self.statement).strip() - x = assertion.interpret(source, self.frame, should_fail=True) + x = _assertion.interpret(source, self.frame, should_fail=True) if not isinstance(x, str): - raise TypeError, "interpret returned non-string %r" % (x,) + raise TypeError("interpret returned non-string %r" % (x,)) self.exprinfo = x return self.exprinfo @@ -358,7 +359,9 @@ class ExceptionInfo(object): if tup is None: tup = sys.exc_info() if exprinfo is None and isinstance(tup[1], py.code._AssertionError): - exprinfo = tup[1].msg + exprinfo = getattr(tup[1], 'msg', None) + if exprinfo is None: + exprinfo = str(tup[1]) if exprinfo and exprinfo.startswith('assert '): self._striptext = 'AssertionError: ' self._excinfo = tup @@ -491,9 +494,10 @@ class FormattedExcinfo(object): def repr_locals(self, locals): if self.showlocals: lines = [] - items = locals.items() - items.sort() - for name, value in items: + keys = list(locals) + keys.sort() + for name in keys: + value = locals[name] if name == '__builtins__': lines.append("__builtins__ = ") else: @@ -737,16 +741,25 @@ def patch_builtins(assertion=True, compile=True): if assertion: from py.__.code import assertion l = oldbuiltins.setdefault('AssertionError', []) - l.append(cpy_builtin.AssertionError) - cpy_builtin.AssertionError = assertion.AssertionError + l.append(py.builtin.builtins.AssertionError) + py.builtin.builtins.AssertionError = assertion.AssertionError if compile: l = oldbuiltins.setdefault('compile', []) - l.append(cpy_builtin.compile) - cpy_builtin.compile = py.code.compile + l.append(py.builtin.builtins.compile) + py.builtin.builtins.compile = py.code.compile def unpatch_builtins(assertion=True, compile=True): """ remove compile and AssertionError builtins from Python builtins. """ if assertion: - cpy_builtin.AssertionError = oldbuiltins['AssertionError'].pop() + py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop() if compile: - cpy_builtin.compile = oldbuiltins['compile'].pop() + py.builtin.builtins.compile = oldbuiltins['compile'].pop() + +def getrawcode(obj): + """ return code object for given function. """ + obj = getattr(obj, 'im_func', obj) + obj = getattr(obj, 'func_code', obj) + obj = getattr(obj, 'f_code', obj) + obj = getattr(obj, '__code__', obj) + return obj + diff --git a/py/code/source.py b/py/code/source.py index 90527f78d..079486ec7 100644 --- a/py/code/source.py +++ b/py/code/source.py @@ -17,7 +17,7 @@ class Source(object): partlines = [] if isinstance(part, Source): partlines = part.lines - elif isinstance(part, (unicode, str)): + elif isinstance(part, py.builtin.basestring): partlines = part.split('\n') if rstrip: while partlines: @@ -164,7 +164,8 @@ class Source(object): def __str__(self): return "\n".join(self.lines) - def compile(self, filename=None, mode='exec', flag=generators.compiler_flag, + def compile(self, filename=None, mode='exec', + flag=generators.compiler_flag, dont_inherit=0, _genframe=None): """ return compiled code object. if filename is None invent an artificial filename which displays @@ -245,10 +246,7 @@ class MyStr(str): """ custom string which allows to add attributes. """ def findsource(obj): - if hasattr(obj, 'func_code'): - obj = obj.func_code - elif hasattr(obj, 'f_code'): - obj = obj.f_code + obj = py.code.getrawcode(obj) try: fullsource = obj.co_filename.__source__ except AttributeError: @@ -259,7 +257,7 @@ def findsource(obj): except: return None, None source = Source() - source.lines = map(str.rstrip, sourcelines) + source.lines = [line.rstrip() for line in sourcelines] return source, lineno else: lineno = obj.co_firstlineno - 1 @@ -267,10 +265,7 @@ def findsource(obj): def getsource(obj, **kwargs): - if hasattr(obj, 'func_code'): - obj = obj.func_code - elif hasattr(obj, 'f_code'): - obj = obj.f_code + obj = py.code.getrawcode(obj) try: fullsource = obj.co_filename.__source__ except AttributeError: @@ -304,8 +299,12 @@ def deindent(lines, offset=None): yield line + '\n' while True: yield '' - - readline = readline_generator(lines).next + + r = readline_generator(lines) + try: + readline = r.next + except AttributeError: + readline = r.__next__ try: for _, _, (sline, _), (eline, _), _ in tokenize.generate_tokens(readline): diff --git a/py/code/testing/test_assertion.py b/py/code/testing/test_assertion.py index 9ecce2601..004444a56 100644 --- a/py/code/testing/test_assertion.py +++ b/py/code/testing/test_assertion.py @@ -1,5 +1,7 @@ import py -from py.__.code.assertion import View +from py.__.code._assertion import View +def exvalue(): + return py.std.sys.exc_info()[1] def setup_module(mod): py.code.patch_builtins(assertion=True, compile=False) @@ -13,14 +15,16 @@ def f(): def test_assert(): try: assert f() == 3 - except AssertionError, e: + 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: + except AssertionError: + e = exvalue() assert e.msg == 'hello' def test_assert_within_finally(): @@ -47,7 +51,8 @@ def test_assert_multiline_1(): try: assert (f() == 3) - except AssertionError, e: + except AssertionError: + e = exvalue() s = str(e) assert s.startswith('assert 2 == 3\n') @@ -55,7 +60,8 @@ def test_assert_multiline_2(): try: assert (f() == (4, 3)[-1]) - except AssertionError, e: + except AssertionError: + e = exvalue() s = str(e) assert s.startswith('assert 2 ==') @@ -65,7 +71,8 @@ def test_assert_non_string_message(): return "hello" try: assert 0 == 1, A() - except AssertionError, e: + except AssertionError: + e = exvalue() assert e.msg == "hello" @@ -78,7 +85,8 @@ def bug_test_assert_repr(): v = WeirdRepr() try: assert v == 1 - except AssertionError, e: + except AssertionError: + e = exvalue() assert e.msg.find('WeirdRepr') != -1 assert e.msg.find('second line') != -1 assert 0 @@ -86,7 +94,8 @@ def bug_test_assert_repr(): def test_assert_non_string(): try: assert 0, ['list'] - except AssertionError, e: + except AssertionError: + e = exvalue() assert e.msg.find("list") != -1 def test_assert_implicit_multiline(): @@ -94,7 +103,8 @@ def test_assert_implicit_multiline(): x = [1,2,3] assert x != [1, 2, 3] - except AssertionError, e: + except AssertionError: + e = exvalue() assert e.msg.find('assert [1, 2, 3] !=') != -1 diff --git a/py/code/testing/test_code.py b/py/code/testing/test_code.py index 82f478dfb..0f0e74616 100644 --- a/py/code/testing/test_code.py +++ b/py/code/testing/test_code.py @@ -1,6 +1,6 @@ from __future__ import generators import py -import sys, new +import sys from py.__.code.code import safe_repr def test_newcode(): @@ -64,12 +64,17 @@ def test_new_code_object_carries_filename_through(): filename = mystr("dummy") co = compile("hello\n", filename, 'exec') assert not isinstance(co.co_filename, mystr) - c2 = new.code(co.co_argcount, co.co_nlocals, co.co_stacksize, + 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) + 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(): @@ -162,20 +167,22 @@ class TestSafeRepr: return "<%s>" %(self.name) try: s = safe_repr(Function()) - except Exception, e: + except Exception: py.test.fail("saferepr failed for newstyle class") def test_builtin_patch_unpatch(monkeypatch): - import __builtin__ as cpy_builtin + cpy_builtin = py.builtin.builtins comp = cpy_builtin.compile def mycompile(*args, **kwargs): return comp(*args, **kwargs) - monkeypatch.setattr(cpy_builtin, 'AssertionError', None) + class Sub(AssertionError): + pass + monkeypatch.setattr(cpy_builtin, 'AssertionError', Sub) monkeypatch.setattr(cpy_builtin, 'compile', mycompile) py.code.patch_builtins() - assert cpy_builtin.AssertionError + assert cpy_builtin.AssertionError != Sub assert cpy_builtin.compile != mycompile py.code.unpatch_builtins() - assert cpy_builtin.AssertionError is None + assert cpy_builtin.AssertionError is Sub assert cpy_builtin.compile == mycompile diff --git a/py/code/testing/test_excinfo.py b/py/code/testing/test_excinfo.py index 720cab1e7..281997aed 100644 --- a/py/code/testing/test_excinfo.py +++ b/py/code/testing/test_excinfo.py @@ -29,12 +29,11 @@ def test_excinfo_getstatement(): f() except ValueError: excinfo = py.code.ExceptionInfo() - linenumbers = [f.func_code.co_firstlineno-1+3, - f.func_code.co_firstlineno-1+1, - g.func_code.co_firstlineno-1+1,] + 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] - print l[0].frame.statement assert foundlinenumbers == linenumbers #for x in info: # print "%s:%d %s" %(x.path.relto(root), x.lineno, x.statement) @@ -91,10 +90,10 @@ class TestTraceback_f_g_h: xyz() """) try: - exec source.compile() + exec (source.compile()) except NameError: tb = py.code.ExceptionInfo().traceback - print tb[-1].getsource() + print (tb[-1].getsource()) s = str(tb[-1].getsource()) assert s.startswith("def xyz():\n try:") assert s.endswith("except somenoname:") @@ -111,7 +110,6 @@ class TestTraceback_f_g_h: def test_traceback_cut_excludepath(self, testdir): p = testdir.makepyfile("def f(): raise ValueError") excinfo = py.test.raises(ValueError, "p.pyimport().f()") - print excinfo.traceback pydir = py.path.local(py.__file__).dirpath() newtraceback = excinfo.traceback.cut(excludepath=pydir) assert len(newtraceback) == 1 @@ -138,7 +136,7 @@ class TestTraceback_f_g_h: def reraise_me(): import sys exc, val, tb = sys.exc_info() - raise exc, val, tb + py.builtin._reraise(exc, val, tb) def f(n): try: do_stuff() @@ -214,7 +212,6 @@ def test_excinfo_repr(): def test_excinfo_str(): excinfo = py.test.raises(ValueError, h) s = str(excinfo) - print s assert s.startswith(__file__[:-1]) # pyc file assert s.endswith("ValueError") assert len(s.split(":")) >= 3 # on windows it's 4 @@ -225,7 +222,7 @@ def test_excinfo_errisinstance(): def test_excinfo_no_sourcecode(): try: - exec "raise ValueError()" + exec ("raise ValueError()") except ValueError: excinfo = py.code.ExceptionInfo() s = str(excinfo.traceback[-1]) @@ -273,7 +270,7 @@ class TestFormattedExcinfo: def excinfo_from_exec(self, source): source = py.code.Source(source).strip() try: - exec source.compile() + exec (source.compile()) except KeyboardInterrupt: raise except: @@ -303,7 +300,6 @@ class TestFormattedExcinfo: pr = FormattedExcinfo() source = pr._getentrysource(excinfo.traceback[-1]) lines = pr.get_source(source, 1, excinfo) - print lines assert lines == [ ' def f():', '> assert 0', @@ -315,7 +311,7 @@ class TestFormattedExcinfo: pr = FormattedExcinfo() co = compile("raise ValueError()", "", "exec") try: - exec co + exec (co) except ValueError: excinfo = py.code.ExceptionInfo() repr = pr.repr_excinfo(excinfo) @@ -328,7 +324,7 @@ a = 1 raise ValueError() """, "", "exec") try: - exec co + exec (co) except ValueError: excinfo = py.code.ExceptionInfo() repr = pr.repr_excinfo(excinfo) @@ -387,7 +383,6 @@ raise ValueError() loc = {'y': 5, 'z': 7, 'x': 3, '__builtins__': __builtins__} reprlocals = p.repr_locals(loc) assert reprlocals.lines - print reprlocals.lines assert reprlocals.lines[0] == '__builtins__ = ' assert reprlocals.lines[1] == 'x = 3' assert reprlocals.lines[2] == 'y = 5' @@ -402,7 +397,6 @@ raise ValueError() excinfo.traceback = excinfo.traceback.filter() p = FormattedExcinfo() reprtb = p.repr_traceback_entry(excinfo.traceback[-1]) - print reprtb # test as intermittent entry lines = reprtb.lines diff --git a/py/code/testing/test_source.py b/py/code/testing/test_source.py index ffb00200c..5c07ca36b 100644 --- a/py/code/testing/test_source.py +++ b/py/code/testing/test_source.py @@ -19,10 +19,16 @@ def test_source_str_function(): """, rstrip=True) assert str(x) == "\n3" -def test_unicode(): +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) @@ -119,17 +125,13 @@ class TestSourceParsingAndCompiling: def test_compile(self): co = py.code.compile("x=3") - exec co - assert x == 3 - - def test_compile_unicode(self): - co = py.code.compile(unicode('u"\xc3\xa5"', 'utf8'), mode='eval') - val = eval(co) - assert isinstance(val, unicode) + d = {} + exec (co, d) + assert d['x'] == 3 def test_compile_and_getsource_simple(self): co = py.code.compile("x=3") - exec co + exec (co) source = py.code.Source(co) assert str(source) == "x=3" @@ -191,7 +193,7 @@ class TestSourceParsingAndCompiling: def test_compile_and_getsource(self): co = self.source.compile() - exec co + py.builtin.exec_(co, globals()) f(7) excinfo = py.test.raises(AssertionError, "f(6)") frame = excinfo.traceback[-1].frame @@ -267,7 +269,7 @@ def test_getfuncsource_dynamic(): def g(): pass """ co = py.code.compile(source) - exec co + 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' @@ -369,7 +371,7 @@ def test_getfslineno(): fname = fname[:-1] assert fspath == py.path.local(fname) - assert lineno == f.func_code.co_firstlineno-1 # see findsource + assert lineno == py.code.getrawcode(f).co_firstlineno-1 # see findsource class A(object): pass diff --git a/py/io/capture.py b/py/io/capture.py index ce61ecd54..dcbe524d6 100644 --- a/py/io/capture.py +++ b/py/io/capture.py @@ -9,10 +9,11 @@ except ImportError: from StringIO import StringIO class TextIO(StringIO): - def write(self, data): - if not isinstance(data, unicode): - data = unicode(data, getattr(self, '_encoding', 'UTF-8')) - StringIO.write(self, data) + if sys.version_info < (3,0): + def write(self, data): + if not isinstance(data, unicode): + data = unicode(data, getattr(self, '_encoding', 'UTF-8')) + StringIO.write(self, data) try: from io import BytesIO diff --git a/py/io/terminalwriter.py b/py/io/terminalwriter.py index 77954c132..9320fd43c 100644 --- a/py/io/terminalwriter.py +++ b/py/io/terminalwriter.py @@ -147,7 +147,7 @@ class TerminalWriter(object): self.stringio = file = py.io.TextIO() else: file = py.std.sys.stdout - elif callable(file): + elif hasattr(file, '__call__'): file = WriteFile(file) self._file = file self.fullwidth = get_terminal_width() @@ -202,7 +202,7 @@ class TerminalWriter(object): self._file.flush() def _getbytestring(self, s): - if isinstance(s, unicode): + if sys.version_info < (3,0) and isinstance(s, unicode): return s.encode(self._encoding) elif not isinstance(s, str): return str(s) diff --git a/py/path/common.py b/py/path/common.py index 26e5df1f0..9fb34f7b4 100644 --- a/py/path/common.py +++ b/py/path/common.py @@ -58,7 +58,7 @@ class Checkers: raise TypeError( "no %r checker available for %r" % (name, self.path)) try: - if meth.im_func.func_code.co_argcount > 1: + if py.code.getrawcode(meth).co_argcount > 1: if (not meth(value)) ^ invert: return False else: diff --git a/py/path/local.py b/py/path/local.py index 5d5a84a61..cac72aac5 100644 --- a/py/path/local.py +++ b/py/path/local.py @@ -144,6 +144,20 @@ class LocalPath(FSBase): def __hash__(self): return hash(self.strpath) + def __eq__(self, other): + s1 = str(self) + s2 = str(other) + if iswin32: + s1 = s1.lower() + s2 = s2.lower() + return s1 == s2 + + def __ne__(self, other): + return not (self == other) + + def __lt__(self, other): + return str(self) < str(other) + def remove(self, rec=1): """ remove a file or directory (or a directory tree if rec=1). """ if self.check(dir=1, link=0): @@ -285,14 +299,6 @@ class LocalPath(FSBase): obj.strpath = os.path.normpath(strpath) return obj - def __eq__(self, other): - s1 = str(self) - s2 = str(other) - if iswin32: - s1 = s1.lower() - s2 = s2.lower() - return s1 == s2 - def open(self, mode='r'): """ return an opened file with the given mode. """ return py.error.checked_call(open, self.strpath, mode) @@ -308,7 +314,7 @@ class LocalPath(FSBase): childurl = self.join(name) if fil is None or fil(childurl): res.append(childurl) - if callable(sort): + if hasattr(sort, '__call__'): res.sort(sort) elif sort: res.sort() @@ -762,7 +768,7 @@ def autopath(globs=None): __file__ = globs['__file__'] except KeyError: if not sys.argv[0]: - raise ValueError, "cannot compute autopath in interactive mode" + raise ValueError("cannot compute autopath in interactive mode") __file__ = os.path.abspath(sys.argv[0]) ret = py.path.local(__file__) diff --git a/py/test/cmdline.py b/py/test/cmdline.py index f34f711f5..5ee1ce8ce 100644 --- a/py/test/cmdline.py +++ b/py/test/cmdline.py @@ -1,4 +1,5 @@ import py +import sys # # main entry point @@ -6,7 +7,7 @@ import py def main(args=None): if args is None: - args = py.std.sys.argv[1:] + args = sys.argv[1:] config = py.test.config try: config.parse(args) @@ -15,7 +16,8 @@ def main(args=None): exitstatus = session.main() config.pluginmanager.do_unconfigure(config) raise SystemExit(exitstatus) - except config.Error, e: - py.std.sys.stderr.write("ERROR: %s\n" %(e.args[0],)) + except config.Error: + e = sys.exc_info()[1] + sys.stderr.write("ERROR: %s\n" %(e.args[0],)) raise SystemExit(3) diff --git a/py/test/collect.py b/py/test/collect.py index 722f8e0c8..894af904c 100644 --- a/py/test/collect.py +++ b/py/test/collect.py @@ -40,7 +40,8 @@ class Node(object): # def __getstate__(self): return (self.name, self.parent) - def __setstate__(self, (name, parent)): + def __setstate__(self, nameparent): + name, parent = nameparent try: colitems = parent._memocollect() except KeyboardInterrupt: @@ -92,7 +93,7 @@ class Node(object): exattrname = "_ex_" + attrname failure = getattr(self, exattrname, None) if failure is not None: - raise failure[0], failure[1], failure[2] + py.builtin._reraise(failure[0], failure[1], failure[2]) if hasattr(self, attrname): return getattr(self, attrname) try: diff --git a/py/test/config.py b/py/test/config.py index a3a2cd3f5..083f61e0d 100644 --- a/py/test/config.py +++ b/py/test/config.py @@ -1,5 +1,5 @@ import py, os -from conftesthandle import Conftest +from py.__.test.conftesthandle import Conftest from py.__.test import parseopt @@ -289,7 +289,9 @@ def gettopdir(args): parent directory of the root package is returned. """ args = [py.path.local(arg) for arg in args] - p = reduce(py.path.local.common, args) + p = args and args[0] or None + for x in args[1:]: + p = p.common(x) assert p, "cannot determine common basedir of %s" %(args,) pkgdir = p.pypkgpath() if pkgdir is None: diff --git a/py/test/conftesthandle.py b/py/test/conftesthandle.py index 4326c3789..6003e5ecf 100644 --- a/py/test/conftesthandle.py +++ b/py/test/conftesthandle.py @@ -64,7 +64,7 @@ class Conftest(object): return mod, getattr(mod, name) except AttributeError: continue - raise KeyError, name + raise KeyError(name) def importconftest(self, conftestpath): # Using caching here looks redundant since ultimately diff --git a/py/test/funcargs.py b/py/test/funcargs.py index 56b8f1865..0e21bdcc1 100644 --- a/py/test/funcargs.py +++ b/py/test/funcargs.py @@ -1,9 +1,11 @@ import py def getfuncargnames(function): - argnames = py.std.inspect.getargs(function.func_code)[0] - startindex = hasattr(function, 'im_self') and 1 or 0 - numdefaults = len(function.func_defaults or ()) + argnames = py.std.inspect.getargs(py.code.getrawcode(function))[0] + startindex = py.std.inspect.ismethod(function) and 1 or 0 + defaults = getattr(function, 'func_defaults', + getattr(function, '__defaults__', None)) or () + numdefaults = len(defaults) if numdefaults: return argnames[startindex:-numdefaults] return argnames[startindex:] diff --git a/py/test/outcome.py b/py/test/outcome.py index a62630c03..94bab7541 100644 --- a/py/test/outcome.py +++ b/py/test/outcome.py @@ -93,14 +93,13 @@ def raises(ExpectedException, *args, **kwargs): #print "raises frame scope: %r" % frame.f_locals try: code = py.code.Source(code).compile() - exec code in frame.f_globals, loc + py.builtin.exec_(code, frame.f_globals, loc) # XXX didn'T mean f_globals == f_locals something special? # this is destroyed here ... except ExpectedException: return py.code.ExceptionInfo() else: func = args[0] - assert callable try: func(*args[1:], **kwargs) except ExpectedException: diff --git a/py/test/plugin/pytest__pytest.py b/py/test/plugin/pytest__pytest.py index 513a721f6..536cce9c1 100644 --- a/py/test/plugin/pytest__pytest.py +++ b/py/test/plugin/pytest__pytest.py @@ -64,11 +64,11 @@ class HookRecorder: # errors on wrong input arguments, using # *args/**kwargs delays this and gives errors # elsewhere - exec py.code.compile(""" + exec (py.code.compile(""" def %(name)s%(fspec)s: self._recorder.calls.append( ParsedCall(%(name)r, locals())) - """ % locals()) + """ % locals())) return locals()[name] def getcalls(self, names): diff --git a/py/test/plugin/pytest_assertion.py b/py/test/plugin/pytest_assertion.py index eb3cdbde5..65c55f3aa 100644 --- a/py/test/plugin/pytest_assertion.py +++ b/py/test/plugin/pytest_assertion.py @@ -1,4 +1,5 @@ import py +import sys def pytest_addoption(parser): group = parser.getgroup("debugconfig") @@ -7,14 +8,18 @@ def pytest_addoption(parser): help="disable python assert expression reinterpretation."), def pytest_configure(config): + # XXX + if sys.version_info >= (3,0): + return + if not config.getvalue("noassert"): warn_about_missing_assertion() - config._oldassertion = py.std.__builtin__.AssertionError - py.std.__builtin__.AssertionError = py.code._AssertionError + config._oldassertion = py.builtin.builtins.AssertionError + py.builtin.builtins.AssertionError = py.code._AssertionError def pytest_unconfigure(config): if hasattr(config, '_oldassertion'): - py.std.__builtin__.AssertionError = config._oldassertion + py.builtin.builtins.AssertionError = config._oldassertion del config._oldassertion def warn_about_missing_assertion(): diff --git a/py/test/plugin/pytest_capture.py b/py/test/plugin/pytest_capture.py index e19de17ef..b9a57433e 100644 --- a/py/test/plugin/pytest_capture.py +++ b/py/test/plugin/pytest_capture.py @@ -275,12 +275,16 @@ class EncodedFile(object): def __init__(self, _stream, encoding): self._stream = _stream self.encoding = encoding - - def write(self, obj): - if isinstance(obj, unicode): + + if py.std.sys.version_info < (3,0): + def write(self, obj): + if isinstance(obj, unicode): + self._stream.write(obj.encode(self.encoding)) + else: + self._stream.write(obj) + else: + def write(self, obj): self._stream.write(obj.encode(self.encoding)) - else: - self._stream.write(obj) def writelines(self, linelist): data = ''.join(linelist) diff --git a/py/test/plugin/pytest_default.py b/py/test/plugin/pytest_default.py index 85cc78562..cd20274c2 100644 --- a/py/test/plugin/pytest_default.py +++ b/py/test/plugin/pytest_default.py @@ -95,7 +95,6 @@ def pytest_addoption(parser): def pytest_configure(config): fixoptions(config) setsession(config) - #xxxloadplugins(config) def fixoptions(config): if config.option.numprocesses: @@ -104,11 +103,6 @@ def fixoptions(config): if config.option.distload: config.option.dist = "load" -def xxxloadplugins(config): - for name in config.getvalue("plugin"): - print "importing", name - config.pluginmanager.import_plugin(name) - def setsession(config): val = config.getvalue if val("collectonly"): @@ -156,7 +150,7 @@ class TestDistOptions: config = testdir.parseconfigure("--tx=popen", "--tx", "ssh=xyz") xspecs = config.getxspecs() assert len(xspecs) == 2 - print xspecs + print(xspecs) assert xspecs[0].popen assert xspecs[1].ssh == "xyz" diff --git a/py/test/plugin/pytest_keyword.py b/py/test/plugin/pytest_keyword.py index 656b16ef9..37a3d1a78 100644 --- a/py/test/plugin/pytest_keyword.py +++ b/py/test/plugin/pytest_keyword.py @@ -55,7 +55,7 @@ class MarkerDecorator: self.kwargs = kwargs.copy() return self else: - if not len(args) == 1 or not hasattr(args[0], 'func_dict'): + if not len(args) == 1 or not hasattr(args[0], '__dict__'): raise TypeError("need exactly one function to decorate, " "got %r" %(args,)) func = args[0] diff --git a/py/test/plugin/pytest_pdb.py b/py/test/plugin/pytest_pdb.py index e049d8dbd..65c807ed1 100644 --- a/py/test/plugin/pytest_pdb.py +++ b/py/test/plugin/pytest_pdb.py @@ -52,7 +52,7 @@ class Pdb(py.std.pdb.Pdb): else: first = max(1, int(x) - 5) except: - print '*** Error in argument:', repr(arg) + print ('*** Error in argument: %s' % repr(arg)) return elif self.lineno is None: first = max(1, self.curframe.f_lineno - 5) @@ -68,7 +68,7 @@ class Pdb(py.std.pdb.Pdb): line = self._getline(filename, lineno) # end difference from normal do_line if not line: - print '[EOF]' + print ('[EOF]') break else: s = repr(lineno).rjust(3) @@ -77,7 +77,7 @@ class Pdb(py.std.pdb.Pdb): else: s = s + ' ' if lineno == self.curframe.f_lineno: s = s + '->' - print s + '\t' + line, + sys.stdout.write(s + '\t' + line) self.lineno = lineno except KeyboardInterrupt: pass diff --git a/py/test/plugin/pytest_pytester.py b/py/test/plugin/pytest_pytester.py index a7d20d0f3..96ab136b7 100644 --- a/py/test/plugin/pytest_pytester.py +++ b/py/test/plugin/pytest_pytester.py @@ -6,8 +6,8 @@ import py import sys, os import inspect from py.__.test.config import Config as pytestConfig -import hookspec -import subprocess +from py.__.test.plugin import hookspec +from py.builtin import print_ pytest_plugins = '_pytest' @@ -94,7 +94,7 @@ class TmpTestdir: self._olddir = old def _makefile(self, ext, args, kwargs): - items = kwargs.items() + items = list(kwargs.items()) if args: source = "\n".join(map(str, args)) basename = self.request.function.__name__ @@ -249,7 +249,7 @@ class TmpTestdir: p.write("import py ; pytest_plugins = %r" % plugins) else: if self.plugins: - print "warning, ignoring reusing existing con", p + print ("warning, ignoring reusing existing %s" % p) def popen(self, cmdargs, stdout, stderr, **kw): if not hasattr(py.std, 'subprocess'): @@ -274,7 +274,7 @@ class TmpTestdir: cmdargs = map(str, cmdargs) p1 = py.path.local("stdout") p2 = py.path.local("stderr") - print "running", cmdargs, "curdir=", py.path.local() + print_("running", cmdargs, "curdir=", py.path.local()) f1 = p1.open("w") f2 = p2.open("w") popen = self.popen(cmdargs, stdout=f1, stderr=f2, @@ -480,17 +480,17 @@ class LineMatcher: while lines1: nextline = lines1.pop(0) if line == nextline: - print "exact match:", repr(line) + print_("exact match:", repr(line)) break elif fnmatch(nextline, line): - print "fnmatch:", repr(line) - print " with:", repr(nextline) + print_("fnmatch:", repr(line)) + print_(" with:", repr(nextline)) break else: if not nomatchprinted: - print "nomatch:", repr(line) + print_("nomatch:", repr(line)) nomatchprinted = True - print " and:", repr(nextline) + print_(" and:", repr(nextline)) extralines.append(nextline) else: if line != nextline: diff --git a/py/test/plugin/pytest_runner.py b/py/test/plugin/pytest_runner.py index 3fb32eb4b..44c9364f7 100644 --- a/py/test/plugin/pytest_runner.py +++ b/py/test/plugin/pytest_runner.py @@ -249,7 +249,7 @@ class SetupState(object): if colitem is None, this will add a finalizer that is called at the end of teardown_all(). """ - assert callable(finalizer) + assert hasattr(finalizer, '__call__') #assert colitem in self.stack self._finalizers.setdefault(colitem, []).append(finalizer) diff --git a/py/test/plugin/pytest_unittest.py b/py/test/plugin/pytest_unittest.py index 1340cae99..28f32ccff 100644 --- a/py/test/plugin/pytest_unittest.py +++ b/py/test/plugin/pytest_unittest.py @@ -128,7 +128,6 @@ def test_teardown(testdir): """) reprec = testdir.inline_run(testpath) passed, skipped, failed = reprec.countoutcomes() - print "COUNTS", passed, skipped, failed assert failed == 0, failed assert passed == 2 assert passed + skipped + failed == 2 diff --git a/py/test/pluginmanager.py b/py/test/pluginmanager.py index a4c577f51..453345830 100644 --- a/py/test/pluginmanager.py +++ b/py/test/pluginmanager.py @@ -44,7 +44,7 @@ class PluginManager(object): def unregister(self, plugin): self.hook.pytest_plugin_unregistered(plugin=plugin) self.comregistry.unregister(plugin) - for name, value in self.impname2plugin.items(): + for name, value in list(self.impname2plugin.items()): if value == plugin: del self.impname2plugin[name] @@ -100,7 +100,8 @@ class PluginManager(object): mod = importplugin(modname) except KeyboardInterrupt: raise - except Skipped, e: + except Skipped: + e = py.std.sys.exc_info()[1] self._warn("could not import plugin %r, reason: %r" %( (modname, e.msg))) else: @@ -109,7 +110,7 @@ class PluginManager(object): self.consider_module(mod) def _warn(self, msg): - print "===WARNING=== %s" % (msg,) + print ("===WARNING=== %s" % (msg,)) def _checkplugin(self, plugin): # ===================================================== @@ -217,12 +218,14 @@ def canonical_importname(name): def importplugin(importspec): try: return __import__(importspec) - except ImportError, e: + except ImportError: + e = py.std.sys.exc_info()[1] if str(e).find(importspec) == -1: raise try: return __import__("py.__.test.plugin.%s" %(importspec), None, None, '__doc__') - except ImportError, e: + except ImportError: + e = py.std.sys.exc_info()[1] if str(e).find(importspec) == -1: raise #print "syspath:", py.std.sys.path @@ -236,8 +239,8 @@ def isgenerichook(name): name.startswith("pytest_funcarg__") def getargs(func): - args = py.std.inspect.getargs(func.func_code)[0] - startindex = hasattr(func, 'im_self') and 1 or 0 + args = py.std.inspect.getargs(py.code.getrawcode(func))[0] + startindex = py.std.inspect.ismethod(func) and 1 or 0 return args[startindex:] def collectattr(obj, prefixes=("pytest_",)): @@ -250,7 +253,7 @@ def collectattr(obj, prefixes=("pytest_",)): def formatdef(func): return "%s%s" %( - func.func_name, + func.__name__, py.std.inspect.formatargspec(*py.std.inspect.getargspec(func)) ) @@ -277,7 +280,7 @@ if __name__ == "__main__": text = name2text[name] if name[0] == "_": continue - print "%-20s %s" % (name, text.split("\n")[0]) + print ("%-20s %s" % (name, text.split("\n")[0])) #text = py.std.textwrap.wrap(name2text[name], # width = 80, diff --git a/py/test/pycollect.py b/py/test/pycollect.py index d977c0ba5..0be730b43 100644 --- a/py/test/pycollect.py +++ b/py/test/pycollect.py @@ -92,7 +92,7 @@ class PyCollectorMixin(PyobjMixin, py.test.collect.Collector): if l is not None: return l name2items = self._buildname2items() - colitems = name2items.values() + colitems = list(name2items.values()) colitems.sort(key=lambda item: item.reportinfo()[:2]) return colitems @@ -128,7 +128,7 @@ class PyCollectorMixin(PyobjMixin, py.test.collect.Collector): if res is not None: return res return self.Class(name, parent=self) - elif self.funcnamefilter(name) and callable(obj): + elif self.funcnamefilter(name) and hasattr(obj, '__call__'): res = self._deprecated_join(name) if res is not None: return res @@ -237,7 +237,7 @@ class FunctionMixin(PyobjMixin): def setup(self): """ perform setup for this test function. """ - if hasattr(self.obj, 'im_self'): + if py.std.inspect.ismethod(self.obj): name = 'setup_method' else: name = 'setup_function' @@ -345,7 +345,8 @@ class Function(FunctionMixin, py.test.collect.Item): def readkeywords(self): d = super(Function, self).readkeywords() - d.update(self.obj.func_dict) + d.update(getattr(self.obj, '__dict__', + getattr(self.obj, 'func_dict', {}))) return d def runtest(self): @@ -372,7 +373,9 @@ class Function(FunctionMixin, py.test.collect.Item): def __ne__(self, other): return not self == other - + + def __hash__(self): + return hash((self.parent, self.name)) def hasinit(obj): init = getattr(obj, '__init__', None)