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
This commit is contained in:
holger krekel 2009-08-28 19:16:15 +02:00
parent 5e95feaf90
commit 783e6aeb4d
33 changed files with 218 additions and 164 deletions

View File

@ -130,6 +130,7 @@ initpkg(__name__,
'code.ExceptionInfo' : ('./code/code.py', 'ExceptionInfo'), 'code.ExceptionInfo' : ('./code/code.py', 'ExceptionInfo'),
'code.Traceback' : ('./code/code.py', 'Traceback'), 'code.Traceback' : ('./code/code.py', 'Traceback'),
'code.getfslineno' : ('./code/source.py', 'getfslineno'), 'code.getfslineno' : ('./code/source.py', 'getfslineno'),
'code.getrawcode' : ('./code/code.py', 'getrawcode'),
'code.patch_builtins' : ('./code/code.py', 'patch_builtins'), 'code.patch_builtins' : ('./code/code.py', 'patch_builtins'),
'code.unpatch_builtins' : ('./code/code.py', 'unpatch_builtins'), 'code.unpatch_builtins' : ('./code/code.py', 'unpatch_builtins'),
'code._AssertionError' : ('./code/assertion.py', 'AssertionError'), 'code._AssertionError' : ('./code/assertion.py', 'AssertionError'),
@ -146,6 +147,8 @@ initpkg(__name__,
'builtin.print_' : ('./builtin/builtin31.py', 'print_'), 'builtin.print_' : ('./builtin/builtin31.py', 'print_'),
'builtin._reraise' : ('./builtin/builtin31.py', '_reraise'), 'builtin._reraise' : ('./builtin/builtin31.py', '_reraise'),
'builtin.exec_' : ('./builtin/builtin31.py', 'exec_'), 'builtin.exec_' : ('./builtin/builtin31.py', 'exec_'),
'builtin.basestring' : ('./builtin/builtin31.py', 'basestring'),
'builtin.builtins' : ('./builtin/builtin31.py', 'builtins'),
# gateways into remote contexts # gateways into remote contexts
'execnet.__doc__' : ('./execnet/__init__.py', '__doc__'), 'execnet.__doc__' : ('./execnet/__init__.py', '__doc__'),

View File

@ -3,6 +3,7 @@ py lib plugins and plugin call management
""" """
import py import py
import inspect
class MultiCall: class MultiCall:
""" execute a call into multiple python functions/methods. """ """ execute a call into multiple python functions/methods. """
@ -39,10 +40,9 @@ class MultiCall:
pass # might be optional param pass # might be optional param
return kwargs return kwargs
def varnames(rawcode): def varnames(func):
ismethod = hasattr(rawcode, 'im_self') ismethod = inspect.ismethod(func)
rawcode = getattr(rawcode, 'im_func', rawcode) rawcode = py.code.getrawcode(func)
rawcode = getattr(rawcode, 'func_code', rawcode)
try: try:
return rawcode.co_varnames[ismethod:] return rawcode.co_varnames[ismethod:]
except AttributeError: except AttributeError:

View File

@ -19,7 +19,7 @@ def searchpy(current):
# if p == current: # if p == current:
# return True # return True
if current != sys.path[0]: # if we are already first, then ok 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) sys.path.insert(0, current)
return True return True
current = opd(current) current = opd(current)
@ -34,4 +34,4 @@ if not searchpy(abspath(os.curdir)):
import py import py
if __name__ == '__main__': if __name__ == '__main__':
print "py lib is at", py.__file__ print ("py lib is at %s" % py.__file__)

View File

@ -2,7 +2,12 @@ import sys
if sys.version_info >= (3, 0): if sys.version_info >= (3, 0):
exec ("print_ = print ; exec_=exec") exec ("print_ = print ; exec_=exec")
import builtins
basestring = str
else: else:
basestring = basestring
import __builtin__ as builtins
def print_(*args, **kwargs): def print_(*args, **kwargs):
""" minimal backport of py3k print statement. """ """ minimal backport of py3k print statement. """
sep = 'sep' in kwargs and kwargs.pop('sep') or ' ' sep = 'sep' in kwargs and kwargs.pop('sep') or ' '

View File

@ -75,7 +75,7 @@ def test_print_simple():
f = py.io.TextIO() f = py.io.TextIO()
print_("hello", "world", file=f) print_("hello", "world", file=f)
s = f.getvalue() s = f.getvalue()
assert s == u"hello world\n" assert s == "hello world\n"
py.test.raises(TypeError, "print_(hello=3)") py.test.raises(TypeError, "print_(hello=3)")
def test_reraise(): def test_reraise():

View File

@ -1,19 +1,17 @@
import py import py
import sys import sys
builtin_repr = repr
try: try:
import repr import repr
except ImportError: except ImportError:
import reprlib as repr import reprlib as repr
import __builtin__ as cpy_builtin
builtin_repr = cpy_builtin.repr
class Code(object): class Code(object):
""" wrapper around Python code objects """ """ wrapper around Python code objects """
def __init__(self, rawcode): def __init__(self, rawcode):
rawcode = getattr(rawcode, 'im_func', rawcode) rawcode = py.code.getrawcode(rawcode)
rawcode = getattr(rawcode, 'func_code', rawcode)
self.raw = rawcode self.raw = rawcode
try: try:
self.filename = rawcode.co_filename self.filename = rawcode.co_filename
@ -49,7 +47,7 @@ class Code(object):
for name in names: for name in names:
if name not in kwargs: if name not in kwargs:
kwargs[name] = getattr(self.raw, name) kwargs[name] = getattr(self.raw, name)
return py.std.new.code( arglist = [
kwargs['co_argcount'], kwargs['co_argcount'],
kwargs['co_nlocals'], kwargs['co_nlocals'],
kwargs['co_stacksize'], kwargs['co_stacksize'],
@ -64,7 +62,10 @@ class Code(object):
kwargs['co_lnotab'], kwargs['co_lnotab'],
kwargs['co_freevars'], kwargs['co_freevars'],
kwargs['co_cellvars'], kwargs['co_cellvars'],
) ]
if sys.version_info >= (3,0):
arglist.insert(1, kwargs['co_kwonlyargcount'])
return self.raw.__class__(*arglist)
def path(self): def path(self):
""" return a py.path.local object pointing to the source code """ """ 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 = self.f_locals.copy()
f_locals.update(vars) 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): def repr(self, object):
""" return a 'safe' (non-recursive, one-line) string repr for '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 """Reinterpret the failing statement and returns a detailed information
about what operations are performed.""" about what operations are performed."""
if self.exprinfo is None: if self.exprinfo is None:
from py.__.code import assertion from py.__.code import _assertion
source = str(self.statement).strip() 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): if not isinstance(x, str):
raise TypeError, "interpret returned non-string %r" % (x,) raise TypeError("interpret returned non-string %r" % (x,))
self.exprinfo = x self.exprinfo = x
return self.exprinfo return self.exprinfo
@ -358,7 +359,9 @@ class ExceptionInfo(object):
if tup is None: if tup is None:
tup = sys.exc_info() tup = sys.exc_info()
if exprinfo is None and isinstance(tup[1], py.code._AssertionError): 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 '): if exprinfo and exprinfo.startswith('assert '):
self._striptext = 'AssertionError: ' self._striptext = 'AssertionError: '
self._excinfo = tup self._excinfo = tup
@ -491,9 +494,10 @@ class FormattedExcinfo(object):
def repr_locals(self, locals): def repr_locals(self, locals):
if self.showlocals: if self.showlocals:
lines = [] lines = []
items = locals.items() keys = list(locals)
items.sort() keys.sort()
for name, value in items: for name in keys:
value = locals[name]
if name == '__builtins__': if name == '__builtins__':
lines.append("__builtins__ = <builtins>") lines.append("__builtins__ = <builtins>")
else: else:
@ -737,16 +741,25 @@ def patch_builtins(assertion=True, compile=True):
if assertion: if assertion:
from py.__.code import assertion from py.__.code import assertion
l = oldbuiltins.setdefault('AssertionError', []) l = oldbuiltins.setdefault('AssertionError', [])
l.append(cpy_builtin.AssertionError) l.append(py.builtin.builtins.AssertionError)
cpy_builtin.AssertionError = assertion.AssertionError py.builtin.builtins.AssertionError = assertion.AssertionError
if compile: if compile:
l = oldbuiltins.setdefault('compile', []) l = oldbuiltins.setdefault('compile', [])
l.append(cpy_builtin.compile) l.append(py.builtin.builtins.compile)
cpy_builtin.compile = py.code.compile py.builtin.builtins.compile = py.code.compile
def unpatch_builtins(assertion=True, compile=True): def unpatch_builtins(assertion=True, compile=True):
""" remove compile and AssertionError builtins from Python builtins. """ """ remove compile and AssertionError builtins from Python builtins. """
if assertion: if assertion:
cpy_builtin.AssertionError = oldbuiltins['AssertionError'].pop() py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop()
if compile: 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

View File

@ -17,7 +17,7 @@ class Source(object):
partlines = [] partlines = []
if isinstance(part, Source): if isinstance(part, Source):
partlines = part.lines partlines = part.lines
elif isinstance(part, (unicode, str)): elif isinstance(part, py.builtin.basestring):
partlines = part.split('\n') partlines = part.split('\n')
if rstrip: if rstrip:
while partlines: while partlines:
@ -164,7 +164,8 @@ class Source(object):
def __str__(self): def __str__(self):
return "\n".join(self.lines) 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): dont_inherit=0, _genframe=None):
""" return compiled code object. if filename is None """ return compiled code object. if filename is None
invent an artificial filename which displays invent an artificial filename which displays
@ -245,10 +246,7 @@ class MyStr(str):
""" custom string which allows to add attributes. """ """ custom string which allows to add attributes. """
def findsource(obj): def findsource(obj):
if hasattr(obj, 'func_code'): obj = py.code.getrawcode(obj)
obj = obj.func_code
elif hasattr(obj, 'f_code'):
obj = obj.f_code
try: try:
fullsource = obj.co_filename.__source__ fullsource = obj.co_filename.__source__
except AttributeError: except AttributeError:
@ -259,7 +257,7 @@ def findsource(obj):
except: except:
return None, None return None, None
source = Source() source = Source()
source.lines = map(str.rstrip, sourcelines) source.lines = [line.rstrip() for line in sourcelines]
return source, lineno return source, lineno
else: else:
lineno = obj.co_firstlineno - 1 lineno = obj.co_firstlineno - 1
@ -267,10 +265,7 @@ def findsource(obj):
def getsource(obj, **kwargs): def getsource(obj, **kwargs):
if hasattr(obj, 'func_code'): obj = py.code.getrawcode(obj)
obj = obj.func_code
elif hasattr(obj, 'f_code'):
obj = obj.f_code
try: try:
fullsource = obj.co_filename.__source__ fullsource = obj.co_filename.__source__
except AttributeError: except AttributeError:
@ -304,8 +299,12 @@ def deindent(lines, offset=None):
yield line + '\n' yield line + '\n'
while True: while True:
yield '' yield ''
readline = readline_generator(lines).next r = readline_generator(lines)
try:
readline = r.next
except AttributeError:
readline = r.__next__
try: try:
for _, _, (sline, _), (eline, _), _ in tokenize.generate_tokens(readline): for _, _, (sline, _), (eline, _), _ in tokenize.generate_tokens(readline):

