* various jython related fixes.

* more care for print-errors including unicode-encoding related errors.

--HG--
branch : trunk
This commit is contained in:
holger krekel 2010-04-28 15:24:38 +02:00
parent 37cdf17e0e
commit 22a50a5b88
12 changed files with 63 additions and 27 deletions

View File

@ -5,14 +5,14 @@ Changes between 1.2.1 and 1.2.2 (release pending)
- (issue85) fix junitxml plugin to handle tests with non-ascii output - (issue85) fix junitxml plugin to handle tests with non-ascii output
- fix some python3 compatibility issues (thanks Benjamin Peterson) - fix some python3 compatibility issues (thanks Benjamin Peterson)
- fixes for making the jython/win32 combination work - fixes for making the jython/win32 combination work
- fixes for handling of unicode exception values - fixes for handling of unicode exception values and unprintable objects
- added links to the new capturelog and coverage plugins
- (issue87) fix unboundlocal error in assertionold code - (issue87) fix unboundlocal error in assertionold code
- (issue86) improve documentation for looponfailing - (issue86) improve documentation for looponfailing
- expose test outcome related exceptions as py.test.skip.Exception, - expose test outcome related exceptions as py.test.skip.Exception,
py.test.raises.Exception etc., useful mostly for plugins py.test.raises.Exception etc., useful mostly for plugins
doing special outcome interpreteration/tweaking doing special outcome interpreteration/tweaking
- ship distribute_setup.py version 0.6.10 - ship distribute_setup.py version 0.6.10
- added links to the new capturelog and coverage plugins
Changes between 1.2.1 and 1.2.0 Changes between 1.2.1 and 1.2.0

View File

@ -93,7 +93,7 @@ if sys.version_info >= (3, 0):
# some backward compatibility helpers # some backward compatibility helpers
_basestring = str _basestring = str
def _totext(obj, encoding): def _totext(obj, encoding=None):
if isinstance(obj, bytes): if isinstance(obj, bytes):
obj = obj.decode(encoding) obj = obj.decode(encoding)
elif not isinstance(obj, str): elif not isinstance(obj, str):

View File

@ -3,7 +3,7 @@ import sys, os.path
builtin_repr = repr builtin_repr = repr
repr = py.builtin._tryimport('repr', 'reprlib') reprlib = py.builtin._tryimport('repr', 'reprlib')
class Code(object): class Code(object):
""" wrapper around Python code objects """ """ wrapper around Python code objects """
@ -510,7 +510,7 @@ class FormattedExcinfo(object):
lines.append("__builtins__ = <builtins>") lines.append("__builtins__ = <builtins>")
else: else:
# This formatting could all be handled by the # This formatting could all be handled by the
# _repr() function, which is only repr.Repr in # _repr() function, which is only reprlib.Repr in
# disguise, so is very configurable. # disguise, so is very configurable.
str_repr = self._saferepr(value) str_repr = self._saferepr(value)
#if len(str_repr) < 70 or not isinstance(value, #if len(str_repr) < 70 or not isinstance(value,
@ -591,14 +591,23 @@ class TerminalRepr:
return s return s
def __unicode__(self): def __unicode__(self):
tw = py.io.TerminalWriter(stringio=True) l = []
tw = py.io.TerminalWriter(l.append)
self.toterminal(tw) self.toterminal(tw)
s = tw.stringio.getvalue().strip() l = map(unicode_or_repr, l)
return s return "".join(l).strip()
def __repr__(self): def __repr__(self):
return "<%s instance at %0x>" %(self.__class__, id(self)) return "<%s instance at %0x>" %(self.__class__, id(self))
def unicode_or_repr(obj):
try:
return py.builtin._totext(obj)
except KeyboardInterrupt:
raise
except Exception:
return "<print-error: %r>" % safe_repr(obj)
class ReprExceptionInfo(TerminalRepr): class ReprExceptionInfo(TerminalRepr):
def __init__(self, reprtraceback, reprcrash): def __init__(self, reprtraceback, reprcrash):
self.reprtraceback = reprtraceback self.reprtraceback = reprtraceback
@ -709,17 +718,17 @@ class ReprFuncArgs(TerminalRepr):
class SafeRepr(repr.Repr): class SafeRepr(reprlib.Repr):
""" subclass of repr.Repr that limits the resulting size of repr() """ subclass of repr.Repr that limits the resulting size of repr()
and includes information on exceptions raised during the call. and includes information on exceptions raised during the call.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
repr.Repr.__init__(self, *args, **kwargs) reprlib.Repr.__init__(self, *args, **kwargs)
self.maxstring = 240 # 3 * 80 chars self.maxstring = 240 # 3 * 80 chars
self.maxother = 160 # 2 * 80 chars self.maxother = 160 # 2 * 80 chars
def repr(self, x): def repr(self, x):
return self._callhelper(repr.Repr.repr, self, x) return self._callhelper(reprlib.Repr.repr, self, x)
def repr_instance(self, x, level): def repr_instance(self, x, level):
return self._callhelper(builtin_repr, x) return self._callhelper(builtin_repr, x)