View File

@ -1,5 +1,7 @@
import py 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): def setup_module(mod):
py.code.patch_builtins(assertion=True, compile=False) py.code.patch_builtins(assertion=True, compile=False)
@ -13,14 +15,16 @@ def f():
def test_assert(): def test_assert():
try: try:
assert f() == 3 assert f() == 3
except AssertionError, e: except AssertionError:
e = exvalue()
s = str(e) s = str(e)
assert s.startswith('assert 2 == 3\n') assert s.startswith('assert 2 == 3\n')
def test_assert_with_explicit_message(): def test_assert_with_explicit_message():
try: try:
assert f() == 3, "hello" assert f() == 3, "hello"
except AssertionError, e: except AssertionError:
e = exvalue()
assert e.msg == 'hello' assert e.msg == 'hello'
def test_assert_within_finally(): def test_assert_within_finally():
@ -47,7 +51,8 @@ def test_assert_multiline_1():
try: try:
assert (f() == assert (f() ==
3) 3)
except AssertionError, e: except AssertionError:
e = exvalue()
s = str(e) s = str(e)
assert s.startswith('assert 2 == 3\n') assert s.startswith('assert 2 == 3\n')
@ -55,7 +60,8 @@ def test_assert_multiline_2():
try: try:
assert (f() == (4, assert (f() == (4,
3)[-1]) 3)[-1])
except AssertionError, e: except AssertionError:
e = exvalue()
s = str(e) s = str(e)
assert s.startswith('assert 2 ==') assert s.startswith('assert 2 ==')
@ -65,7 +71,8 @@ def test_assert_non_string_message():
return "hello" return "hello"
try: try:
assert 0 == 1, A() assert 0 == 1, A()
except AssertionError, e: except AssertionError:
e = exvalue()
assert e.msg == "hello" assert e.msg == "hello"
@ -78,7 +85,8 @@ def bug_test_assert_repr():
v = WeirdRepr() v = WeirdRepr()
try: try:
assert v == 1 assert v == 1
except AssertionError, e: except AssertionError:
e = exvalue()
assert e.msg.find('WeirdRepr') != -1 assert e.msg.find('WeirdRepr') != -1
assert e.msg.find('second line') != -1 assert e.msg.find('second line') != -1
assert 0 assert 0
@ -86,7 +94,8 @@ def bug_test_assert_repr():
def test_assert_non_string(): def test_assert_non_string():
try: try:
assert 0, ['list'] assert 0, ['list']
except AssertionError, e: except AssertionError:
e = exvalue()
assert e.msg.find("list") != -1 assert e.msg.find("list") != -1
def test_assert_implicit_multiline(): def test_assert_implicit_multiline():
@ -94,7 +103,8 @@ def test_assert_implicit_multiline():
x = [1,2,3] x = [1,2,3]
assert x != [1, assert x != [1,
2, 3] 2, 3]
except AssertionError, e: except AssertionError:
e = exvalue()
assert e.msg.find('assert [1, 2, 3] !=') != -1 assert e.msg.find('assert [1, 2, 3] !=') != -1

View File

@ -1,6 +1,6 @@
from __future__ import generators from __future__ import generators
import py import py
import sys, new import sys
from py.__.code.code import safe_repr from py.__.code.code import safe_repr
def test_newcode(): def test_newcode():
@ -64,12 +64,17 @@ def test_new_code_object_carries_filename_through():
filename = mystr("dummy") filename = mystr("dummy")
co = compile("hello\n", filename, 'exec') co = compile("hello\n", filename, 'exec')
assert not isinstance(co.co_filename, mystr) 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_flags, co.co_code, co.co_consts,
co.co_names, co.co_varnames, co.co_names, co.co_varnames,
filename, filename,
co.co_name, co.co_firstlineno, co.co_lnotab, 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 assert c2.co_filename is filename
def test_code_gives_back_name_for_not_existing_file(): def test_code_gives_back_name_for_not_existing_file():
@ -162,20 +167,22 @@ class TestSafeRepr:
return "<%s>" %(self.name) return "<%s>" %(self.name)
try: try:
s = safe_repr(Function()) s = safe_repr(Function())
except Exception, e: except Exception:
py.test.fail("saferepr failed for newstyle class") py.test.fail("saferepr failed for newstyle class")
def test_builtin_patch_unpatch(monkeypatch): def test_builtin_patch_unpatch(monkeypatch):
import __builtin__ as cpy_builtin cpy_builtin = py.builtin.builtins
comp = cpy_builtin.compile comp = cpy_builtin.compile
def mycompile(*args, **kwargs): def mycompile(*args, **kwargs):
return comp(*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) monkeypatch.setattr(cpy_builtin, 'compile', mycompile)
py.code.patch_builtins() py.code.patch_builtins()
assert cpy_builtin.AssertionError assert cpy_builtin.AssertionError != Sub
assert cpy_builtin.compile != mycompile assert cpy_builtin.compile != mycompile
py.code.unpatch_builtins() py.code.unpatch_builtins()
assert cpy_builtin.AssertionError is None assert cpy_builtin.AssertionError is Sub
assert cpy_builtin.compile == mycompile assert cpy_builtin.compile == mycompile

View File