View File

@ -145,15 +145,17 @@ class TerminalWriter(object):
# XXX deprecate stringio argument # XXX deprecate stringio argument
def __init__(self, file=None, stringio=False, encoding=None): def __init__(self, file=None, stringio=False, encoding=None):
self.encoding = encoding
if file is None: if file is None:
if stringio: if stringio:
self.stringio = file = py.io.TextIO() self.stringio = file = py.io.TextIO()
else: else:
file = py.std.sys.stdout file = py.std.sys.stdout
if hasattr(file, 'encoding'):
encoding = file.encoding
elif hasattr(file, '__call__'): elif hasattr(file, '__call__'):
file = WriteFile(file, encoding=encoding) file = WriteFile(file, encoding=encoding)
self.encoding = encoding
self._file = file self._file = file
self.fullwidth = get_terminal_width() self.fullwidth = get_terminal_width()
self.hasmarkup = should_do_markup(file) self.hasmarkup = should_do_markup(file)
@ -200,18 +202,22 @@ class TerminalWriter(object):
def write(self, s, **kw): def write(self, s, **kw):
if s: if s:
s = self._getbytestring(s) if not isinstance(self._file, WriteFile):
if self.hasmarkup and kw: s = self._getbytestring(s)
s = self.markup(s, **kw) if self.hasmarkup and kw:
s = self.markup(s, **kw)
self._file.write(s) self._file.write(s)
self._file.flush() self._file.flush()
def _getbytestring(self, s): def _getbytestring(self, s):
# XXX review this and the whole logic # XXX review this and the whole logic
if self.encoding and sys.version_info < (3,0) and isinstance(s, unicode): if self.encoding and sys.version_info[0] < 3 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) try:
return str(s)
except UnicodeEncodeError:
return "<print-error '%s' object>" % type(s).__name__
return s return s
def line(self, s='', **kw): def line(self, s='', **kw):

View File

@ -144,6 +144,7 @@ class LogXML(object):
suite_stop_time = time.time() suite_stop_time = time.time()
suite_time_delta = suite_stop_time - self.suite_start_time suite_time_delta = suite_stop_time - self.suite_start_time
numtests = self.passed + self.failed numtests = self.passed + self.failed
logfile.write('<?xml version="1.0" encoding="utf-8"?>')
logfile.write('<testsuite ') logfile.write('<testsuite ')
logfile.write('name="" ') logfile.write('name="" ')
logfile.write('errors="%i" ' % self.errors) logfile.write('errors="%i" ' % self.errors)

View File

@ -21,7 +21,9 @@ def pytest_pycollect_makeitem(collector, name, obj):
return # nobody derived unittest.TestCase return # nobody derived unittest.TestCase
try: try:
isunit = issubclass(obj, py.std.unittest.TestCase) isunit = issubclass(obj, py.std.unittest.TestCase)
except TypeError: except KeyboardInterrupt:
raise
except Exception:
pass pass
else: else:
if isunit: if isunit:

View File