@ -29,12 +29,11 @@ def test_excinfo_getstatement():
f() f()
except ValueError: except ValueError:
excinfo = py.code.ExceptionInfo() excinfo = py.code.ExceptionInfo()
linenumbers = [f.func_code.co_firstlineno-1+3, linenumbers = [py.code.getrawcode(f).co_firstlineno-1+3,
f.func_code.co_firstlineno-1+1, py.code.getrawcode(f).co_firstlineno-1+1,
g.func_code.co_firstlineno-1+1,] py.code.getrawcode(g).co_firstlineno-1+1,]
l = list(excinfo.traceback) l = list(excinfo.traceback)
foundlinenumbers = [x.lineno for x in l] foundlinenumbers = [x.lineno for x in l]
print l[0].frame.statement
assert foundlinenumbers == linenumbers assert foundlinenumbers == linenumbers
#for x in info: #for x in info:
# print "%s:%d %s" %(x.path.relto(root), x.lineno, x.statement) # print "%s:%d %s" %(x.path.relto(root), x.lineno, x.statement)
@ -91,10 +90,10 @@ class TestTraceback_f_g_h:
xyz() xyz()
""") """)
try: try:
exec source.compile() exec (source.compile())
except NameError: except NameError:
tb = py.code.ExceptionInfo().traceback tb = py.code.ExceptionInfo().traceback
print tb[-1].getsource() print (tb[-1].getsource())
s = str(tb[-1].getsource()) s = str(tb[-1].getsource())
assert s.startswith("def xyz():\n try:") assert s.startswith("def xyz():\n try:")
assert s.endswith("except somenoname:") assert s.endswith("except somenoname:")
@ -111,7 +110,6 @@ class TestTraceback_f_g_h:
def test_traceback_cut_excludepath(self, testdir): def test_traceback_cut_excludepath(self, testdir):
p = testdir.makepyfile("def f(): raise ValueError") p = testdir.makepyfile("def f(): raise ValueError")
excinfo = py.test.raises(ValueError, "p.pyimport().f()") excinfo = py.test.raises(ValueError, "p.pyimport().f()")
print excinfo.traceback
pydir = py.path.local(py.__file__).dirpath() pydir = py.path.local(py.__file__).dirpath()
newtraceback = excinfo.traceback.cut(excludepath=pydir) newtraceback = excinfo.traceback.cut(excludepath=pydir)
assert len(newtraceback) == 1 assert len(newtraceback) == 1
@ -138,7 +136,7 @@ class TestTraceback_f_g_h:
def reraise_me(): def reraise_me():
import sys import sys
exc, val, tb = sys.exc_info() exc, val, tb = sys.exc_info()
raise exc, val, tb py.builtin._reraise(exc, val, tb)
def f(n): def f(n):
try: try:
do_stuff() do_stuff()
@ -214,7 +212,6 @@ def test_excinfo_repr():
def test_excinfo_str(): def test_excinfo_str():
excinfo = py.test.raises(ValueError, h) excinfo = py.test.raises(ValueError, h)
s = str(excinfo) s = str(excinfo)
print s
assert s.startswith(__file__[:-1]) # pyc file assert s.startswith(__file__[:-1]) # pyc file
assert s.endswith("ValueError") assert s.endswith("ValueError")
assert len(s.split(":")) >= 3 # on windows it's 4 assert len(s.split(":")) >= 3 # on windows it's 4
@ -225,7 +222,7 @@ def test_excinfo_errisinstance():
def test_excinfo_no_sourcecode(): def test_excinfo_no_sourcecode():
try: try:
exec "raise ValueError()" exec ("raise ValueError()")
except ValueError: except ValueError:
excinfo = py.code.ExceptionInfo() excinfo = py.code.ExceptionInfo()
s = str(excinfo.traceback[-1]) s = str(excinfo.traceback[-1])
@ -273,7 +270,7 @@ class TestFormattedExcinfo:
def excinfo_from_exec(self, source): def excinfo_from_exec(self, source):
source = py.code.Source(source).strip() source = py.code.Source(source).strip()
try: try:
exec source.compile() exec (source.compile())
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except:
@ -303,7 +300,6 @@ class TestFormattedExcinfo:
pr = FormattedExcinfo() pr = FormattedExcinfo()
source = pr._getentrysource(excinfo.traceback[-1]) source = pr._getentrysource(excinfo.traceback[-1])
lines = pr.get_source(source, 1, excinfo) lines = pr.get_source(source, 1, excinfo)
print lines
assert lines == [ assert lines == [
' def f():', ' def f():',
'> assert 0', '> assert 0',
@ -315,7 +311,7 @@ class TestFormattedExcinfo:
pr = FormattedExcinfo() pr = FormattedExcinfo()
co = compile("raise ValueError()", "", "exec") co = compile("raise ValueError()", "", "exec")
try: try:
exec co exec (co)
except ValueError: except ValueError:
excinfo = py.code.ExceptionInfo() excinfo = py.code.ExceptionInfo()
repr = pr.repr_excinfo(excinfo) repr = pr.repr_excinfo(excinfo)
@ -328,7 +324,7 @@ a = 1
raise ValueError() raise ValueError()
""", "", "exec") """, "", "exec")
try: try:
exec co exec (co)
except ValueError: except ValueError:
excinfo = py.code.ExceptionInfo() excinfo = py.code.ExceptionInfo()
repr = pr.repr_excinfo(excinfo) repr = pr.repr_excinfo(excinfo)
@ -387,7 +383,6 @@ raise ValueError()
loc = {'y': 5, 'z': 7, 'x': 3, '__builtins__': __builtins__} loc = {'y': 5, 'z': 7, 'x': 3, '__builtins__': __builtins__}
reprlocals = p.repr_locals(loc) reprlocals = p.repr_locals(loc)
assert reprlocals.lines assert reprlocals.lines
print reprlocals.lines
assert reprlocals.lines[0] == '__builtins__ = <builtins>' assert reprlocals.lines[0] == '__builtins__ = <builtins>'
assert reprlocals.lines[1] == 'x = 3' assert reprlocals.lines[1] == 'x = 3'
assert reprlocals.lines[2] == 'y = 5' assert reprlocals.lines[2] == 'y = 5'
@ -402,7 +397,6 @@ raise ValueError()
excinfo.traceback = excinfo.traceback.filter() excinfo.traceback = excinfo.traceback.filter()
p = FormattedExcinfo() p = FormattedExcinfo()
reprtb = p.repr_traceback_entry(excinfo.traceback[-1]) reprtb = p.repr_traceback_entry(excinfo.traceback[-1])
print reprtb
# test as intermittent entry # test as intermittent entry
lines = reprtb.lines lines = reprtb.lines

View File

@ -19,10 +19,16 @@ def test_source_str_function():
""", rstrip=True) """, rstrip=True)
assert str(x) == "\n3" assert str(x) == "\n3"
def test_unicode(): def test_unicode():
try:
unicode
except NameError:
return
x = Source(unicode("4")) x = Source(unicode("4"))
assert str(x) == "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(): def test_source_from_function():
source = py.code.Source(test_source_str_function) source = py.code.Source(test_source_str_function)
@ -119,17 +125,13 @@ class TestSourceParsingAndCompiling:
def test_compile(self): def test_compile(self):
co = py.code.compile("x=3") co = py.code.compile("x=3")
exec co d = {}
assert x == 3 exec (co, d)
assert d['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)
def test_compile_and_getsource_simple(self): def test_compile_and_getsource_simple(self):
co = py.code.compile("x=3") co = py.code.compile("x=3")
exec co exec (co)
source = py.code.Source(co) source = py.code.Source(co)
assert str(source) == "x=3" assert str(source) == "x=3"
@ -191,7 +193,7 @@ class TestSourceParsingAndCompiling:
def test_compile_and_getsource(self): def test_compile_and_getsource(self):
co = self.source.compile() co = self.source.compile()
exec co py.builtin.exec_(co, globals())
f(7) f(7)
excinfo = py.test.raises(AssertionError, "f(6)") excinfo = py.test.raises(AssertionError, "f(6)")
frame = excinfo.traceback[-1].frame frame = excinfo.traceback[-1].frame
@ -267,7 +269,7 @@ def test_getfuncsource_dynamic():
def g(): pass def g(): pass
""" """
co = py.code.compile(source) 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(f)).strip() == 'def f():\n raise ValueError'
assert str(py.code.Source(g)).strip() == 'def g(): pass' assert str(py.code.Source(g)).strip() == 'def g(): pass'
@ -369,7 +371,7 @@ def test_getfslineno():
fname = fname[:-1] fname = fname[:-1]
assert fspath == py.path.local(fname) 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): class A(object):
pass pass

View File

@ -9,10 +9,11 @@ except ImportError:
from StringIO import StringIO from StringIO import StringIO
class TextIO(StringIO): class TextIO(StringIO):
def write(self, data): if sys.version_info < (3,0):
if not isinstance(data, unicode): def write(self, data):
data = unicode(data, getattr(self, '_encoding', 'UTF-8')) if not isinstance(data, unicode):
StringIO.write(self, data) data = unicode(data, getattr(self, '_encoding', 'UTF-8'))
StringIO.write(self, data)
try: try:
from io import BytesIO from io import BytesIO

View File

@ -147,7 +147,7 @@ class TerminalWriter(object):
self.stringio = file = py.io.TextIO() self.stringio = file = py.io.TextIO()
else: else:
file = py.std.sys.stdout file = py.std.sys.stdout
elif callable(file): elif hasattr(file, '__call__'):
file = WriteFile(file) file = WriteFile(file)
self._file = file self._file = file
self.fullwidth = get_terminal_width() self.fullwidth = get_terminal_width()
@ -202,7 +202,7 @@ class TerminalWriter(object):
self._file.flush() self._file.flush()
def _getbytestring(self, s): def _getbytestring(self, s):
if isinstance(s, unicode): if sys.version_info < (3,0) and isinstance(s, unicode):
return s.encode(self._encoding) return s.encode(self._encoding)
elif not isinstance(s, str): elif not isinstance(s, str):
return str(s) return str(s)

View File

@ -58,7 +58,7 @@ class Checkers:
raise TypeError( raise TypeError(
"no %r checker available for %r" % (name, self.path)) "no %r checker available for %r" % (name, self.path))
try: try:
if meth.im_func.func_code.co_argcount > 1: if py.code.getrawcode(meth).co_argcount > 1:
if (not meth(value)) ^ invert: if (not meth(value)) ^ invert:
return False return False
else: else:

View File

@ -144,6 +144,20 @@ class LocalPath(FSBase):
def __hash__(self): def __hash__(self):
return hash(self.strpath) 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): def remove(self, rec=1):
""" remove a file or directory (or a directory tree if rec=1). """ """ remove a file or directory (or a directory tree if rec=1). """
if self.check(dir=1, link=0): if self.check(dir=1, link=0):
@ -285,14 +299,6 @@ class LocalPath(FSBase):
obj.strpath = os.path.normpath(strpath) obj.strpath = os.path.normpath(strpath)
return obj 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'): def open(self, mode='r'):
""" return an opened file with the given mode. """ """ return an opened file with the given mode. """
return py.error.checked_call(open, self.strpath, mode) return py.error.checked_call(open, self.strpath, mode)
@ -308,7 +314,7 @@ class LocalPath(FSBase):
childurl = self.join(name) childurl = self.join(name)
if fil is None or fil(childurl): if fil is None or fil(childurl):
res.append(childurl) res.append(childurl)
if callable(sort): if hasattr(sort, '__call__'):
res.sort(sort) res.sort(sort)
elif sort: elif sort:
res.sort() res.sort()
@ -762,7 +768,7 @@ def autopath(globs=None):
__file__ = globs['__file__'] __file__ = globs['__file__']
except KeyError: except KeyError:
if not sys.argv[0]: 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]) __file__ = os.path.abspath(sys.argv[0])
ret = py.path.local(__file__) ret = py.path.local(__file__)

View File

@ -1,4 +1,5 @@
import py import py
import sys
# #
# main entry point # main entry point
@ -6,7 +7,7 @@ import py
def main(args=None): def main(args=None):
if args is None: if args is None:
args = py.std.sys.argv[1:] args = sys.argv[1:]
config = py.test.config config = py.test.config
try: try:
config.parse(args) config.parse(args)
@ -15,7 +16,8 @@ def main(args=None):
exitstatus = session.main() exitstatus = session.main()
config.pluginmanager.do_unconfigure(config) config.pluginmanager.do_unconfigure(config)
raise SystemExit(exitstatus) raise SystemExit(exitstatus)
except config.Error, e: except config.Error:
py.std.sys.stderr.write("ERROR: %s\n" %(e.args[0],)) e = sys.exc_info()[1]
sys.stderr.write("ERROR: %s\n" %(e.args[0],))
raise SystemExit(3) raise SystemExit(3)