@ -193,7 +193,7 @@ def test_builtin_patch_unpatch(monkeypatch):
assert cpy_builtin.compile == mycompile assert cpy_builtin.compile == mycompile
def test_unicode_handling(testdir): def test_unicode_handling():
value = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8').encode('utf8') value = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8').encode('utf8')
def f(): def f():
raise Exception(value) raise Exception(value)
@ -201,3 +201,19 @@ def test_unicode_handling(testdir):
s = str(excinfo) s = str(excinfo)
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
u = unicode(excinfo) u = unicode(excinfo)
def test_unicode_or_repr():
from py._code.code import unicode_or_repr
assert unicode_or_repr('hello') == "hello"
if sys.version_info[0] < 3:
s = unicode_or_repr('\xf6\xc4\x85')
else:
s = eval("unicode_or_repr(b'\\f6\\xc4\\x85')")
assert 'print-error' in s
assert 'c4' in s
class A:
def __repr__(self):
raise ValueError()
s = unicode_or_repr(A())
assert 'print-error' in s
assert 'ValueError' in s

View File

@ -129,8 +129,8 @@ class TestTerminalWriter:
tw.write("x\n", red=True) tw.write("x\n", red=True)
l = tw.getlines() l = tw.getlines()
if sys.platform != "win32": if sys.platform != "win32":
assert len(l[0]) > 2, l assert len(l[0]) >= 2, l
assert len(l[1]) > 2, l assert len(l[1]) >= 2, l
def test_attr_fullwidth(self, tw): def test_attr_fullwidth(self, tw):
tw.sep("-", "hello", fullwidth=70) tw.sep("-", "hello", fullwidth=70)

View File

@ -393,7 +393,8 @@ def test_setup_failure_does_not_kill_capturing(testdir):
def test_fdfuncarg_skips_on_no_osdup(testdir): def test_fdfuncarg_skips_on_no_osdup(testdir):
testdir.makepyfile(""" testdir.makepyfile("""
import os import os
del os.dup if hasattr(os, 'dup'):
del os.dup
def test_hello(capfd): def test_hello(capfd):
pass pass
""") """)

View File

@ -1,6 +1,6 @@
from xml.dom import minidom from xml.dom import minidom
import py import py, sys
def runandparse(testdir, *args): def runandparse(testdir, *args):
resultpath = testdir.tmpdir.join("junit.xml") resultpath = testdir.tmpdir.join("junit.xml")
@ -104,7 +104,7 @@ class TestPython:
name="test_collect_error") name="test_collect_error")
fnode = tnode.getElementsByTagName("failure")[0] fnode = tnode.getElementsByTagName("failure")[0]
assert_attr(fnode, message="collection failure") assert_attr(fnode, message="collection failure")
assert "invalid syntax" in fnode.toxml() assert "SyntaxError" in fnode.toxml()
def test_collect_skipped(self, testdir): def test_collect_skipped(self, testdir):
testdir.makepyfile("import py ; py.test.skip('xyz')") testdir.makepyfile("import py ; py.test.skip('xyz')")
@ -130,7 +130,8 @@ class TestPython:
assert result.ret == 1 assert result.ret == 1
tnode = dom.getElementsByTagName("testcase")[0] tnode = dom.getElementsByTagName("testcase")[0]
fnode = tnode.getElementsByTagName("failure")[0] fnode = tnode.getElementsByTagName("failure")[0]
assert "hx" in fnode.toxml() if not sys.platform.startswith("java"):
assert "hx" in fnode.toxml()
class TestNonPython: class TestNonPython:
def test_summing_simple(self, testdir): def test_summing_simple(self, testdir):

View File

@ -142,7 +142,7 @@ class TestWithFunctionIntegration:
entry_lines = entry.splitlines() entry_lines = entry.splitlines()
assert entry_lines[0].startswith('! ') assert entry_lines[0].startswith('! ')
assert os.path.basename(__file__)[:-1] in entry_lines[0] #.py/.pyc assert os.path.basename(__file__)[:-9] in entry_lines[0] #.pyc/class
assert entry_lines[-1][0] == ' ' assert entry_lines[-1][0] == ' '
assert 'ValueError' in entry assert 'ValueError' in entry

View File

@ -97,7 +97,7 @@ class TestTerminal:
excinfo = py.test.raises(ValueError, "raise ValueError('hello')") excinfo = py.test.raises(ValueError, "raise ValueError('hello')")
rep.pytest_internalerror(excinfo.getrepr()) rep.pytest_internalerror(excinfo.getrepr())
linecomp.assert_contains_lines([ linecomp.assert_contains_lines([
"INTERNALERROR> *raise ValueError*" "INTERNALERROR> *ValueError*hello*"
]) ])
def test_writeline(self, testdir, linecomp): def test_writeline(self, testdir, linecomp):