View File

@ -40,7 +40,8 @@ class Node(object):
# #
def __getstate__(self): def __getstate__(self):
return (self.name, self.parent) return (self.name, self.parent)
def __setstate__(self, (name, parent)): def __setstate__(self, nameparent):
name, parent = nameparent
try: try:
colitems = parent._memocollect() colitems = parent._memocollect()
except KeyboardInterrupt: except KeyboardInterrupt:
@ -92,7 +93,7 @@ class Node(object):
exattrname = "_ex_" + attrname exattrname = "_ex_" + attrname
failure = getattr(self, exattrname, None) failure = getattr(self, exattrname, None)
if failure is not 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): if hasattr(self, attrname):
return getattr(self, attrname) return getattr(self, attrname)
try: try:

View File

@ -1,5 +1,5 @@
import py, os import py, os
from conftesthandle import Conftest from py.__.test.conftesthandle import Conftest
from py.__.test import parseopt from py.__.test import parseopt
@ -289,7 +289,9 @@ def gettopdir(args):
parent directory of the root package is returned. parent directory of the root package is returned.
""" """
args = [py.path.local(arg) for arg in args] 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,) assert p, "cannot determine common basedir of %s" %(args,)
pkgdir = p.pypkgpath() pkgdir = p.pypkgpath()
if pkgdir is None: if pkgdir is None:

View File

@ -64,7 +64,7 @@ class Conftest(object):
return mod, getattr(mod, name) return mod, getattr(mod, name)
except AttributeError: except AttributeError:
continue continue
raise KeyError, name raise KeyError(name)
def importconftest(self, conftestpath): def importconftest(self, conftestpath):
# Using caching here looks redundant since ultimately # Using caching here looks redundant since ultimately

View File

@ -1,9 +1,11 @@
import py import py
def getfuncargnames(function): def getfuncargnames(function):
argnames = py.std.inspect.getargs(function.func_code)[0] argnames = py.std.inspect.getargs(py.code.getrawcode(function))[0]
startindex = hasattr(function, 'im_self') and 1 or 0 startindex = py.std.inspect.ismethod(function) and 1 or 0
numdefaults = len(function.func_defaults or ()) defaults = getattr(function, 'func_defaults',
getattr(function, '__defaults__', None)) or ()
numdefaults = len(defaults)
if numdefaults: if numdefaults:
return argnames[startindex:-numdefaults] return argnames[startindex:-numdefaults]
return argnames[startindex:] return argnames[startindex:]

View File

@ -93,14 +93,13 @@ def raises(ExpectedException, *args, **kwargs):
#print "raises frame scope: %r" % frame.f_locals #print "raises frame scope: %r" % frame.f_locals
try: try:
code = py.code.Source(code).compile() 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? # XXX didn'T mean f_globals == f_locals something special?
# this is destroyed here ... # this is destroyed here ...
except ExpectedException: except ExpectedException:
return py.code.ExceptionInfo() return py.code.ExceptionInfo()
else: else:
func = args[0] func = args[0]
assert callable
try: try:
func(*args[1:], **kwargs) func(*args[1:], **kwargs)
except ExpectedException: except ExpectedException:

View File

@ -64,11 +64,11 @@ class HookRecorder:
# errors on wrong input arguments, using # errors on wrong input arguments, using
# *args/**kwargs delays this and gives errors # *args/**kwargs delays this and gives errors
# elsewhere # elsewhere
exec py.code.compile(""" exec (py.code.compile("""
def %(name)s%(fspec)s: def %(name)s%(fspec)s:
self._recorder.calls.append( self._recorder.calls.append(
ParsedCall(%(name)r, locals())) ParsedCall(%(name)r, locals()))
""" % locals()) """ % locals()))
return locals()[name] return locals()[name]
def getcalls(self, names): def getcalls(self, names):

View File

@ -1,4 +1,5 @@
import py import py
import sys
def pytest_addoption(parser): def pytest_addoption(parser):
group = parser.getgroup("debugconfig") group = parser.getgroup("debugconfig")
@ -7,14 +8,18 @@ def pytest_addoption(parser):
help="disable python assert expression reinterpretation."), help="disable python assert expression reinterpretation."),
def pytest_configure(config): def pytest_configure(config):
# XXX
if sys.version_info >= (3,0):
return
if not config.getvalue("noassert"): if not config.getvalue("noassert"):
warn_about_missing_assertion() warn_about_missing_assertion()
config._oldassertion = py.std.__builtin__.AssertionError config._oldassertion = py.builtin.builtins.AssertionError
py.std.__builtin__.AssertionError = py.code._AssertionError py.builtin.builtins.AssertionError = py.code._AssertionError
def pytest_unconfigure(config): def pytest_unconfigure(config):
if hasattr(config, '_oldassertion'): if hasattr(config, '_oldassertion'):
py.std.__builtin__.AssertionError = config._oldassertion py.builtin.builtins.AssertionError = config._oldassertion
del config._oldassertion del config._oldassertion
def warn_about_missing_assertion(): def warn_about_missing_assertion():

View File

@ -275,12 +275,16 @@ class EncodedFile(object):
def __init__(self, _stream, encoding): def __init__(self, _stream, encoding):
self._stream = _stream self._stream = _stream
self.encoding = encoding self.encoding = encoding
def write(self, obj): if py.std.sys.version_info < (3,0):
if isinstance(obj, unicode): 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)) self._stream.write(obj.encode(self.encoding))
else:
self._stream.write(obj)
def writelines(self, linelist): def writelines(self, linelist):
data = ''.join(linelist) data = ''.join(linelist)

View File

@ -95,7 +95,6 @@ def pytest_addoption(parser):
def pytest_configure(config): def pytest_configure(config):
fixoptions(config) fixoptions(config)
setsession(config) setsession(config)
#xxxloadplugins(config)
def fixoptions(config): def fixoptions(config):
if config.option.numprocesses: if config.option.numprocesses:
@ -104,11 +103,6 @@ def fixoptions(config):
if config.option.distload: if config.option.distload:
config.option.dist = "load" config.option.dist = "load"
def xxxloadplugins(config):
for name in config.getvalue("plugin"):
print "importing", name
config.pluginmanager.import_plugin(name)
def setsession(config): def setsession(config):
val = config.getvalue val = config.getvalue
if val("collectonly"): if val("collectonly"):
@ -156,7 +150,7 @@ class TestDistOptions:
config = testdir.parseconfigure("--tx=popen", "--tx", "ssh=xyz") config = testdir.parseconfigure("--tx=popen", "--tx", "ssh=xyz")
xspecs = config.getxspecs() xspecs = config.getxspecs()
assert len(xspecs) == 2 assert len(xspecs) == 2
print xspecs print(xspecs)
assert xspecs[0].popen assert xspecs[0].popen
assert xspecs[1].ssh == "xyz" assert xspecs[1].ssh == "xyz"

View File

@ -55,7 +55,7 @@ class MarkerDecorator:
self.kwargs = kwargs.copy() self.kwargs = kwargs.copy()
return self return self
else: 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, " raise TypeError("need exactly one function to decorate, "
"got %r" %(args,)) "got %r" %(args,))
func = args[0] func = args[0]

View File

@ -52,7 +52,7 @@ class Pdb(py.std.pdb.Pdb):
else: else:
first = max(1, int(x) - 5) first = max(1, int(x) - 5)
except: except:
print '*** Error in argument:', repr(arg) print ('*** Error in argument: %s' % repr(arg))
return return
elif self.lineno is None: elif self.lineno is None:
first = max(1, self.curframe.f_lineno - 5) first = max(1, self.curframe.f_lineno - 5)
@ -68,7 +68,7 @@ class Pdb(py.std.pdb.Pdb):
line = self._getline(filename, lineno) line = self._getline(filename, lineno)
# end difference from normal do_line # end difference from normal do_line
if not line: if not line:
print '[EOF]' print ('[EOF]')
break break
else: else:
s = repr(lineno).rjust(3) s = repr(lineno).rjust(3)
@ -77,7 +77,7 @@ class Pdb(py.std.pdb.Pdb):
else: s = s + ' ' else: s = s + ' '
if lineno == self.curframe.f_lineno: if lineno == self.curframe.f_lineno:
s = s + '->' s = s + '->'
print s + '\t' + line, sys.stdout.write(s + '\t' + line)
self.lineno = lineno self.lineno = lineno
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass

View File

@ -6,8 +6,8 @@ import py
import sys, os import sys, os
import inspect import inspect
from py.__.test.config import Config as pytestConfig from py.__.test.config import Config as pytestConfig
import hookspec from py.__.test.plugin import hookspec
import subprocess from py.builtin import print_
pytest_plugins = '_pytest' pytest_plugins = '_pytest'
@ -94,7 +94,7 @@ class TmpTestdir:
self._olddir = old self._olddir = old
def _makefile(self, ext, args, kwargs): def _makefile(self, ext, args, kwargs):
items = kwargs.items() items = list(kwargs.items())
if args: if args:
source = "\n".join(map(str, args)) source = "\n".join(map(str, args))
basename = self.request.function.__name__ basename = self.request.function.__name__
@ -249,7 +249,7 @@ class TmpTestdir:
p.write("import py ; pytest_plugins = %r" % plugins) p.write("import py ; pytest_plugins = %r" % plugins)
else: else:
if self.plugins: if self.plugins:
print "warning, ignoring reusing existing con", p print ("warning, ignoring reusing existing %s" % p)
def popen(self, cmdargs, stdout, stderr, **kw): def popen(self, cmdargs, stdout, stderr, **kw):
if not hasattr(py.std, 'subprocess'): if not hasattr(py.std, 'subprocess'):
@ -274,7 +274,7 @@ class TmpTestdir:
cmdargs = map(str, cmdargs) cmdargs = map(str, cmdargs)
p1 = py.path.local("stdout") p1 = py.path.local("stdout")
p2 = py.path.local("stderr") p2 = py.path.local("stderr")
print "running", cmdargs, "curdir=", py.path.local() print_("running", cmdargs, "curdir=", py.path.local())
f1 = p1.open("w") f1 = p1.open("w")
f2 = p2.open("w") f2 = p2.open("w")
popen = self.popen(cmdargs, stdout=f1, stderr=f2, popen = self.popen(cmdargs, stdout=f1, stderr=f2,
@ -480,17 +480,17 @@ class LineMatcher:
while lines1: while lines1:
nextline = lines1.pop(0) nextline = lines1.pop(0)
if line == nextline: if line == nextline:
print "exact match:", repr(line) print_("exact match:", repr(line))
break break
elif fnmatch(nextline, line): elif fnmatch(nextline, line):
print "fnmatch:", repr(line) print_("fnmatch:", repr(line))
print " with:", repr(nextline) print_(" with:", repr(nextline))
break break
else: else:
if not nomatchprinted: if not nomatchprinted:
print "nomatch:", repr(line) print_("nomatch:", repr(line))
nomatchprinted = True nomatchprinted = True
print " and:", repr(nextline) print_(" and:", repr(nextline))
extralines.append(nextline) extralines.append(nextline)
else: else:
if line != nextline: if line != nextline:

View File

@ -249,7 +249,7 @@ class SetupState(object):
if colitem is None, this will add a finalizer that if colitem is None, this will add a finalizer that
is called at the end of teardown_all(). is called at the end of teardown_all().
""" """
assert callable(finalizer) assert hasattr(finalizer, '__call__')
#assert colitem in self.stack #assert colitem in self.stack
self._finalizers.setdefault(colitem, []).append(finalizer) self._finalizers.setdefault(colitem, []).append(finalizer)

View File

@ -128,7 +128,6 @@ def test_teardown(testdir):
""") """)
reprec = testdir.inline_run(testpath) reprec = testdir.inline_run(testpath)
passed, skipped, failed = reprec.countoutcomes() passed, skipped, failed = reprec.countoutcomes()
print "COUNTS", passed, skipped, failed
assert failed == 0, failed assert failed == 0, failed
assert passed == 2 assert passed == 2
assert passed + skipped + failed == 2 assert passed + skipped + failed == 2

View File

@ -44,7 +44,7 @@ class PluginManager(object):
def unregister(self, plugin): def unregister(self, plugin):
self.hook.pytest_plugin_unregistered(plugin=plugin) self.hook.pytest_plugin_unregistered(plugin=plugin)
self.comregistry.unregister(plugin) self.comregistry.unregister(plugin)
for name, value in self.impname2plugin.items(): for name, value in list(self.impname2plugin.items()):
if value == plugin: if value == plugin:
del self.impname2plugin[name] del self.impname2plugin[name]
@ -100,7 +100,8 @@ class PluginManager(object):
mod = importplugin(modname) mod = importplugin(modname)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except Skipped, e: except Skipped:
e = py.std.sys.exc_info()[1]
self._warn("could not import plugin %r, reason: %r" %( self._warn("could not import plugin %r, reason: %r" %(
(modname, e.msg))) (modname, e.msg)))
else: else:
@ -109,7 +110,7 @@ class PluginManager(object):
self.consider_module(mod) self.consider_module(mod)
def _warn(self, msg): def _warn(self, msg):
print "===WARNING=== %s" % (msg,) print ("===WARNING=== %s" % (msg,))
def _checkplugin(self, plugin): def _checkplugin(self, plugin):
# ===================================================== # =====================================================
@ -217,12 +218,14 @@ def canonical_importname(name):
def importplugin(importspec): def importplugin(importspec):
try: try:
return __import__(importspec) return __import__(importspec)
except ImportError, e: except ImportError:
e = py.std.sys.exc_info()[1]
if str(e).find(importspec) == -1: if str(e).find(importspec) == -1:
raise raise
try: try:
return __import__("py.__.test.plugin.%s" %(importspec), None, None, '__doc__') 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: if str(e).find(importspec) == -1:
raise raise
#print "syspath:", py.std.sys.path #print "syspath:", py.std.sys.path
@ -236,8 +239,8 @@ def isgenerichook(name):
name.startswith("pytest_funcarg__") name.startswith("pytest_funcarg__")
def getargs(func): def getargs(func):
args = py.std.inspect.getargs(func.func_code)[0] args = py.std.inspect.getargs(py.code.getrawcode(func))[0]
startindex = hasattr(func, 'im_self') and 1 or 0 startindex = py.std.inspect.ismethod(func) and 1 or 0
return args[startindex:] return args[startindex:]
def collectattr(obj, prefixes=("pytest_",)): def collectattr(obj, prefixes=("pytest_",)):
@ -250,7 +253,7 @@ def collectattr(obj, prefixes=("pytest_",)):
def formatdef(func): def formatdef(func):
return "%s%s" %( return "%s%s" %(
func.func_name, func.__name__,
py.std.inspect.formatargspec(*py.std.inspect.getargspec(func)) py.std.inspect.formatargspec(*py.std.inspect.getargspec(func))
) )
@ -277,7 +280,7 @@ if __name__ == "__main__":
text = name2text[name] text = name2text[name]
if name[0] == "_": if name[0] == "_":
continue continue
print "%-20s %s" % (name, text.split("\n")[0]) print ("%-20s %s" % (name, text.split("\n")[0]))
#text = py.std.textwrap.wrap(name2text[name], #text = py.std.textwrap.wrap(name2text[name],
# width = 80, # width = 80,

View File

@ -92,7 +92,7 @@ class PyCollectorMixin(PyobjMixin, py.test.collect.Collector):
if l is not None: if l is not None:
return l return l
name2items = self._buildname2items() name2items = self._buildname2items()
colitems = name2items.values() colitems = list(name2items.values())
colitems.sort(key=lambda item: item.reportinfo()[:2]) colitems.sort(key=lambda item: item.reportinfo()[:2])
return colitems return colitems
@ -128,7 +128,7 @@ class PyCollectorMixin(PyobjMixin, py.test.collect.Collector):
if res is not None: if res is not None:
return res return res
return self.Class(name, parent=self) 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) res = self._deprecated_join(name)
if res is not None: if res is not None:
return res return res
@ -237,7 +237,7 @@ class FunctionMixin(PyobjMixin):
def setup(self): def setup(self):
""" perform setup for this test function. """ """ perform setup for this test function. """
if hasattr(self.obj, 'im_self'): if py.std.inspect.ismethod(self.obj):
name = 'setup_method' name = 'setup_method'
else: else:
name = 'setup_function' name = 'setup_function'
@ -345,7 +345,8 @@ class Function(FunctionMixin, py.test.collect.Item):
def readkeywords(self): def readkeywords(self):
d = super(Function, self).readkeywords() d = super(Function, self).readkeywords()
d.update(self.obj.func_dict) d.update(getattr(self.obj, '__dict__',
getattr(self.obj, 'func_dict', {})))
return d return d
def runtest(self): def runtest(self):
@ -372,7 +373,9 @@ class Function(FunctionMixin, py.test.collect.Item):
def __ne__(self, other): def __ne__(self, other):
return not self == other return not self == other
def __hash__(self):
return hash((self.parent, self.name))
def hasinit(obj): def hasinit(obj):
init = getattr(obj, '__init__', None) init = getattr(obj, '__init__', None)